[COM]에서 문자열 사용
COM strings은 "OLE Strings" 혹은 "Basic Strings"이라고 한다.
L"" 은 BSTR이 아니다
같은 아파트먼트 에서 사용하기위해 쓰면 동작하지만 옳은 것은 아니며,
마샬되지 않는 문자열이 만들어진다.
CComBSTR(L"") 를 사용하라.
CComBSTR을 비교하기 위해 "!= " 대신에 "! (==)" 를 사용하라
아래 두 코드는
다르다.
CComBSTR b1, b2;
if (b1 != b2) // 틀렸다
{
}if (!(b1 == b2)) // 맞다
{
}
b1 != b2 는 문자열을 비교하는 것이 아니라 BSTR 포인터를 비교한다.
CComBSTR 에서 연산자는 동작하지 않는다
CComBSTR bar;
BSTR foo, baf;
baf = L"baf";
foo = bar ? bar:baf;
생각한것처럼 동작하지 않는다.
bar는 bar를 BSTR로 변환한다. 결과적으로 CComBSTR(baf) 호출하기 때문에 foo 는 임시 객체가 할당되고,
임시객체는 삭제된다. 위 코드 대신에 bar.Length() ? bar:baf 를 써라.
유용한 CComBSTR 메서드
* AppendBSTR
*
Copy - 복사된 BSTR 사본을 리턴한다.
* CopyTo - BSTR 을 BSTR * 에 복사
*
Attach / Detach
* CComBSTR(GUID) - GUID 를 문자열로 변환
& 연산은 CComBSTR 에 memory leak을 야기한다
* & 연산사용은
매우 위험. BSTR * 가 기록되면 deallocated 할 수 없게된다.
* & 연산을 사용하기 전에 Empty()를
사용하라.
CComBSTR 복사
* BSTR로 CComBSTR 을 만들어라. BSTR 의 길이를 구하기 위해
_wcslen()를 사용하라
* BSTR혹은 CComBSTR 을 CComBSTR에 assign 하라. 역시 _wcslen()를
쓴다.
* _wcslen 보다는 {{{ SysStringLen }}}이 훨씬 빠르다.
* 따라서, BSTR을
BSTR 로 복사하는 가장 효과적인 방법은
SysAllocStringLen(bstr,
SysStringLen(bstr));
* BSTR을 CComBSTR로 복사하는 가장 효과적인
방법은
CComBSTR(SysStringLen(bstr), bstr);
* BSTR를
CComBSTR에 할당하는 가장 효과적인
방법은
bs.Empty();
bs.Attach(SysAllocStringLen(bstr,
SysStringLen(bstr));
TCHAR, LPTSTR, _T, _tcs, OLE2T, and T2OLE
* UNICODE 혹은
non-UNICODE 코드를 쓰는 다양한 매크로가 있다.
* #include
*
#include
* _UNICODE 가 정의되면 TCHAR 은
WCHAR이고, 정의되어 있지 않으면 char이 된다.
* LPTSTR 은 TCHAR * 이다
*
_UNICODE 가 정의되면, _T는 LPOLESTR 이된다 (_T 가 L 가 된다), 정의되어 있지 않으면 _T 는 (char *) 가 된다.
예 : _T("foo")
* _tprintf, _tcscpy, _tcscmp, _tcslen 함수들이 _UNICODE 에
연관되어 있다.
* OLE2T 는 UNICODE 문자열을 LPTSTR 로 만든다 - 사용하기전에 USES_CONVERSION 를
써야한다.
* T2OLE 는 LPTSTR 을 LPOLESTR 로 바꾼다. - 사용하기전에 USES_CONVERSION 를
써야한다.
L, LPOLESTR, LPWSTR, BSTR, and CComBSTR
* L는 하드코드된 UNICODE 문자열. 예 : L"Foo"
* LPOLESTR 은
null-terminated UNICODE 문자열
* LPOLESTR == LPWSTR == WCHAR *
*
BSTR 과 LPOLESTR 은 같다
* BSTR은 null-terminated UNICODE 문자열이다. 하지만, 문자열의
시작에 길이를 가지고 있다.
* BSTR은 COM에서 가장 선호하는 문자열, 인터페이스는 BSTR를 써야지 LPOLESTR를
쓰지 않는다.
* CComBSTR 는 BSTR의 편리한 wrapper - #include
OLE2T / T2OLE / 기타 조언
* non-Unicode 에서 각 매크로는 stack을 할당한다.
(대략 50k이내에서 사용)
* 리턴값에 대한 포인터 사용에 주의하라. 다음은 전형적인
오류이다.
WCHAR *pwz = NULL;
try {
pwz =
OLE2T(L"Hello world");
}
catch(...){}
wprintf("%ls", pwz);
try가 끝나면 pwz 는 해지된 메모리를 가리킨다. 이 코드는 빌드형태(debug vs. release vs.
Unicode)에 종속적이다.
Conversions / Operations
* hard-coded LPOLESTR
만들기
L"foo"
* BSTR -> LPOLESTR
LPOLESTR wstr = bstr;
* LPOLESTR, BSTR -> TSTR
USES_CONVERSION;
TCHAR
*sz = OLE2T(lpolestr_or_bstr);
WideCharToMultiByte 는 null-terminated ASCII 문자열을 만들지 않는다. UNICODE 빌드에서 WideCharToMultiByte 를 사용하지 말 것. 대신에 #ifdef _UNICODE 를 사용하라. 옳은 사용법은 ...
HRESULT appendBSTR(basic_string
& 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;
#endifreturn S_OK;
}
* TSTR -> LPOLESTR
USES_CONVERSION;
LPOLESTR lpolestr = T2OLE(szText);
UNICODE 에서 MultiByteToWideChar 를 사용하지 말라. 대신에 #ifdef _UNICODE를 써라.
* TSTR -> BSTR
CComBSTR bstr(_T("foo"));
* BSTR 복사
CComBSTR bstr_copy(bstr);
해지 되지 않게하려면 bstr_copy.Detach()를 써라.
COM 인터페이스에서 BSTR 사용
* 빈 BSTR은 NULL 포인터이다.
* 입력 파라미터
- BSTR 을 COM 에 전달하기
* Caller - Caller는 TSTR 을 BSTR 로 바꾸고 BSTR 을 해지
한다.
CComBStr bstr(szThisIsA_TStr);
comObject ->
someMethod(bstr);
* COM 메서드(callee) 는 BSTR 을 TSTR로 변환한다.
USES_CONVERSION;
LPCTSTR szParam = OLE2T(bstr);
* 출력 파라미터 - COM에서 BSTR을 리턴한다.
* COM 메서드는 (callee) 내부 TSTR 을
BSTR로 바꾼다.
CComBSTR bstr("Hi");
// pbstrOut is a BSTR *
*pbstrOut =
bstr.Detach();
* Caller - Caller 는 BSTR 을 TSTR 로 바꾸고 BSTR을
해지한다.
USES_CONVERSION;
BSTR bstrName;
foo->get_Name(&bstrName);
LPCTSTR szName =
OLE2T(bstrName);
...
SysFreeString(bstrName);
또는, (자동으로 해지)
USES_CONVERSION;
foo->get_Name(&bstrName);
LPCTSTR szName = OLE2T(bstrName);