2008年11月26日 星期三

擴充boost serialization 支援 CString, CTime

boost的serialization是一個很強大的工具
原本的程式架構只支援std::string等STL元件
如果你的程式有需要用到MFC的話
MFC的CString, CTime或其他class可以很簡單的擴充到boost serialization


namespace boost
{
namespace serialization
{
template
inline void save(Archive & ar, const CString& str, const unsigned int file_version)
{
std::wstring wstr(str);
ar & BOOST_SERIALIZATION_NVP(wstr);
}

template
inline void load(Archive &ar, CString& str, const unsigned int file_version)
{
std::wstring wstr;
ar & BOOST_SERIALIZATION_NVP(wstr);
str = wstr.data();
}

template
inline void serialize(Archive &ar, CString &str, const unsigned int file_version)
{
boost::serialization::split_free(ar, str, file_version);
}

template
inline void save(Archive & ar, const CTime& time, const unsigned int file_version)
{
__time64_t t = time.GetTime();
ar & t;
}

template
inline void load(Archive &ar, CTime& time, const unsigned int file_version)
{
__time64_t t;
ar & t;
time = t;
}

template
inline void serialize(Archive &ar, CTime &time, const unsigned int file_version)
{
boost::serialization::split_free(ar, time, file_version);
}
}
}


ps. 要注意一點,擴充的class要放在boost::serialization namespace裡,要不然可能會找不到對映的function

Reference
http://www.boost.org/doc/libs/1_37_0/libs/serialization/doc/index.html

2008年11月25日 星期二

Inno Setup 包裝 Visual C++ runtime library

前言
用Inno Setup建立Visual C++的安裝程式時,如果你使用MFC Shared DLL的話,通常你都要把vcredist.exe包裝進來,不過vcredist.exe一直存在一個blocking problem,安裝的時候常常會卡在某一個畫面,有時候慢的話要三分鐘才會結束(這個問題在Visual C++ 2008 sp1有獲得改善了),而且vcredist對user來說只需要安裝一次就足夠了,因此在安裝程式的時候,可以透過簡單的語法來判斷是否需要安裝vcredist.exe。


[Setup]
Your program setup

[Files]
; Visual C++ redist
Source: vcredist_x86.exe"; DestDir: "{tmp}"; Check: NeedInstallVC9SP1

[Run]
Filename: "{tmp}\vcredist_x86.exe"; Parameters: /q; WorkingDir: {tmp}; Flags: skipifdoesntexist; StatusMsg: "Installing Microsoft Visual C++ Runtime ..."; Check: NeedInstallVC9SP1

[Code]
var vc9SP1Missing: Boolean;

function NeedInstallVC9SP1(): Boolean;
begin
Result := vc9SP1Missing;
end;

function InitializeSetup(): Boolean;
var version: Cardinal;
begin
if RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{9A25302D-30C0-39D9-BD6F-21E6EC160475}', 'Version', version) = false then begin
vc9SP1Missing := true;
end;
result := true;
end;


上面這樣的程式碼會先檢查User端有沒有安裝過vcredist.exe,如果沒有安裝過則解壓縮vcredist並且install,如果已經有安裝了就不解壓縮且不install。

enjoy Inno Setup

2008年11月22日 星期六

'dynamic_cast' : 'A' is not a polymorphic type


class A
{
public:
A() : m_a(1) {}

int m_a;
}

class B : public A
{
public:
B() : A(), m_b(2) {}

int m_b;
}

int main()
{
A* a = new B;
B* b = dynamic_cast(a); // error
delete a;
}


上面的程式碼在編譯時,我們最好的朋友 - complier - 會告訴你dynamic_cast那一行有錯誤,錯誤訊息應該會像下面這樣:
'dynamic_cast' : 'A' is not a polymorphic type
咦,明明B和A是有繼承體系的,為什麼沒辦法用dynamic_cast呢??
主要是dynamic_cast在做型別轉換時會依賴vftable做型別檢查
(dynamic_cast會檢查型別是否符合,不符合會傳回NULL)
而要建立vftable只要在class底下有包含至少一個virtual function就可以了
在effective C++也有提到,如果你的類別需要被繼承的話,最好將你的解構子(destructor)設為virtual
既可以加入vftable,也可以避免delete base的memory leak

所以程式碼修改成下面就ok了

class A
{
public:
A() : m_a(1) {}
virtual ~A() {}

int m_a;
}

class B : public A
{
public:
B() : A(), m_b(2) {}
virtual ~B() {}

int m_b;
}

int main()
{
A* a = new B;
B* b = dynamic_cast(a); // pass
delete a;
}


delete a, b, c;

雖然用C++在工作上也有三四年的時間了,可是有時候有一些細節的觀念還不是很清楚
可能是我不用功好好k書吧 orz.. 而且自己接觸的是Embedded System.. C++技術都沒進步的 orz..

----------------------------------------


int *a, *b, *c;
a = new int;
b = new int;
c = new int;
// ....
delete a, b, c;


上面這樣的寫法會造成memory leak,主要是因為delete a, b, c只會刪除a而已,且乎略b, c
我一開始看到memory leak的時候還蠻訝異的,明明int *a, *b, *c就是正常的,會宣告出a,b,c三個int pointer
為什麼會delete a, b, c卻只會對a動作呢??

主要是delete a, b, c裡面還包成逗號運算元
delete a, b, c 等於(delete a), b, c;
先delete a之後再對b, c取值。
所以要寫delete動作時還是乖乖的一行一行寫吧
delete a;
delete b;
delete c;

2008年11月13日 星期四

MFC如何分析Command指令

在執行程式的時候後面可以加入Command Line
ex:
dir /w *.txt
myapp.exe /service


在console C/C++時,直接分析arg等參數就可以了
而在MFC程式裡,因為MFC有將這個分析的動作包成class
所以繼承該class並重載function

底下是example
class CYourCommandLineInfo : public CCommandLineInfo
{
public:
CCommandLineInfo() : m_service(false) {}

bool IsService() const {return m_service;}

virtual void ParseParam(const TCHAR* pszParam, BOOL bFlag, BOOL bLast)
{
if (bFlag)
{
if(_tcscmp(pszParam, _T("service")) == 0)
m_service = true;
}
}

private:
bool m_service;
};


BOOL CYourWinApp::InitInstance()
{
CYourCommandLineInfo cmdLineInfo;
ParseCommandLine(cmdLineInfo);
if (cmdLineInfo.IsService())
{
// ...
}

// ...
}

2008年11月12日 星期三

CMFCVisualManager的memory leak問題

國外遇到的問題,很巧的我也遇到了
http://209.85.175.104/search?q=cache:pxlLUie-0XAJ:social.technet.microsoft.com/Forums/en-US/vcgeneral/thread/8870974f-1414-4dd7-b7c3-a1c320c0e91e+CMFCVisualManager+memory+leak&hl=zh-TW&ct=clnk&cd=1&gl=tw

在使用CMFCVisualManager時,有時候結束時會有memory leak
解決方法如下:
1. 將CWinApp改成CWinAppEx就ok了,但是如果你有重載ExitInstance的話,記得要再呼叫CWinAppEx::ExitInstance() (這是我遇到的問題,忘記呼叫底層了)
2. 在關閉程式時,手動clean

CMFCVisualManager::DestroyInstance(TRUE /* bAutoDestroyOnly */);
CMFCVisualManagerOffice2007::CleanStyle();


第1種方式才是正解,只要記得call CWinAppEx::ExitInstance()就ok了
enjoy the powerful UI.

2008年11月3日 星期一

小小大星球 簡易開箱文

今天終於入手小小大星球了,但是很可惜的我沒有拿到巫毒娃娃,因為之前巴哈開始預購的時候,我還在猶鬱要買新的還是二手的,結果後來在9/30才下訂單,不過我的巫毒娃娃已經離我而去了,哭哭。

因為目前人還在公司,所以從7-11拿到小小大星球也只是開箱拍個照而已,呵呵。




相面照



開盒


一本中文手冊、一個光碟及一個英文的紙張




下班回去趕快來玩吧... XD

LinkWithin

Related Posts with Thumbnails