GSI

Smart Ptr

#ifndef SMARTPTR_H
#define SMARTPTR_H

template <class T> class SmartPtr;

// IRefCount 참조 횟수 관리를 위한 인터페이스
// 클래스들은 이것을 직접 구현해도 되고, 아니면
// 내부적으로 IRefCount를 구현하고 있는 SmartPtr을 사용해도 된다.

template <class T> class IRefCount {
    friend class SmartPtr<T>;
protected:
    virtual void AddRef() = 0;
    virtual void Release() = 0;
    virtual T* GetPtr() const = 0;
};

// IRefCountImpl
// IRefCount의 표준적인 구현
// 이것을 상속하기만 하면 참조 횟수 관리 기능이 생긴다.
// class CMyObject : public IrefCountImpl<CMyObjct> { ... };
// 주의: 개별 클래스가 IRefCount를 꼭 구현할 필요는 없지만,
// 직접 구현함으로써 메모리 단편화를 줄일 수도 있다.

template <class T> class IRefCountImpl
: public IRefCount<T>
{
private:
    int m_Count;

protected:
    virtual void AddRef() { m_Count++; }
    virtual void Release();
    {
        assert( m_Count>=0);
        m_Count--;
        if( m_Count<=0 )
        {
            Destroy();
        }
    }
    virtual T* GetPtr() const { return ( (T*)this ); }
    virtual void Destroy() { if(GetPtr()!=NULL) delete GetPtr(); }

    IRefCountImpl() { m_Count = 0; }
};

// SmartPtr

template <class T> class SmartPtr
{
private:
    IRefCount<T> *m_RefCount;
// RefCounter
// IRefCount를 직접 구현하지 않는 클래스를 위한 내부구현.
// SmartPtr은 이 내부 구현과 클래스 T의 IRefCount 구현중
// 적절한 것ㅇ르 자동적으로 선택한다.

    class RefCounter : public IRefCountImpl<T> {
    private:
         T *m_Ptr;
    protected:
         virtual T* GetPtr() const { return m_Ptr; }
         virtual void Destroy() { delete this; }

    public:
       RefCounter( T* ptr ) { m_Ptr = ptr; }
       virtual ~RefCounter() { IRefCountImpl<T>::Destroy(); }
    };
//  T가 IRefCount를 구현하지 않았다면 이 메서드가 호출된다.
    void Assign( void *ptr )
    {
        if( ptr==NULL )
            Assign( (IRefCount<T> *)NULL );
        else
        {
            Assign( new RefCounter( static_cast<T*>(ptr) ) );
        }
    }

     // T가 IRefCount를 구현하고 있다면 Assign(void *ptr) 대신
// 이 메서드가 호출된다.
// 이를 통해서 메모리 사용이 좀더 최적화된다.
    void Assign( IRefCount<T> *refcount )
    {
        if( refcount != NULL )
             refcount->AddRef();
        IRefCount<T> *oldref = m_RefCount;
        m_RefCount = refcount;
        if( oldref!=NULL )
             oldref->Release();
    }
public:

    SmartPtr() { m_RefCount = NULL; }
    SmartPtr( T *ptr ) { m_RefCount = NULL; Assign(ptr); }
    SmartPtr(const SmartPtr &sp) { m_RefCount = NULL; Assign(sp.m_RefCount); }
    virtual ~SmartPtr() { Assign( (IRefCount<T> *)NULL); }

    T* GetPtr() const { return (m_RefCount = NULL ) ? NULL : m_RefCount->GetPtr(); }

    // 배정 연산자들
    SmartPtr& operator = (const SmartPtr &sp) { Assign(sp.m_RefCount); return *this; }
    SmartPtr& operator = (T* ptr) { Assign(ptr); return *this; }

    // T접근 및 const 변환
    T* operator -> () { assert(GetPtr() != NULL); return GetPtr(); }
    operator T* () const { return GetPtr(); }

    // 기타 편의성 연산자들
    bool operator ! () { return GetPtr() == NULL; }
    bool operator == (const SmartPtr &sp) { return GetPtr() == sp.GetPtr(); }
    bool operator != (const SmartPtr &sp) { return GetPtr() != sp.GetPtr(); }
};

#endif

다음은 템플릿 사용 예
SmartPtr.cpp

#include "stdafx.h"
#include "assert.h"
#include "smartptr.h"

class CMyObject
{
   char *name;
public:
   CMyObject(char *aname) { name = aname; printf( "create %s\n", name ); }
   virtual ~CMyObject() { printf("delete %s\n", name ); }
   void print() { printf("print %s\n",name ); }
};

SmartPtr<CMyObject> f1( char *name )
{
    return SmartPtr<CMyObject>(new CMyObject(name));
}

void f2( CMyObject *o )
{
    printf( " (print from a function) ");
    o->print();
}

int main( void )
{
    SmartPtr<CMyObject> ptr1(new CMyObject("1")); // 객체 1을 생성
    SmartPtr<CMyObject> ptr2 = new CMyObject("2"); // 객체 2을 생성

    ptr1 = ptr2; //객체 1을 파괴
    ptr2 = f1("3"); // 반환값으로 쓰이는 경우
    ptr2 = NULL; // 객체 3을 파괴
    f2(ptr1);

    // 잘못된 용례
    //  CMyObject o1;
    // ptr1 = &o1; // o1은 스택에 있으므로 이렇게 하면 안된다.
   
    // CMyObject *o2 = new CMyObject;
    // ptr1 = o2;
    // ptr2 = o2; // CMyObject가 IRefCount를 구현하지 않는 한 이렇게 하면 안된다.
    //     대신 ptr1 = ptr2를 사용할 것, 그것이 항상 안전하다.

    // int에 대해서도 SmartPtr을 사용할수 있다.
    SmartPtr<int> a(new int);
    SmartPtr<int> b(new int);

    *a = 5;
    *b = 6;

    // 명시적으로 파괴하지 않아도 메모리가 새지 않는다.
    return 0;
}

(펌) : http://blog.naver.com/twofree?Redirect=Log&logNo=21484155

Posted by gsi
:

단위 전략 부분의 디자인 패턴 내용을 보고 있다.

template 을 사용해서 다중 상속과 비슷한 구조를 취하기도 하고 메모리 생성 부분을 struct, class 형태로 따로 빼서 관리도 되는거 같다.

예제 1 :

class Ca
{
public:
 Ca() { value = 100; }
 virtual ~Ca() {}

 int value;
protected:
private:
};

template< class T>
class Cb
{
public:
 Cb() {}
 virtual ~Cb() {}

 T b;
protected:
private:
};

template< class T>
class Cc
{
public:
 Cc() {}
 virtual ~Cc() {}

 T c;
protected:
private:
};

template
<
 class T,
 template <class> class CheckingPolicy,
 template <class> class ThreadingModel
>
class SmartPtr
{
public:
 SmartPtr() {}
 ~SmartPtr() {}

public:
 T a;
 CheckingPolicy<T> b;
 ThreadingModel<T> c;
};

typedef SmartPtr<Ca, Cb, Cc> WidgetPtr;

위의 내용에서 보면 typedef를 사용해서 WidgetPtr을 하나 만들고 있다.
여기에 들어가는 내용은 Ca, Cb, Cc 가 있으며,
Cb, CC는 Ca를 포함할 수 있기 때문에 template로 선언되어 있는게 조건인듯 하다.

위와 같이 선언한 후에 아래와 같이 선언해서 사용하게 된다.

TestPtr< OpNewCreator > b;

이렇게 되면 b의 내용을 보면 SmartPtr의 클래스 내부에 b, c가 존재 하는데
이것은 T라는 템플릿 즉, Ca를 가지게 되며, 다른 동작들을 관리할 수 있을거 같다.

예제 2 :

class CTest
{
public:
 CTest() { value = 20; }
 ~CTest() {}

public:
 int value;
};

template <class T>
struct OpNewCreator
{
 static T* Create()
 {
  return new T;
 }
};

template < template <class T> class CreationPolicy>
class TestPtr : public CreationPolicy<CTest>
{
public:
 TestPtr()
 {
  ptr = CreationPolicy<CTest>().Create();
 }
 ~TestPtr()
 {
 }

public:
 CTest* ptr;
};

OpNewCreator 라는 struct를 사용하면서 new를 처리해 준다.
이 곳에서 몇개의 다른 처리를 해서 넘겨 주는 형태를 취해도 될것 같다.

상속 형태로 해서 아래와 같은 코드로 작성 하면,
template < template <class T> class CreationPolicy>
class TestPtr : public CreationPolicy<CTest>
...
이렇게 하고 나서

ptr = CreationPolicy<CTest>().Create();
이런 식으로 생성할 수 있다. 이 코드 참 멋진듯 하다. ^^

생성해서 처리 하는 방법은 아래와 같습니다.

 TestPtr< OpNewCreator > b;
 b.ptr->value = 30;
 printf("%d\n", b.ptr->value);
 TestPtr< OpNewCreator > c;
 b.ptr->value = 50;
 printf("%d\n", b.ptr->value);

아뭍턴.. 템플릿을 구현하는 방법이 복잡하긴 하지만,
제대로 사용하면 정말로 많은 기능을 구사할 수 있다.
Posted by gsi
:

객체 지향 설계에서 기존의 것과는 독립된 새로운 것을 추가, 확장시키기 위한 가장 좋은 방법 중 하나가 클래스 상속(InHeritance)을 이용하는 것이다.

객체지향 설게에서 클래스 상속은 크게 두가지 목적을 가지는데,

하나는 상위 클래스가 여러 하위 클래스들의 공통된 데이터를 추출해서 관리하도록 만드는 것이고,
다른 하나는 상위 클래스는 전반적인 자료형을 대표 하면서 외부에 공통된 인터페이스를 제공하고, 하위 클래스들은 각기 다른 구현 내용을 가지도록 만들어 주기 위한 것이다.
Posted by gsi
:

State Pattern

C++ 2008. 1. 22. 09:21 |

State Pattern

사용자 삽입 이미지
< State 패턴예>


GamePlayer 클래스와 GameLevel 및 그 하위 클래스들은 모두 동일한 인터페이스를 가지고 있는데, 이는 GamePlayer 객체에 각기 다른 유형의 공격 요청이 주어졌을 때 이에 대한 처리를 GameLevel 및 그 하위 클래스에게 위임시키기 위한 것이다.
이때 GamePlayer 객체가 공격 요청을 위임시키기 위한 방법으로는 내부적으로 관리하고 있는 GameLevel 포인터 객체를 통해 다형성(Polymorphism)을 적용시키는 것이다.

추가된 상태를 포함해서 객체의 상태 변화 시 기존 소스코드 변경없이 행위 수행 변경이 가능하도록 객체 상태 정보를 클래스 상속 구조로 정의해서 사용하는 방식을 State 패턴이라고 한다.

Posted by gsi
:

Observer Pattern - Simple

C++ 2008. 1. 21. 12:25 |


Observer Pattern을 공부중..

사용자 삽입 이미지

<Observer 패턴예>


데이터와 뷰가 분리 되어 있을때 하나의 데이터를 두개 이상의 뷰에 의존적일 경우에
이 패턴을 사용하면 되는거 같아요.
즉, 데이터를 두개의 뷰에 업데이트가 가능하며, 하나의 뷰에서 데이터가 수정된 후에
다른 뷰에도 업데이트가 가능하게 됩니다.

Posted by gsi
:

#include <iostream>

 

using namespace std;

 

typedef void(*F)(int);

 

class QSpinBox

{

       int data;

      F handler;   // call back 함수 이게 포인트. 값이 변경되면 이 함수를 통해서 콜백을 한다.

public:

       QSPinBox(F f = 0 ) : handler(f) { }

       void SetValue(int n)

       {

             data = n;     // data가 변경되었다

             valueChanged(data);

       }

       void up() { ++data; valueChanged(data);   }

       void Down() { --data; valueChanged(data); }

 

private:

       // Spin은 내부 상태가 바뀔때마다 valueChanged가 호출되는데 여기서 외부로 알려지게 된다 - Signal 이라고 부른다.

       void valueChanged(int n)

       { // 여기서 callback handler를 관리하자

             if(handler != 0)

                    handler(n);

       }

 

 

};

 

int main()

{

       QSpinBox s;

       s.SetValue(100);

       s.Up();

}

 

// SpinBox 의 상태가 변경되면 외부에 알려준다 -> callback


(펌) - http://blog.naver.com/arcyze?Redirect=Log&logNo=60041494408

Posted by gsi
:

소스 코드 :


Http를 통해서 해당 파일을 다운로드 받는 클래스 입니다.

// 접속
if (HttpOpenURL ("http://localhost/Azitro.cab")) {
    OutputDebugString ("HTTP open error.\n");
    ... 기타 작업 ....
    PostQuitMessage (0);
    return;
}

// 다운로드
if (PushDownloadObj (szFileName, NULL, NULL, 0, 0) == false) {
   ... 기타 작업 ...
   PostQuitMessage (0);
   return;
}

이후에 다운로드 진행사항이 보여지는 다이얼로그를 표시 하고 실제 파일을 다운로드 받고 cab 파일을 풀어서 설치 하는 과정까지 짝 있는데요 아무래도 좀더 파악하고 올려야 할듯 합니다. 제대로 데모를 하나 만들어서 ^^
필요하신분은 요청해 주세요 ^^.

Posted by gsi
:

윈도우 찾아서 종료 시키기

인스톨 프로그램과 비슷한 경우를 보면 해당 실행파일을 업데이트 할 경우가 생기게 되는데 이때 실행 파일을 종료 하고 새로운 파일을 추가한 후에 다시 실행시켜야 하는 경우가 발생 한다.

그래서 화면에 떠 있는 응용 프로그램의 타이틀이나 클래스를 검색 해서 프로세스 아이디를 얻은 다음에 프로세스를 종료 시켜야 한다.

프로그램을 실행하고 Spy++로 보게 되면 아래와 같이 보이게 됩니다.

사용자 삽입 이미지




여기서 나오는 "TestRemoteClose" 와 "#32770" 두개를 접근해서 프로세스를 처리할 수 있습니다.

아래의 함수는 os에서 현재 돌아가고 있는 각종 윈도우를 순회 하면서 내가 원하는 윈도우를 찾아 주는 코드 입니다.

BOOL CALLBACK SearchWindowProc (HWND hWnd, LPARAM lParam)
{
 char szClassName[1024]={0,}, szTitle[1024]={0,};
 char *pTitle = "TestRemoteClose", *pTitle2 = "TestRemoteClose";
 char *pDest = NULL, *pDest2 = NULL;

 GetClassName (hWnd, szClassName, sizeof(szClassName));
 GetWindowText (hWnd, szTitle, sizeof(szTitle));

#ifdef _DEBUG
 char szBuf[2048];
 wsprintf (szBuf, "Title: [%s],\tClass: [%s]\n", szTitle, szClassName);
 OutputDebugString (szBuf);
#endif

 pDest = strstr (szTitle, pTitle);
 pDest2 = strstr (szTitle, pTitle2);

 // Title 의 값에서 pTitle, pTitle2의 값을 검사해서 NULL인지를 검사한다.
 // 즉, NULL 이 아니면 해당 윈도우라고 판단한다.
 if (pDest != NULL || pDest2 != NULL) {

  //if (!strcmp (szClassName, "IEFrame")) // 웹일 경우 IEFrame로 되어 있다.
  {

   if (bIsMsgBox == false) {
    bIsMsgBox = true;
    MessageBox (NULL, "정상적인 설치를 위하여 잠시 종료합니다.", "설치 정보", MB_ICONINFORMATION);
   }

   DWORD dwProcessId = 0;
   GetWindowThreadProcessId (hWnd, &dwProcessId);

   if (dwProcessId)
    UserTerminateProcessId (dwProcessId);
  }
 }

 return TRUE;
}

// 메인쪽에서 아래 함수를 호출하면서 순회 하게 된다.
EnumWindows (SearchWindowProc, NULL);

더 자세한 내용이나 수정해야될 부분이 있다면 코멘트 부탁 드립니다.

Posted by gsi
:

어플리케이션이 실행될 OS의 타입과 빌드 번호 등을 알아 오는 데모

사용자 삽입 이미지

OSVersionChk 소스 코드 :

Posted by gsi
:

상태바를 추가 해서 툴을 적용할때 각종 정보들을 출력할 수 있습니다.

1. 리소스 기호를 추가 합니다.

사용자 삽입 이미지
2. String Table 에 추가 합니다.
사용자 삽입 이미지

3. 해당 내용을 추가 합니다.

static UINT indicators[] =
{
// ID_SEPARATOR,           // 상태 줄 표시기
 ID_INDICATOR_INFO0,      // 추가한 상태바
 ID_INDICATOR_INFO1,      // 추가한 상태바
 ID_INDICATOR_INFO2,      // 추가한 상태바
 ID_INDICATOR_INFO3,      // 추가한 상태바
 ID_INDICATOR_CAPS,
 ID_INDICATOR_NUM,
 ID_INDICATOR_SCRL,
};

4. 메인 프레임 사이즈 조정시 상태바의 크기도 조절 되도록 한다.

void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
 CFrameWnd::OnSize(nType, cx, cy);

 if(m_wndStatusBar.m_hWnd != NULL)
 {
  int width = cy - 90;

  m_wndStatusBar.SetPaneInfo(0, ID_INDICATOR_INFO0, SBPS_NORMAL|SBPS_STRETCH, width/4);
  m_wndStatusBar.SetPaneInfo(1, ID_INDICATOR_INFO1, SBPS_NORMAL|SBPS_STRETCH, width/4);
  m_wndStatusBar.SetPaneInfo(2, ID_INDICATOR_INFO2, SBPS_NORMAL|SBPS_STRETCH, width/4);
  m_wndStatusBar.SetPaneInfo(3, ID_INDICATOR_INFO3, SBPS_NORMAL|SBPS_STRETCH, width/4);
  m_wndStatusBar.SetPaneInfo(4, ID_INDICATOR_INFO3, SBPS_NORMAL|SBPS_STRETCH, 30);
  m_wndStatusBar.SetPaneInfo(5, ID_INDICATOR_INFO3, SBPS_NORMAL|SBPS_STRETCH, 30);
  m_wndStatusBar.SetPaneInfo(6, ID_INDICATOR_INFO3, SBPS_NORMAL|SBPS_STRETCH, 30);
 }
}

5. 문자열을 바꿀때는 SetPaneText()를 사용한다.

m_wndStatusBar.SetPaneText(0, str0);  // 0은 인덱스, str0은 문자열

Posted by gsi
:

13가지 주의 사항: Visual C++ .NET 프로그램을 Visual Studio 2005로 이식하기 전에 알아야 할 13가지 내용


Stanley B. Lippman

Microsoft Corporation


적용 대상:

   Microsoft Visual C++ .NET

   Microsoft Visual C++ 2005

   Microsoft Visual Studio 2005

   Microsoft Visual Studio .NET


요약: 개발자가 응용 프로그램을 Microsoft Visual Studio 2005로 이식할 때 주의해야 할 내용에 대해 Stan Lippman이 소개합니다.



Posted by gsi
:

[MFC] 폴더 경로 얻기

C++ 2007. 12. 12. 14:23 |

사용자 삽입 이미지

 ITEMIDLIST      *pidlBrowse;
 char                  pszPathname[MAX_PATH];

 BROWSEINFO     BrInfo;

 BrInfo.hwndOwner = GetSafeHwnd();
 BrInfo.pidlRoot = NULL;

 memset( &BrInfo, 0, sizeof(BrInfo) );
 BrInfo.pszDisplayName = pszPathname;
 BrInfo.lpszTitle = "선택하고자 하는 폴더를 선택해 주십시오.";
 BrInfo.ulFlags = BIF_RETURNONLYFSDIRS;

 // 다이얼로그 띄우기
 pidlBrowse = SHBrowseForFolder(&BrInfo); 

 if( pidlBrowse != NULL)
 {
  // 패스를 얻어옴
  BOOL bSuccess = ::SHGetPathFromIDList(pidlBrowse, pszPathname);

  if ( bSuccess )
  {
   m_szSafedefaultPath = pszPathname;   //<-- 여기서 값을 입력
   UpdateData(FALSE);
  }
  else
  {
   MessageBox("잘못된 폴더명입니다.", "lol", MB_OKCANCEL|MB_ICONASTERISK );
  }
 }

Posted by gsi
:

 //저장파일의 파일명을 찾아낸다.
 //확장자 분리 모듈
 TCHAR szDir[_MAX_DIR];
 TCHAR szDrive[_MAX_DRIVE];
 TCHAR szFileName[200] ;
 TCHAR szFileExt[20] ;
 _tsplitpath(saveFile, szDrive, szDir,szFileName, szFileExt);

 // etc
 //aze 파일 확장자를 소문자로 바꾸는 코드
 CString fileName;
 CString fileExt;
 fileExt.Format("%s", szFileExt);
 fileExt.MakeLower();
 fileName.Format("%s%s%s%s", szDrive, szDir, szFileName, fileExt);

szFile = strrchr( *pFullPath, '\\' ) + 1;
이건 뒤에 있는 파일이름+확장자 를 뽑아 주는 함수.
Posted by gsi
:

Dll 프로젝트를 하나 만들고 xml을 읽는 테스트를 진행해 봤다.
아래의 xml 파일을 읽는 테스트...

<?xml version="1.0" encoding="euc-kr" ?>

<Symbols>
  <Scanorders>
    <order Name="default">
      <!--false이면 지그재그-->
      <lineartype>true</lineartype>
      <!--두개씩 쌍을 이룬다.
          처음 두개는 진행방향 from > to 이고,
          뒤에 두개는 흐름방향 이다.-->
      <left>-1</left>
      <right>-1</right>
      <top>-1</top>
      <bottom>-1</bottom>
    </order>
  </Scanorders>
 
  <!--DefaultSymbol은 true이면 line이고, false이면 rectangle 이다.-->
  <Symbol Name="none" Uid="0" Type="line" DefaultSymbol="true">
    <HorizontalPixels>1</HorizontalPixels>
    <VerticalPixels>11</VerticalPixels>
    <SymbolWidth>12</SymbolWidth>
    <SymbolHeight>13</SymbolHeight>
    <ScanOrder>14</ScanOrder>
    <TotalPixels>15</TotalPixels>
    <TotalWidth>16</TotalWidth>
    <TotalHeight>17</TotalHeight>
    <Length>18</Length>
    <Color>
      <r>128</r>
      <g>129</g>
      <b>130</b>
    </Color>
  </Symbol>
  <Symbol Name="none" Uid="0" Type="line" DefaultSymbol="true">
<!--    <HorizontalPixels>1</HorizontalPixels> -->
    <VerticalPixels>2</VerticalPixels>
    <SymbolWidth>2</SymbolWidth>
    <SymbolHeight>2</SymbolHeight>
    <ScanOrder>2</ScanOrder>
    <TotalPixels>2</TotalPixels>
    <TotalWidth>2</TotalWidth>
    <TotalHeight>2</TotalHeight>
    <Length>2</Length>
    <Color>
      <r>80</r>
      <g>81</g>
      <b>82</b>
    </Color>
  </Symbol>
  <Symbol Name="none" Uid="0" Type="line" DefaultSymbol="true">
    <HorizontalPixels>3</HorizontalPixels>
    <VerticalPixels>3</VerticalPixels>
    <SymbolWidth>3</SymbolWidth>
    <SymbolHeight>3</SymbolHeight>
    <ScanOrder>3</ScanOrder>
    <TotalPixels>3</TotalPixels>
    <TotalWidth>3</TotalWidth>
    <TotalHeight>3</TotalHeight>
    <Length>3</Length>
    <Color>
      <r>150</r>
      <g>151</g>
      <b>152</b>
    </Color>
  </Symbol>
</Symbols>



C++ 에서 테스트할때..

    TRACE("--- xml start ---\n");
    if(m_TestXmlWrap2.Load("d:\\symbol.xml")) {
     // 정상적으로 읽었다면 여기로..
     
     HRESULT hr;
     MSXML2::IXMLDOMDocument2Ptr  pDoc;
     MSXML2::IXMLDOMNodeListPtr  pNodeList;
     MSXML2::IXMLDOMNodePtr   pNodeSub;
     MSXML2::IXMLDOMNodeListPtr  pNodeSubList;
     MSXML2::IXMLDOMNodePtr   pNodeSubSub;
     MSXML2::IXMLDOMNodePtr   pNodeSubSubSub;
     MSXML2::IXMLDOMElementPtr  pNodeSubElement;
     BSTR bszNodeValue;

     TRACE("--- xml start ---\n");
     if(m_TestXmlWrap2.GetDoc()) {
      pNodeList = m_TestXmlWrap2.GetDoc()->selectNodes(".//Symbol");
      for(int i = 0; i < pNodeList->length; i++) {
       pNodeSub = pNodeList->Getitem(i);

       // 같은 노드가 하나 이상은 존재 하지 않는다고 가정한다.
       pNodeSubSub = pNodeSub->selectSingleNode(".//HorizontalPixels");
       string value = "none";
       if(pNodeSubSub)
        value = (LPCTSTR)pNodeSubSub->Gettext();
       TRACE1("Symbol/HorizontalPixels=%s\n", value.c_str());
      }
     }
     TRACE("--- xml end ---\n");

     TRACE("--- xml start ---\n");
     if(m_TestXmlWrap2.GetDoc()) {
      pNodeList = m_TestXmlWrap2.GetDoc()->selectNodes(".//Symbol");
      for(int i = 0; i < pNodeList->length; i++) {
       pNodeSub = pNodeList->Getitem(i);

       pNodeSubList = pNodeSub->selectNodes(".//Color");
       for(int i = 0; i < pNodeSubList->length; i++) {
        pNodeSubSub = pNodeSubList->Getitem(i);

        string value;
        // 같은 노드가 하나 이상은 존재 하지 않는다고 가정한다.
        pNodeSubSubSub = pNodeSubSub->selectSingleNode(".//r");
        value = "none";
        if(pNodeSubSubSub)
         value = (LPCTSTR)pNodeSubSubSub->Gettext();
        TRACE1("Symbol/Color/r=%s\n", value.c_str());

        // 같은 노드가 하나 이상은 존재 하지 않는다고 가정한다.
        pNodeSubSubSub = pNodeSubSub->selectSingleNode(".//g");
        value = "none";
        if(pNodeSubSubSub)
         value = (LPCTSTR)pNodeSubSubSub->Gettext();
        TRACE1("Symbol/Color/g=%s\n", value.c_str());

        // 같은 노드가 하나 이상은 존재 하지 않는다고 가정한다.
        pNodeSubSubSub = pNodeSubSub->selectSingleNode(".//b");
        value = "none";
        if(pNodeSubSubSub)
         value = (LPCTSTR)pNodeSubSubSub->Gettext();
        TRACE1("Symbol/Color/b=%s\n", value.c_str());
       }
      }
     }
     TRACE("--- xml end ---\n");

      // 저장
      m_TestXmlWrap2.Save(_T("d:\\save_test.xml"));
    }

Dll 코드 :


Posted by gsi
:

XML 처리방법

C++ 2007. 12. 6. 12:53 |

XML 데이터 처리 하는 방법 정리.
파일 읽기, http 정보 읽기, 노드 정보 출력, 노드 검색 정보 출력


1. XML 파일 읽어서 출력하기

MSXML2::IXMLDOMDocument2Ptr pDoc; // XML Document 선언
pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument)); // 인스턴스 생성

HRESULT hr = pDoc->load((_variant_t)".\\test.xml");
if(hr == 0) {
 AfxMessageBox("로딩 에러");
 return;
}
AfxMessageBox(pDoc->xml);

2. http을 통한 XML 파일 읽어서 출력하기

MSXML2::IXMLDOMDocument2Ptr pDoc; // XML Document 선언
pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument)); // 인스턴스 생성

DWORD startTick = GetTickCount();
pDoc->put_async(VARIANT_FALSE);
HRESULT hr = pDoc->load((_variant_t)"http://localhost/TestXml/test2.xml");
if(hr == 0) {
 AfxMessageBox("로딩 에러");
 return;
}
AfxMessageBox(pDoc->xml);

3. XML 데이터의 첫번째 해당 노드값 읽어서 출력하기

MSXML2::IXMLDOMDocument2Ptr pDoc; // XML Document 선언
pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument)); // 인스턴스 생성

HRESULT hr = pDoc->load((_variant_t)".\\test.xml");
if(hr == 0) {
 AfxMessageBox("로딩 에러");
 return;
}

MSXML2::IXMLDOMNodePtr pNode;
pNode = pDoc->selectSingleNode(L"//name");

CString outString;
outString.Format("[검색결과] 노드명:%s, 노드값:%s\r\n", (LPCTSTR)pNode->GetnodeName(), (LPCTSTR)pNode->Gettext());
AfxMessageBox(outString);

4. XML 데이터의 해당 노드값 모두 읽어서 출력하기

MSXML2::IXMLDOMDocument2Ptr pDoc; // XML Document 선언
pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument)); // 인스턴스 생성

HRESULT hr = pDoc->load((_variant_t)".\\test.xml");
if(hr == 0) {
 AfxMessageBox("로딩 에러");
 return;
}

MSXML2::IXMLDOMNodeListPtr pNodeList;
pNodeList = pDoc->selectNodes(L"//name");

CString outTotalString;
for(int i = 0; i < pNodeList->length; i++) {
 CString outString;
 outString.Format("[검색결과] 노드명:%s, 노드값:%s\r\n",
  (LPCTSTR)pNodeList->Getitem(i)->GetnodeName(),
  (LPCTSTR)pNodeList->Getitem(i)->Gettext());
 outTotalString.Append(outString);
}
AfxMessageBox(outTotalString);

나머지 노드값 변경하는 방법,
속성값 읽어 오기 및 변경 방법 등을 정리 해야 함.

테스트 소스 :

Posted by gsi
: