COM字串轉換大全

來源:互聯網
上載者:User
文章目錄
  • Empty BSTR strings are NULL pointers.
  • Input Parameters - Passing a BSTR to a COM method
  • Output Parameters - Returning a BSTR from a COM method
COM Strings
 

20 Jan 2001 13:59

Introduction

COM uses Unicode exclusively.  COM strings are called "OLE Strings" or "Basic Strings."  COM objects that aren't built under Unicode must convert OLE strings to ASCII in order to pass them to Win32 and the standard C library.

See the information regarding passing strings between C++ functions.

MSDN articles
  • Strings the OLE Way regarding BSTR usage rules
  • TN059: Using MFC MBCS/Unicode Conversion Macros describes the conversion macros in <atlconv.h>
L"" Does not Create a BSTR!
  • This is really deceptive.  If you're calling an object in the same apartment, using L"" will work but it's incorrect and creates strings that can not be marshalled.
  • Use CComBSTR(L"") instead.
Use ! (==)  instead of != with CComBSTR

The following are not the same:

CComBSTR b1, b2;

if (b1 != b2) // this is wrong
{
}

if (!(b1 == b2)) // this is right
{
}

b1 != b2 compares the underlying BSTR pointers and does not perform a string comparison.

? operator doesn't work with CComBSTR

CComBSTR bar;
BSTR foo, baf;

baf = L"baf";
foo = bar ? bar:baf;

This won't do what you think...  You would think this code evaluates bar ? by converting bar to a BSTR.  But this code ends up calling CComBSTR(baf), causing foo to be assigned to a temporary object that is deleted whenever the compiler feels like it.  Instead, use bar.Length() ? bar:baf

Useful CComBSTR methods
  • AppendBSTR
  • Copy - produces a copy and returns the copy's BSTR
  • CopyTo - copies a BSTR to a BSTR *
  • Attach / Detach
  • CComBSTR(GUID) - converts GUID to string
& operator on CComBSTR results in memory leaks
  • Using the & operator is very dangerous -- if the BSTR * gets written to, the existing string data won't be deallocated
  • Call Empty() before calling operator &
CComBSTR Copy Efficiency
  • Creating a CComBSTR with a BSTR or CComBSTR uses _wcslen to get the length of the BSTR
  • Assigning a BSTR or a CComBSTR to a CComBSTR also uses _wcslen
  • It's undesirable to use _wcslen -- SysStringLen is much faster
  • Therefore, the most efficient way to copy a BSTR as a BSTR is:
    SysAllocStringLen(bstr, SysStringLen(bstr));
  • And the most efficient way to copy a BSTR as a CComBSTR is:
    CComBSTR(SysStringLen(bstr), bstr);
  • And the most efficient way to assign a BSTR to a CComBSTR is:
    bs.Empty();
    bs.Attach(SysAllocStringLen(bstr, SysStringLen(bstr));
TCHAR, LPTSTR, _T, _tcs, OLE2T, and T2OLE
  • These various macros allow developers to write code for UNICODE and non-UNICODE (ASCII) environments easily
  • #include <tchar.h> to get them
  • #include <atlconv.h> to get OLE2T and T2OLE
  • If _UNICODE is defined, TCHAR is a WCHAR.  Otherwise it's a char.
  • LPTSTR is a typedef for TCHAR *
  • If _UNICODE is defined, _T creates LPOLESTR (_T becomes L in this case).  Otherwise _T creates ASCII strings (char *).  _T("foo")
  • The various functions _tprintf, _tcscpy, _tcscmp, _tcslen, etc. are macros that depend on _UNICODE.  If _UNICODE is defined, _tcscpy is wstrcpy.  Otherwise it's strcpy.
  • OLE2T converts UNICODE strings to LPTSTR - you must define USES_CONVERSION in the function that uses it
  • T2OLE converts LPTSTR to LPOLESTR - you must define USES_CONVERSION in the function that uses it
L, LPOLESTR, LPWSTR, BSTR, and CComBSTR
  • L creates hard-coded UNICODE strings, e.g., L"Foo"
  • LPOLESTR is a null-terminated UNICODE string
  • LPOLESTR is a LPWSTR which is a WCHAR *
  • BSTR and LPOLESTR are not identical
  • BSTRs are also null-terminated UNICODE strings, but the beginning of the string contains its length
  • BSTRs are the "preferred string" of COM, so all new interfaces should use BSTR and not LPOLESTR
  • CComBSTR is a convenient wrapper class around BSTR - #include <atlbase.h> to get it
OLE2T / T2OLE / Etc. Warning

In non-Unicode builds, each invocation of these macros allocates memory on the stack.   Therefore these macros should not be used in a loop.  If used in a loop (i.e., that runs 1,000 times) the stack may be overrun.  Stacks are typically only about 50k in size.

Secondly, you should be careful about assigning pointers to the return values of these macros.  The following is a classic error:

WCHAR *pwz = NULL;
try {
    pwz = OLE2T(L"Hello world");
}
catch(...){}
wprintf("%ls", pwz);

After the code in the try block completes, pwz points to deallocated memory.  The behavior of this code snippet is unspecified and varies from machine to machine and also may vary depending on the build type (debug vs. release vs. Unicode).

Conversions / Operations
  • To create a hard-coded LPOLESTR:

L"foo"

  • Convert a BSTR to an LPOLESTR:

LPOLESTR wstr = bstr;

  • Convert an LPOLESTR or a BSTR to a TSTR:

USES_CONVERSION;
TCHAR *sz = OLE2T(lpolestr_or_bstr);

See also WideCharToMultiByteWideCharToMultiByte does not create a null-terminated ASCII string.  You should avoid calling WideCharToMultiByte in UNICODE builds - use #ifdef _UNICODE.  Here is the correct usage:

HRESULT appendBSTR(basic_string<TCHAR>& t, BSTR wsz)
{
  if (!wsz) return S_OK;

#ifdef _UNICODE
t.append(wsz);
#else
long len = SysStringLen(wsz) + 1;
char * a = new CHAR[len];

if (!WideCharToMultiByte(CP_ACP, 0, wsz, len, (char*)a, len, NULL, FALSE))
{
    delete[] a;
   return E_FAIL;
}

*(a + len-1) = 0;
t.append(a);

  delete[] a;
#endif

return S_OK;
}
 

  • Convert a TSTR to an LPOLESTR:

    USES_CONVERSION;
    LPOLESTR lpolestr = T2OLE(szText);

    See also MultiByteToWideChar.  You should avoid calling MultiByteToWideChar in UNICODE builds - use #ifdef _UNICODE.

  • Convert a TSTR to a BSTR:

CComBSTR bstr(_T("foo"));

  • Copy a BSTR:

CComBSTR bstr_copy(bstr);

Use bstr_copy.Detach() if you don't want the copy to get free'd.

BSTR in COM Interfaces

This section describes how to pass/return BSTRs via COM.

Empty BSTR strings are NULL pointers.Input Parameters - Passing a BSTR to a COM method

Caller - Caller converts TSTR to BSTR and frees the BSTR:

CComBStr bstr(szThisIsA_TStr);
comObject -> someMethod(bstr);

COM method (callee) converts BSTR to TSTR:

USES_CONVERSION;
LPCTSTR szParam = OLE2T(bstr);

Output Parameters - Returning a BSTR from a COM method

COM method (callee) converts internal TSTR data to BSTR:

CComBSTR bstr("Hi");
// pbstrOut is a BSTR *
*pbstrOut = bstr.Detach();

Caller - Caller converts BSTR to TSTR and frees the BSTR:

USES_CONVERSION;

BSTR bstrName;
foo->get_Name(&bstrName);
LPCTSTR szName = OLE2T(bstrName);
...
SysFreeString(bstrName);

-or- (String is free'd for you automatically...)

USES_CONVERSION;

CComBStr bstrName;
foo->get_Name(&bstrName);
LPCTSTR szName = OLE2T(bstrName);

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.