티스토리 툴바

빨간꽃밭

COM String

2008/06/20 16:18 : VC++

[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 OLE2T, T2OLE 를 사용
 * _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;
#endif

return 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;

CComBStr bstrName;
foo->get_Name(&bstrName);
LPCTSTR szName = OLE2T(bstrName);
TAGVC++
Posted by 빨간꽃 Trackback 0 Comment 0

MDI환경에서 HtmlView의 window.open으로 새창을 열때 새 ChildFrame에 문서 띄우기

void CWebView::OnNewWindow2(LPDISPATCH* ppDisp, BOOL* Cancel)
{
 
    CUFOApp* pApp = (CUFOApp*)AfxGetApp();
    CMultiDocTemplate* _pWebTemplate;
    _pWebTemplate = pApp->GetWebDocTemplate();
    ASSERT(_pWebTemplate);

 CChildWebFrame* pChldFrme = (CChildWebFrame*)((CMainFrame*)AfxGetMainWnd())->MDIGetActive();
 
 
  CChildWebFrame* pNewFrame = (CChildWebFrame*)_pWebTemplate->CreateNewFrame(NULL,NULL);//GetDocument(),
  ASSERT(pNewFrame);
 

  _pWebTemplate->InitialUpdateFrame(pNewFrame, NULL);
  CHtmlView * pWBVw = (CHtmlView*)pNewFrame->GetActiveView();
  ASSERT(pWBVw);
  pWBVw->SetRegisterAsBrowser(TRUE);
  *ppDisp = pWBVw->GetApplication();
  pWBVw->ShowScrollBar(SB_BOTH,TRUE);
  CHtmlView::OnNewWindow2(ppDisp, Cancel);
}



window.close event 받아 HtmlView 닫기

 void CWebView::OnParentNotify(UINT message, LPARAM lParam ) 
{
 if ((LOWORD(message) == WM_DESTROY) && ((HWND)lParam == m_wndBrowser))  
 {  
  CChildWebFrame* pThisFrme = (CChildWebFrame*)((CMainFrame*)AfxGetMainWnd())->MDIGetActive();
  pThisFrme->PostMessage(WM_CLOSE, 0, 0);

 }  
 else  
  CHtmlView::OnParentNotify(message, lParam );
}

TAGVC++
Posted by 빨간꽃 Trackback 0 Comment 0

TinyXML 파서 사용하기

2008/06/20 16:11 : VC++
1. TinyXml을 사용 할려면

- 먼저 TinyXml 라이브러리를 다운 받은 후 빌더를 해야된다.
  빌더를 할 때는 이 라이브러리를 사용할 프로젝트가
  싱글 쓰레드인지 멀티 쓰레드 인지에 따라서 tinyXml의 쓰레드 옵션을 설정 후 빌드  해야된다.

- 빌드가 끝나면 사용할 프로젝트에서 lib파일을 링크 시킨다.

- tinyxml.h, tinyxml.cpp, tinyxmlerror.cpp, tinyxmlparser.cpp를 프로젝트에 포함시킨다.
- tinystr.h 파일을 프로젝트 폴더에 포함시킨다.

- 위 파일 중 tinyxml.h 파일만 소스에서 include 하면 된다.

- MFC 프로젝트는 tinyxml.cpp, tinyxmlerror.cpp, tinyxmlparser.cpp
의 상단에 #include "stdafx.h”를 포함시킨다.

- TinyXml을 사용한 후 따로 delete로 지울 필요는 없다
  즉 TiXmlNode* node = new ....; 이렇게 사용된 것들..).

2. xml 파일 읽기

- TiXmlDocument doc( "menu.xml" );
   doc.LoadFile();

- TiXmlDocument m_XmlDoc;

      if( m_XmlDoc.LoadFile("menu.xml" ) == false )

             return ERR_LOADXML;
3. 노드의 이동

- 루트에서 시작하여 바로 Option 노드로 이동할려면
TiXmlNode* node = doc.FirstChild("menus")->FirstChild("menu")->FirstChild( "submenu" );

4. 노드의 애트리뷰트 값을 얻기

- 현재 노드에서 모든 자식노드의 애트리뷰트 값을 얻을려면 다음과 같이 한다.

    node = node->FirstChild();
    CONTROL_RECT ControlRect;
    TiXmlElement* elem;
while( node != NULL )
    {
      elem = node->ToElement();
      elem->Attribute( "Index", &ControlRect.index )
      elem->Attribute( "X", &ControlRect.x );
      elem->Attribute( "Y", &ControlRect.y );
      elem->Attribute( "W", &ControlRect.w );
      elem->Attribute( "H", &ControlRect.h );
      node = node->NextSibling();
    }
      Attribute 의 리턴 값으로 애트리뷰트 값의 문자형을 얻을 수 있다.
- 애트리뷰트 이동 방법

    // 노드의 첫 애트리뷰트에서 마지막 애트리뷰트까지 이동
    count = 0;
    for( element = todoElement->FirstChildElement();
      element;
      element = element->NextSiblingElement() )
    {
      count++;
    }
5. 애트리뷰트를 얻을 수 있도록 노드 대신 element를 얻는 방법

    - node = node->FirstChild();
TiXmlElement* Rootelem = node->NextSiblingElement( _strNodeName );
    TiXmlElement* elem = Rootelem->FirstChildElement( _strSubNodeName );
    elem->Attribute( "Index", &iIndex );
6. 애트리뷰트의 첫버째 속성과 다음 속성을 얻는 방법

- TiXmlAttribute* Attribut;
Attribut = elem->FirstAttribute()

// 정수 및 스트링
Attribut->IntValue();
Attribut->Value();

// 다음 애트리뷰트 값
Attribut = Attribut->Next();
TAGVC++
Posted by 빨간꽃 Trackback 0 Comment 0