12 12月 2009

[Win32 API] String Conversion

在Windows底下做字串轉換其實還滿簡單的,在MFC的Library裡,提供了一些簡單的Marco可以用,就可以針對wstring, string, CComBSTR, BSTR之間做轉換了。需 Include AtlBase.h, AtlConv.h

以下是 ATL7.0 版 Marco、Class的命名規則
CSourceType2[C]DestinationType[EX]

以下是 ATL3.0 舊版 Marco的命名規則
SourceType2[C]DestinationType[EX]



SourceType or DestinationType包含了A, W, T, OLE可使用,Ex: A2W, W2T, T2OLE...
  • 新舊版的命名規則差異只有開頭有沒有C,結果有沒有EX。新版的C開頭代表跟舊版的Marco不一樣,而是以Class去實作的。Ex: A2W, W2A是Marco,CA2W, CW2A則是Class。
  • [C] : 中間的C可有可無,代表著DestinationType是否為 const 的字串。
  • [EX] : 新版的EX表示,可指定Class所使用的Buffer size。Ex: CA2W<64>

既然有新版的,當然是用新的好啊,因為用舊版的在使用前,必須手動加一個Marco : USES_CONVERSION才能正常Work。舊版是吃stack的memory,一定要等function離開後才會release。

範例:
[錯誤!]ANSI的字串轉成Unicode字串
LPSTR name = "Falldog"; 
LPWSTR wstr = CA2W(name);
//Use wstr....
這樣子的寫法,在 ATL3.0 使用A2W是可以work的,但是在 ATL7.0 的版本中,CA2W是一個class,所以意義上會變得不太一樣。
將上面的範例做慢動作解析:
LPSTR name = "Falldog"; 
LPWSTR wstr;
{
    CA2W temp(name);
    wstr = temp.operator LPWSTR(); 
}
//Use wstr.... but memory stored in temp is destroyed... 
//再把上面的有問題的地方轉成平常可能看到的畫面
LPWSTR my_func_CA2W( /*LPSTR ansi*/)
{
    WCHAR* temp = L"Falldog";
    return temp;
}
LPWSTR wstr = my_func_CA2W();
//Use wstr....
下半部出現的問題是,當 my_func_CA2W 將 temp return 回來後,其實儲存字串內容的 memory 就已經被 release 掉了,所以當去 access wstr 時,就會有 exception 了。
而上半部跟下半部的問題是一樣的,當你 create 了一個CA2W的object,但是卻把它 assign 給一個 pointer,而 CA2W 的 life scope 在 assign 給 pointer 之後就結束了。當然使用者再使用 wstr 後,會出現 exception。



[正解1] 將ANSI的字串轉成Unicode字串 (可重複使用轉換後字串)
LPSTR name = "Falldog"; 
CA2W wstr(name);
//Use wstr...

[正解2] 將ANSI的字串轉成Unicode字串 (只用一次, 射後不理)
LPSTR name = "Falldog"; 
wprintf( L"User Unicode Name=%s", CA2W(name) );

Reference : [MSDN] ATL and MFC String Conversion Macros

沒有留言: