共用方式為


TN059: 使用 MFC MBCS/Unicode 轉換巨集

注意事項注意事項

由於它第一次線上文件中包含尚未更新下列技術提示。如此一來,某些程序和主題可能已經過期或不正確。如需最新資訊,建議您先搜尋線上文件索引中有興趣的主題。

這個註解告訴您,如何使用 MBCS/Unicode 轉換,AFXPRIV 中所定義的巨集。H. 這些巨集是最有用,如果您的應用程式處理直接與 OLE API 或因某種原因,通常需要 Unicode 並使用 MBCS 之間進行轉換。

概觀

在 [MFC 3.x 中,已使用特殊的 DLL (MFCANS32。DLL),自動將轉換之間 Unicode 並使用 MBCS 時所呼叫的 OLE 介面。 這個 DLL 已允許 OLE 應用程式,即使它們永遠是 Unicode,猶如 OLE Api 和介面 MBCS,寫入幾乎透明圖層 (除非在 Macintosh 上)。 這一層是不是很方便,且允許應用程式,以快速地從 Win16 移植用於 Win32 (MFC,Microsoft Word,Microsoft Excel 中和 VBA 中,都只是有些 Microsoft 應用程式使用這項技術),它已有有時顯著的效能叫用。 基於這個理由,MFC 4.x 不會使用這個 DLL,而是直接與 Unicode OLE 介面交談。 若要執行這項操作,MFC 成 OLE 介面,在呼叫時,將轉換成 Unicode MBCS,並且經常需要將實作 OLE 介面時從 Unicode 轉換成 MBCS。 若要有效且輕鬆地,請處理這個選項,一些巨集所建立為了簡化這項轉換。

在最大上達到標準建立這類一組巨集的其中一項是記憶體配置。 由於無法轉換字串中的位置,都必須配置新的記憶體來存放已轉換的結果。 這可以做類似下列的程式碼:

// we want to convert an MBCS string in lpszA
int nLen = MultiByteToWideChar(CP_ACP, 0,lpszA, -1, NULL, NULL);
LPWSTR lpszW = new WCHAR[nLen];
MultiByteToWideChar(CP_ACP, 0, 
   lpszA, -1, lpszW, nLen);
// use it to call OLE here
pI->SomeFunctionThatNeedsUnicode(lpszW);
// free the string
delete[] lpszW;

問題的原因為這種方法。 主要問題在於它是許多撰寫、 測試和偵錯的程式碼。 是簡單的函式呼叫的項目已經是更為複雜。 此外,沒有明顯的執行階段負荷執行這項作業。 記憶體已配置在堆積上並釋放每次會執行轉換。 最後,上面的程式碼需具備適當#ifdefs加入針對 Unicode 並使用 Macintosh 組建 (而不需要這種轉換才會生效)。

若要建立何種 1) 遮罩各種平台和 2) 使用可有效的記憶體配置的配置,之間的差異及 3) 輕易地插入到現有的原始程式碼某些巨集,我們想出解決方法。 以下是其中一個定義的範例:

#define A2W(lpa) (\
    ((LPCSTR)lpa == NULL) ? NULL : (\
          _convert = (strnlen(lpa)+1),\
        AfxA2WHelper((LPWSTR) alloca(_convert*2), 
      lpa, _convert)\
    )\
)

使用此巨集,而不是上述程式碼和項目是簡單得多:

// use it to call OLE here
USES_CONVERSION;
pI->SomeFunctionThatNeedsUnicode(T2OLE(lpszA));

沒有額外的呼叫,轉換就會有必要,但使用巨集是簡單且有效。

每個巨集的實作會使用 _alloca() 函式,而不是堆積的堆疊中配置記憶體。 從堆疊中配置記憶體是配置在堆積的記憶體比快得多,函式結束時,會自動釋放記憶體。 此外,巨集避免呼叫 MultiByteToWideChar (或 WideCharToMultiByte) 一次以上。 這是配置超過了一些額外的記憶體。 我們知道 MBC 會轉換成最多一個 WCHAR ,以及每個 WCHAR 我們將會有兩個 MBC 位元組的最大值。 配置更多個有必要,請永遠但足以處理轉換第二次呼叫第二個轉換函式呼叫會出現。 Helper 函式的呼叫 AfxA2Whelper 減少的數目都必須分別以執行轉換的引數推入 (這會導致較小的程式碼,比如果呼叫 MultiByteToWideChar 直接)。

為了要讓巨集,有的空間來儲存暫時的長度,就必須宣告區域變數呼叫 _convert,這樣每個函式,會使用轉換巨集。 這是藉由叫用 USES_CONVERSION 巨集,如以上範例中所示。

沒有同時為泛型轉換巨集和 OLE 特定巨集。 以下將討論這些兩個不同的巨集集合。 所有巨集存放在 AFXPRIV 上。H.

泛用轉換巨集

泛用轉換巨集表單基礎的機制。 巨集範例與前一節,也就是 A2W,] 所示的實作是一種 「 一般 」 巨集。 它沒有關聯到 OLE 特別。 下列為泛用的巨集的集合:

A2CW      (LPCSTR) -> (LPCWSTR)
A2W      (LPCSTR) -> (LPWSTR)
W2CA      (LPCWSTR) -> (LPCSTR)
W2A      (LPCWSTR) -> (LPSTR)

除了執行文字轉換時,也有巨集和 helper 函式來將轉換的TEXTMETRICDEVMODEBSTR,及 OLE 配置字串。 這些巨集並不討論這個問題討論的範圍-AFXPRIV,請參閱。如需有關這些巨集的 H。

OLE 轉換巨集

OLE 轉換巨集專門用來處理預期的函式設計 OLESTR 個字元。 如果您檢查 OLE 標頭時,您會看到許多參考 LPCOLESTROLECHAR。 這些型別用來參考的型別,而不是平台所特有的 OLE 介面中使用的字元。 OLECHAR 會對應到char在 Win16 和 Macintosh 平台和 WCHAR 在 Win32 中。

若要保留的 # ifdef 到最少的程式碼在 MFC 中的指示詞我們有類似的巨集,每個轉換,其中牽涉到 OLE 字串。 最常使用的下列巨集:

T2COLE   (LPCTSTR) -> (LPCOLESTR)
T2OLE   (LPCTSTR) -> (LPOLESTR)
OLE2CT   (LPCOLESTR) -> (LPCTSTR)
OLE2T   (LPCOLESTR) -> (LPCSTR)

同樣地,有類似的巨集執行此步驟TEXTMETRICDEVMODEBSTR,及 OLE 配置字串。 請參閱 AFXPRIV。如需詳細資訊的 H。

其他考量

請勿在緊密迴圈中使用巨集。 比方說,您不想撰寫下列幾種程式碼:

void BadIterateCode(LPCTSTR lpsz)
{
   USES_CONVERSION;
   for (int ii = 0; ii < 10000; ii++)
      pI->SomeMethod(ii, T2COLE(lpsz));
}

上述程式碼可能會導致配置 mb 的記憶體,視何種字串的內容堆疊上lpsz是! 它也會考慮將迴圈的每個反覆項目的字串轉換的時間。 相反地,將移出迴圈的這類常數轉換:

void MuchBetterIterateCode(LPCTSTR lpsz)
{
   USES_CONVERSION;
   LPCOLESTR lpszT = T2COLE(lpsz);
   for (int ii = 0; ii < 10000; ii++)
      pI->SomeMethod(ii, lpszT);
}

如果字串不是常數,然後將封裝方法呼叫函式。 這可以讓要釋放每次轉換緩衝區。 例如:

void CallSomeMethod(int ii, LPCTSTR lpsz)
{
   USES_CONVERSION;
   pI->SomeMethod(ii, T2COLE(lpsz));
}

void MuchBetterIterateCode2(LPCTSTR* lpszArray)
{
   for (int ii = 0; ii < 10000; ii++)
      CallSomeMethod(ii, lpszArray[ii]);
}

永遠不會將結果傳回的其中一個巨集,除非製作一份資料會在傳回之前所示的傳回值。 比方說,這段程式碼是不正確的:

LPTSTR BadConvert(ISomeInterface* pI)
{
   USES_CONVERSION;
   LPOLESTR lpsz = NULL;
   pI->GetFileName(&lpsz);
   LPTSTR lpszT = OLE2T(lpsz);
   CoMemFree(lpsz);
   return lpszT; // bad! returning alloca memory
}

傳回的值改成將值複製的項目,無法修正上面的程式碼:

CString BetterConvert(ISomeInterface* pI)
{
   USES_CONVERSION;
   LPOLESTR lpsz = NULL;
   pI->GetFileName(&lpsz);
   LPTSTR lpszT = OLE2T(lpsz);
   CoMemFree(lpsz);
   return lpszT; // CString makes copy
}

巨集易於使用,輕易地插入至程式碼,但想必讀者也知道從上述警告,您需要使用它們時非常小心。

請參閱

其他資源

技術的備忘稿編號

依類別的技術注意事項