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)

除执行文本转换外,还有宏,并帮助器对转换 TEXTMETRICDEVMODEBSTR和 OLE 分配的字符串函数。 这些宏超出了本文的讨论范围之内 –请参见 AFXPRIV.H 有关这些宏的更多信息。

OLE 翻译宏

OLE 转换宏来处理需要 OLESTR 个字符的函数而设计。 如果您检查 OLE 标题,您将看到许多对 LPCOLESTROLECHAR。 这些类型在不特定于平台的方法来引用用于 OLE 接口的字符的类型。 OLECHAR 映射到 Win32 的 char 在 Win16 和 Macintosh 平台和 WCHAR

使 #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
}

宏就易用性更方便地插入到代码中,,但,可以从上面警告通知,需要小心,在使用它们。

请参见

其他资源

由Number "技术说明

技术说明按类别