18.04.2015 Views

ArcGIS Engine Developer Guide

ArcGIS Engine Developer Guide

ArcGIS Engine Developer Guide

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

VISUAL C++<br />

switches are used to change Windows API functions (for example,<br />

SetWindowText) to resolve to an ANSI version (SetWindowTextA) or a Unicode<br />

version (SetWindowTextW). In addition, character-independent types (TCHAR<br />

defined in tchar.h) were introduced to represent a character; on an ANSI build<br />

this is defined to be a char, and on a Unicode build this is a wchar_t, a typedef<br />

defined as unsigned short. To perform standard C string manipulation, there are<br />

typically three different definitions of the same function; for example, for a caseinsensitive<br />

comparison, strcmp provides the ANSI version, wcscmp provides the<br />

Unicode version, and _tcscmp provides the TCHAR version. There is also a fourth<br />

version—_mbscmp—which is a variation of the 8-bit ANSI version that will<br />

interpret multibyte character sequences (MBCS) within the 8-bit string.<br />

To check if two CComBSTR strings are different,<br />

do not use the not equal (“!=”) operator. The<br />

“==” operator performs a case-sensitive comparison<br />

of the string contents; however, “!=” will<br />

compare pointer values and not the string<br />

contents, typically returning false.<br />

106 • <strong>ArcGIS</strong> <strong>Engine</strong> <strong>Developer</strong> <strong>Guide</strong><br />

// Initialize some fixed length strings.<br />

char* pNameANSI = "Bill"; // 5 bytes (4 characters plus a terminator)<br />

wchar_t* pNameUNICODE = L"Bill"; // 10 bytes (4 16-bit characters plus a<br />

16-bit terminator)<br />

TCHAR* pNameTCHAR = _T("Bill"); // either 5 or 10 depending on compiler<br />

settings<br />

COM APIs represent variable length strings with a BSTR type; this is a pointer to<br />

a sequence of OLECHAR characters, which is defined as Unicode characters and<br />

is the same as a wchar_t. A BSTR must be allocated and released with the<br />

SysAllocString and SysFreeString windows functions. Unlike C strings, they can<br />

contain embedded zero characters, although this is unusual. The BSTR also has a<br />

count value, which is stored four bytes before the BSTR pointer address. The<br />

CComBSTR wrappers are often used to manage the lifetime of a string.<br />

Do not pass a pointer to a C style array of Unicode characters (OLECHAR or<br />

wchar_t) to a function expecting a BSTR. The compiler will not raise an error as<br />

the types are identical. However, the function receiving the BSTR can behave<br />

incorrectly or crash when accessing the string length, which will be random<br />

memory values.<br />

ipFoo->put_WindowTitle(L"Hello"); // This is bad!<br />

ipFoo->put_WindowTitle(CComBSTR(L"Hello")); // This correctly initializes<br />

and passes a BSTR.<br />

ATL provides conversion macros to switch strings between ANSI (A), TCHAR<br />

(T), Unicode (W), and OLECHAR (OLE). In addition, the types can have a<br />

const modifier (C). These macros use the abbreviations shown in brackets with a<br />

“2” between them. For example, to convert between OLECHAR (such as an<br />

input BSTR) to const TCHAR (for use in a Windows function), use the OLE2CT<br />

conversion macro. To convert ANSI to Unicode, use A2W. These macros require<br />

the USES_CONVERSION macro to be placed at the top of a method; this will<br />

create some local variables that are used by the conversion macros. When the<br />

source and destination character sets are different and the destination type is not<br />

a BSTR, the macro allocates the destination string on the call stack (using the<br />

_alloca runtime function). It’s important to realize this especially when using<br />

these macros within a loop; otherwise, the stack may grow large and run out of<br />

stack space.<br />

STDMETHODIMP CFoo::put_WindowTitle(BSTR bstrTitle)<br />

{<br />

USES_CONVERSION;<br />

if (::SysStringLen(bstrTitle) == 0)<br />

return E_INVALIDARG;

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!