傳遞至並從 32 位元 OLE API 和介面方法收到的所有字串都使用 Unicode。這需要使用 ANSI 字串傳遞給 OLE 之前將它們轉換成 Unicode,並將從 OLE 接收到 ANSI [Unicode 字串轉換的應用程式。本文將告訴您如何可以完成這些轉換。
Windows NT 實作 Unicode (或寬字元) 和接受字串參數的 Win32 函式的 ANSI 版本。然而 Windows 95 未實作大部分的 Win32 函式接受字串參數的 Unicode 版本。相反地它會實作僅 ANSI 版本的這些函式。
主要的例外狀況,這項規則是 32 位元 OLE。32 位元 OLE API 和 Windows NT 和 Windows 95 上的介面方法是以獨佔模式使用 Unicode。 這些函式的 ANSI 版本未實作 Windows NT 或 Windows 95 上。
這表示必須在 Windows 95 與 Windows NT 上執行的 32 位元應用程式必須使用非-OLE Win32 函式的 ANSI 版本,而且必須 ANSI 字串前將轉換為 Unicode 傳遞給 OLE。
只在 Windows NT 執行 32 位元 Unicode 應用程式不需要使用任何 ANSI/Unicode 轉換函式。
Win32 提供 MultiByteToWideChar] 及 [WideCharToMultiByte] 來將以 Unicode 的 ANSI 字串和 Unicode 字串轉換成 ANSI。本文提供 AnsiToUnicode 和 UnicodeToAnsi ANSI/Unicode 轉換為使用這些函式。
/*
* AnsiToUnicode converts the ANSI string pszA to a Unicode string
* and returns the Unicode string through ppszW. Space for the
* the converted string is allocated by AnsiToUnicode.
*/
HRESULT __fastcall AnsiToUnicode(LPCSTR pszA, LPOLESTR* ppszW)
{
ULONG cCharacters;
DWORD dwError;
// If input is null then just return the same.
if (NULL == pszA)
{
*ppszW = NULL;
return NOERROR;
}
// Determine number of wide characters to be allocated for the
// Unicode string.
cCharacters = strlen(pszA)+1;
// Use of the OLE allocator is required if the resultant Unicode
// string will be passed to another COM component and if that
// component will free it. Otherwise you can use your own allocator.
*ppszW = (LPOLESTR) CoTaskMemAlloc(cCharacters*2);
if (NULL == *ppszW)
return E_OUTOFMEMORY;
// Covert to Unicode.
if (0 == MultiByteToWideChar(CP_ACP, 0, pszA, cCharacters,
*ppszW, cCharacters))
{
dwError = GetLastError();
CoTaskMemFree(*ppszW);
*ppszW = NULL;
return HRESULT_FROM_WIN32(dwError);
}
return NOERROR;
/*
* UnicodeToAnsi converts the Unicode string pszW to an ANSI string
* and returns the ANSI string through ppszA. Space for the
* the converted string is allocated by UnicodeToAnsi.
*/
HRESULT __fastcall UnicodeToAnsi(LPCOLESTR pszW, LPSTR* ppszA)
{
ULONG cbAnsi, cCharacters;
DWORD dwError;
// If input is null then just return the same.
if (pszW == NULL)
{
*ppszA = NULL;
return NOERROR;
}
cCharacters = wcslen(pszW)+1;
// Determine number of bytes to be allocated for ANSI string. An
// ANSI string can have at most 2 bytes per character (for Double
// Byte Character Strings.)
cbAnsi = cCharacters*2;
// Use of the OLE allocator is not required because the resultant
// ANSI string will never be passed to another COM component. You
// can use your own allocator.
*ppszA = (LPSTR) CoTaskMemAlloc(cbAnsi);
if (NULL == *ppszA)
return E_OUTOFMEMORY;
// Convert to ANSI.
if (0 == WideCharToMultiByte(CP_ACP, 0, pszW, cCharacters, *ppszA,
cbAnsi, NULL, NULL))
{
dwError = GetLastError();
CoTaskMemFree(*ppszA);
*ppszA = NULL;
return HRESULT_FROM_WIN32(dwError);
}
return NOERROR;
}
範例使用這些函式的是,如下所示。CoTaskMemFree 用來如果 CoTaskMemAlloc 已用它來配置字串釋放已轉換的字串。轉換後的字串必須不釋放如果透過輸出參數傳回至另一個的 OLE 元件因為該元件是負責釋出字串。LPOLESTR 是 Unicode 字串指標。
// The following code gets an ANSI filename that is specified by the
// user in the OpenFile common dialog. This file name is converted into
// a Unicode string and is passed to the OLE API CreateFileMoniker. The
// Unicode string is then freed.
OPENFILENAME ofn;
LPOLESTR pszFileNameW;
LPMONIKER pmk;
:
// Get file name from OpenFile Common Dialog. The ANSI file name will
// be placed in ofn.lpstrFile
GetOpenFileName(&ofn);
:
AnsiToUnicode(ofn.lpstrFile, &pszFileNameW);
CreateFileMoniker(pszFileNameW, &pmk);
CoTaskMemFree(pszFileNameW);
// The following code implements IOleInPlaceFrame::SetStatusText.
// The lpszStatusText string, that is received from another OLE
// component, uses Unicode. The string is converted to ANSI before it is
// passed to the ANSI version of SetWindowText. Windows 95 supports only
// the ANSI version of SetWindowText.
COleInPlaceFrame::SetStatusText(LPCOLESTR pszStatusTextW)
{
LPSTR pszStatusTextA;
UnicodeToAnsi(pszStatusTextW, &pszStatusTextA);
SetWindowText(m_hwndStatus, pszStatusTextA);
CoTaskMemFree(pszStatusTextA);
}
注意: AnsiToUnicode 和 UnicodeToAnsi 關於配置器會用它來配置已轉換的字串中的註解。需要用結果的字串會傳遞至另一個 OLE 元件時,才和該元件可以釋放字串 CoTaskMemAlloc (OLE 配置器)。這表示將字串當做中參數傳遞給 OLE 介面方法不需要使用 OLE 配置器。使用 OLE 配置器必須配置的字串,用來當做在逾時參數傳遞或透過外傳參數或在逾時參數傳回。
字串常數可以轉換成 Unicode 在編譯時期藉由使用 OLESTR 巨集。例如:
CreateFileMoniker(OLESTR("c:\\boo\\har.doc"), &pmk);
可在 Microsoft 基礎類別 (MFC) 原始程式碼的隨附 Visual C++ 4.0 編譯器中找到另一個範例的 ANSI/Unicode 轉換常式。這些常式所述 MFC Technote 59: 巨 '使用 MFC MBCS/Unicode 轉換集'。定義是在 \msdev\mfc\include\afxpriv.h OLE2T、 T2OLE、 OLE2CT、 T2COLE、 A2W、 W2A、 A2CW、 W2CA 及 USES_CONVERSION 這些巨集。請參閱 AfxA2WHelper 和 AfxW2AHelper \msdev\mfc\src 以及在 MFC 原始程式碼中 \msdev\mfc\src OLE2T、 T2OLE、 OLE2CT 和 T2COLE 使用 MFC 原始程式碼中。這些函式,允許程式碼進行編譯可能是 Unicode 或 ANSI 取決於是否已經造成 _UNICODE 前置處理器定義。比方說 CreateFileMoniker 在上述範例中可以被進行呼叫,如下所示與 MFC 巨集,:
USES_CONVERSION;
GetOpenFileName(&ofn);
CreateFileMoniker(T2OLE(ofn.lpstrFile), &pmk);
如果定義 _UNICODE T2OLE 定義如下:
inline LPOLESTR T2OLE(LPTSTR lp) { return lp; }
如果不定義 _UNICODE T2OLE 定義如下:
#define T2OLE(lpa) A2W(lpa)
T2OLE 的 T 表示型別轉換成一個 OLE 字串 (Unicode 字串) 是 Unicode 字串定義 _UNICODE 時和 ANSI 字串不定義 _UNICODE 時。同樣地 LPTSTR 是 Unicode 字串定義 _UNICODE 時的指標,而是為 ANSI 字串的指標時,定義 _UNICODE 未定義。定義 _UNICODE 時 T2OLE 並不會執行任何轉換 (LPTSTR = = LPOLESTR)。如果不定義 Unicode 都稱為 A2W。將 A2W 的 ANSI 字串轉換成 Unicode,如下所示:
#define A2W(lpa) (\
((LPCSTR)lpa == NULL) ? NULL : (\
_convert = (strlen(lpa)+1),\
AfxA2WHelper((LPWSTR) alloca(_convert*2), lpa, _convert)\
)\
)
AfxA2WHelper 使用 MultiByteToWideChar 來執行轉換。
MFC 轉換巨集使用 _alloca 配置從已轉換的字串在程式堆疊空間。程序呼叫完成時,空間會自動解除配置。OLE 需要 OLE 配置器將用於會由一個元件配置並釋放被其他的所有字串 (資料)。這表示透過外傳參數傳遞的字串,而且在-外傳參數的 OLE 介面必須配置與 OLE 配置器。在參數需要不能以配置 OLE 配置器因為呼叫者是負責釋放它們。大部分連結/內嵌 OLE 介面和 API 傳遞字串做為參數中。 因此 MFC 轉換巨集可用於大多數的情況。針對在出參數或傳回透過外傳參數的值,因為它們不執行配置空間使用 OLE 配置器,不能使用 MFC 轉換巨集。在這些情況下可 AnsiToUnicode 和 UnicodeToAnsi。
還另一組 Unicode/ANSI 轉換常式可以找到 Microsoft 系統日誌]) 中的 OLE 的 Don 方塊資料行中八月 1995 Vol.10 [否]。 8,版面 86。Don 方塊定義使用轉換運算子會傳回轉換的 Unicode/ANSI 字串的 C + + 類別。當物件超出範圍時,會自動釋放配置的空間。配置使用 OLE 配置器,並不釋放配置的空間可透過在不足或外傳參數傳遞的字串,這個類別可以進行修改。
類別的其中之一,String16,從 Don 方塊資料行,它會將一個 ANSI 字串轉換為 Unicode,如下。另一個類別,String8 這一個類似的用於 Unicode 轉換成 ANSI。從先前的範例 CreateFileMoniker 呼叫可以與這個類別,如下所示進行:
GetOpenFileName(&ofn);
CreateFileMoniker(String16(ofn.lpstrFile), &pmk);
上述程式碼中建立 String16 的執行個體。類別的建構函式會將 ANSI 字串轉換為 Unicode。語言實作會呼叫轉型運算子、 運算子 const wchar_t *、 轉型成 CreateFileMoniker 的第一個參數型別的這個參數。轉換運算子會傳回 Unicode 字串傳遞至 CreateFileMoniker。物件會在步超出範圍時解構。
// String16 ////////////////////////////////////////////////////////
// Shim class that converts both 8-bit (foreign) and
// 16-bit (native) strings to 16-bit wideness
class String16 {
public:
// native and foreign constructors
String16(const char *p8);
String16(const wchar_t *p16);
// non-virtual destructor (this class is concrete)
~String16(void);
// native conversion operator
operator const wchar_t * (void) const;
private:
// native wideness string
wchar_t *m_sz;
// is foreign??
BOOL m_bIsForeign;
// protect against assignment!
String16(const String16&);
String16& operator=(const String16&);
};
// native constructor is a pass-through
inline String16::String16(const wchar_t *p16)
: m_sz((wchar_t *)p16), m_bIsForeign(FALSE)
{
}
// simply give out the native wideness string
inline String16::operator const wchar_t * (void) const
{
return m_sz;
}
// foreign constructor requires allocation of a native
// string and conversion
inline String16::String16(const char *p8)
: m_bIsForeign(TRUE)
{
// calculate string length
size_t len = strlen(p8);
// calculate required buffer size (some characters may
// already occupy 16-bits under DBCS)
size_t size = mbstowcs(0, p8, len) + 1;
// alloc native string and convert
if (m_sz = new wchar_t[size])
mbstowcs(m_sz, p8, size);
}
// delete native string only if synthesized in foreign constructor
inline String16::~String16(void) {
if (m_bIsForeign)
delete[] m_sz;
}