テクニカル ノート 59: MFC の MBCS/Unicode 変換マクロの使用
[!メモ]
次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。
ここでは、 AFXPRIV.H. で定義されている割り当てるの変換にマクロを使用する方法について説明します。これらのマクロは Unicode と MBCS の間で変換しますが、アプリケーションが OLE API を直接またはなんらかの理由により処理する場合、頻繁に必要です。
概要
MFC Version 3.x では、 OLE インターフェイスが呼び出されたときに自動的に Unicode と MBCS の間で変換する場合は、特別な DLL (MF CANS32 .DLL)が使用されていました。この DLL は Unicode 常にでも、 OLE API とインターフェイスは、 MBCS のように、 OLE アプリケーションがために記述されたほとんど透明レイヤーか、 (Macintosh 上では除きます)。このレイヤーが便利な、許可されるアプリケーションで直接移植する Win16 から Win32 に、 MFC (Microsoft Word、 Microsoft Excel および VBA は、この方法を使用する Microsoft アプリケーションの一部ですが、場合によっては重要なパフォーマンスに影響があります。したがって、 MFC 4.x は、この DLL を使用せず、 Unicode の OLE インターフェイスに直接話しません。これを行うには、 MFC、 OLE インターフェイスを実装すると Unicode の MBCS に変換する呼び出しを OLE インターフェイスに行われる場合、頻繁に必要 MBCS に Unicode に変換する必要があります。これを簡単かつ効率的に処理するには、いくつかのマクロでは、この変換を簡単にするために作成されました。
マクロのこのような設定の作成の最大の難関の 1 つがメモリ割り当てです。文字列を変換した設定することはできないので、変換された結果を格納する新しいメモリを割り当てる必要があります。これは、次のようなコードとする可能性があります:
// 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;
いくつかの問題としてこの方法。主要な問題は、を書き込む、テストする多くのコードとデバッグであることです。単純な関数呼び出しのものは、かなり複雑です。また、その一方で重要なランタイムのオーバーヘッドがあります。メモリはヒープで変換を実行するたびに割り当てと解放する必要があります。最後に、上のコードが追加されるこの変換が発生することなく)に Unicode および Macintosh のビルド (適切な #ifdefs が必要があります。
ここでは、アップしたソリューションは 1)マスクさまざまなプラットフォーム間の違い、および 2)使用効率的なメモリの割り当て方法、および 3)が既存のソース・コードに挿入する簡単なマクロを作成します。定義の 1 例を次に示します。:
#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)を呼び出す方法を使う 1 回以上。これは、大量のメモリを割り当てることで、必要以上されます。ここでは MBC が最大で 1 WCHAR に変換すること、および各 WCHAR には、に最大 2 個の MBC のバイトがあることがわかります。やや多くが必要割り当てることによって、完全に常に変換関数への変換を呼び出すと、コントロールが処理するために回避できます。ヘルパー関数 AfxA2Whelper への呼び出しは MultiByteToWideChar を直接呼び出す場合)変換を実行するためにする必要がある引数のプッシュの数が減少します (これにより、コードで、より発生します。
一時期間を格納する領域を持つマクロにローカル変数を変換マクロを使用する各関数でこれを行う _convert と宣言する必要があります。この例では、上に示したように USES_CONVERSION マクロの呼び出しによってされます。
一般的な変換マクロと OLE 特定のマクロの両方があります。これら二つの異なるマクロ セットは、後で説明します。すべてのマクロは AFXPRIV.H. に存在します。
一般的な変換マクロ
一般的な変換マクロは、基になる機能を形成します。前のセクションで、 A2W は、表示される、マクロの例と実装の 1 つがこのような 「汎用的なマクロ」です。これは OLE と、関連しません。一般的なマクロの設定は、後で説明する ":
A2CW (LPCSTR) -> (LPCWSTR)
A2W (LPCSTR) -> (LPWSTR)
W2CA (LPCWSTR) -> (LPCSTR)
W2A (LPCWSTR) -> (LPSTR)
テキスト変換を行うだけでなく、 TEXTMETRIC、 DEVMODE、 BSTRと OLE によって割り当てられた文字列を変換するためのマクロとヘルパー関数があります。これらのマクロは、この例の対象外です –これらのマクロの詳細については AFXPRIV.H を参照してください。
OLE 変換マクロ
OLE 変換マクロは OLESTR の文字を受け取る関数を処理するために設計されています。OLE ヘッダーを確認すると、 LPCOLESTR と OLECHARへの参照が表示されます。プラットフォームに固有ではなく、これらの型が OLE インターフェイスで使用される文字の種類を示すために使用されます。OLECHAR は Win16 および Macintosh プラットフォームの char 、 Win32 の WCHAR にマップします。
MFC で #ifdef のディレクティブの数を保存するには、 Where OLE 文字列複雑である各変換に似たマクロがある最小コードにします。次のマクロは、最もよく使用されています:
T2COLE (LPCTSTR) -> (LPCOLESTR)
T2OLE (LPCTSTR) -> (LPOLESTR)
OLE2CT (LPCOLESTR) -> (LPCTSTR)
OLE2T (LPCOLESTR) -> (LPCSTR)
もう一度、 TEXTMETRIC、 DEVMODE、 BSTRと 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]);
}
戻り値が戻りの前にデータのコピーを作成することを意味する、オフの戻りマクロの 1 とおりの結果。たとえば、このコードは不適切です:
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
}
マクロは使いやすく、コードに挿入することが簡単ですが上の警告からに対して指定できるように使用する場合は注意が必要です。