TN059:使用MFC MBCS/Unicode翻译宏
说明 |
---|
以下技术声明,则它在联机文档,首先包括了不更新。因此,某些过程和主题可能已过时或不正确。有关最新信息,建议您搜索议题在联机文档的索引。 |
此说明描述如何为 MBCS/Unicode 转换使用宏,在 AFXPRIV.H. 定义。这些宏是最有用,如果应用程序将直接 OLE API 或由于某种原因,通常需要将 Unicode 和 MBCS 之间。
概述
在 MFC 那样,特定 DLL (用于 MFCANS32.DLL) 自动将 Unicode 和 MBCS 之间,当 OLE 接口调用。此 DLL 是允许 OLE 应用程序编写的一个几乎透明层,就象 OLE API 和接口 MBCS,因此,即使它们始终是 Unicode (但在 Macintosh)。在此层方便以及允许的应用程序快。从 Win16 移植到 Win32 (MFC、 Microsoft Word、 Microsoft Excel 和 VBA,是使用此技术) 的某些 Microsoft 应用程序时,其有时明显的性能造成影响。因此, MFC 4.x 不使用此 DLL 和直接使用 Unicode OLE 接口不连接。为此, MFC 需要转换为 Unicode 转换为 MBCS,当调用以一 OLE 接口并经常时需要转换为从 Unicode 的 MBCS,当实现 OLE 接口时。为了处理高效且易于使用,许多的宏创建使此转换更加轻松。
一种最大的障碍创建一组宏是内存分配。由于字符串不能转换的例如,必须将保存转换的结果的新内存。这可以对代码类似于以下内容:
// 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) 可以轻松地插入到现有源代码中的某些宏。这是一个示例的其中一个定义:
#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 () 函数从堆栈分配内存而不是堆。分配内存从堆栈比分配堆中的内存 express,并且,内存自动被释放,在该函数退出时。此外,宏避免调用 MultiByteToWideChar (或 WideCharToMultiByte) 超过一次。这是通过分配更多的内存比需要的完成。我们知道 MBC 将转换为最多一 WCHAR ,并为每 WCHAR 我们最多具有两个 MBC 字节。通过将确保更多的必要,但是,足够总是处理转换第二次调用第二次调用转换功能避免。为帮助器函数 AfxA2Whelper 的调用减少的参数驱动器的个数必须完成才能执行转换 (这会导致较小的代码,相比,如果它直接调用 MultiByteToWideChar )。
为了为了使宏中存储的空间该临时长度,声明局部变量调用执行此在每个函数使用将宏的 _convert 是必需的。这是通过调用 USES_CONVERSION 宏完成如上述在此示例中。
具有两个泛翻译宏和 OLE 特定宏。这两个其他宏设置如下所述。所有宏位于 AFXPRIV.H。
泛型翻译宏
泛型翻译宏窗体基础结构。在前面的部分以及实现显示的一个宏示例, A2W,是这样的一个 “常规”宏。它不专门与 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 映射到 Win32 的 char 在 Win16 和 Macintosh 平台和 WCHAR 。
使 #ifdef 指令数在 MFC 代码添加到最低有位置 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]);
}
,除非返回值在返回之前,这意味着数据副本不希望返回结果的一个宏。例如,此代码是错误的:
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
}
宏就易用性更方便地插入到代码中,,但,可以从上面警告通知,需要小心,在使用它们。