'전체 글'에 해당되는 글 171건

  1. 2007.08.13 [강좌] WTL로 프로그래밍하기#2 – 위저드로 생성되는 코드
  2. 2007.08.12 트레이 영역 구하는 함수 - GetTrayWndRect
  3. 2007.08.11 윈도우 탐색기(shell) 재시작시 Tray에 등록하기 1
  4. 2007.08.10 [TinyXML] 사용해보기 - xml로 만들기 3
  5. 2007.08.10 [TinyXML] 사용해보기 - 읽어오기 1

[강좌] WTL로 프로그래밍하기#2 – 위저드로 생성되는 코드

개발 2007. 8. 13. 15:24

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

WTL로 프로그래밍하기#2 – 위저드로 생성되는 코드

 

저자 : hanburn

날짜 : 2007.08.13

환경 : WTL7.5, VS-2003

 

 

지난시간에는 WTL에 대해서 간략하게 알아보고 설치하고 환경 설정하는 것 까지 알아보았다. 이제 WTL로 간단한 프로젝트를 만들어 보자. VS를 열면 WTL application wizard가 보일 것이다. 이것을 선택하여 시작하도록 하자.

사용자 삽입 이미지


그런 다음에는 너무나도 익숙한 화면이다. SDI, MDI, Dialog base 등 초기의 프로그램 형태를 선택할 수 있는 창이 나온다. MFC wizard와 상당히 유사한 모습이다. 아래 그림처럼 Dialog Base를 선택하고 Generate .CPP Files를 체크한 뒤에 Finish를 선택하면 된다.


사용자 삽입 이미지

이렇게 하면 위저드가 기본 골격 코드를 생성하는데, 생성된 코드를 한번 살펴 보면서 시작하자.

먼저 프로젝트이름.cpp 파일을 살펴보면 아래와 같은 코드가 보일 것이다.

 

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)

{

        HRESULT hRes = ::CoInitialize(NULL);

        ...

        hRes = _Module.Init(NULL, hInstance);

        ATLASSERT(SUCCEEDED(hRes));

 

        int nRet = Run(lpstrCmdLine, nCmdShow);

 

        _Module.Term();

        ::CoUninitialize();

 

        return nRet;

}


우리가 잘 알고있는 WinMain 함수이다. 여기서 살펴볼 것은 _Module 이라 전역객체 인데, MFC theApp 와 비슷한 놈이다. MFC에서는 CWinApp를 상속받아서 각 프로그램마다 한 개씩 있던 것을 보았을 것이다. WTL에서는
CAppModule클래스의 전역객체인데, 쉽게 생각하면 전체 프로그램의 관리자 역할로 보면 것이다. _Module.Init()/Term() 사이에 있는 Run() 이라는 함수가 윈도우 시스템의 메시지를 가지고 와서 배분을 해주는(DispatchMessage) 역할을 하는 부분이다. 전역함수인 Run 함수에 대해서 조금 자세히 알아보자

 

int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)

{

        CMessageLoop theLoop;

        _Module.AddMessageLoop(&theLoop);

 

        CMainDlg dlgMain;

        if(dlgMain.Create(NULL) == NULL)

        {

               ATLTRACE(_T("Main dialog creation failed!\n"));

               return 0;

        }

        dlgMain.ShowWindow(nCmdShow);

 

        int nRet = theLoop.Run();

        _Module.RemoveMessageLoop();

        return nRet;

}

 

웬지 MFC에서 InitInstance 부분과 유사한 느낌을 받을 것이다. 메인 다이얼로그를 생성하고 메시지루프를 처리하고..  WTL MFC보다 역할의 구분을 클래스로 잘 구분을 해놓은 느낌이다. Design Pattern Explained에서 말하는 역할 중심의 설계랄까? ^^

Run함수에서 CMessageLoop 객체를 만들고 _Module에 추가를 해주어서 메시지 펌핑을 받도록 처리하고 있다. CMessageLoop run함수에 우리가 익숙하게 보는 다음과 같은 코드가 들어있다.

 

bRet = ::GetMessage(&m_msg, NULL, 0, 0);

if(!PreTranslateMessage(&m_msg))

{

::TranslateMessage(&m_msg);

::DispatchMessage(&m_msg);

}

 

이렇게 함으로써 Dialog의 기본 골격 코드를 살펴 보았다. 그리고 WTL의 위자드에서 Dialog를 선택하고 DoModal을 체크하게 되면 더 간단하게 아래처럼 Dialog DoModal을 호출해 준다.

 

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)

{

        HRESULT hRes = ::CoInitialize(NULL);

        ...

        hRes = _Module.Init(NULL, hInstance);

 

        int nRet = 0;

        {

               CMainDlg dlgMain;

               nRet = dlgMain.DoModal();

        }

 

        _Module.Term();

        ::CoUninitialize();

 

        return nRet;

}

 

보통 WTL으로 프로그래밍을 할 때, 기본적으로 생성되는 Dialog를 사용하지 않을 때는 첫번째 처럼 기본 틀을 생성하고, Dialog대신 내가 만든 윈도우를 Create 하고 Show를 해주게 되어서, 보통은 Domodal을 체크 않하고 많이 사용한다. (이것은 개인적인 취향이다. )

 

다음으로는 MainDlg.h 를 살펴보자. 실제적인 Dialog에 대핸 메시지 처리 및 기타 주요한 부분을 담당하는 부분이다.

 

class CMainDlg :       public CDialogImpl<CMainDlg>,

public CUpdateUI<CMainDlg>,

                       public CMessageFilter,

public CIdleHandler

{

public:

        enum { IDD = IDD_MAINDLG };

 

        virtual BOOL PreTranslateMessage(MSG* pMsg);

        virtual BOOL OnIdle();

 

        BEGIN_UPDATE_UI_MAP(CMainDlg)

        END_UPDATE_UI_MAP()

 

        BEGIN_MSG_MAP(CMainDlg)

               MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)

               COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)

               COMMAND_ID_HANDLER(IDOK, OnOK)

               COMMAND_ID_HANDLER(IDCANCEL, OnCancel)

        END_MSG_MAP()

 

        LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);

        LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);

        LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);

        LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);

 

        void CloseDialog(int nVal);

};

 

여기서 조금 낯설 수가 있다. 평소에 잘 사용 안하던 다중상속을 사용한 것이다. 전형적인 ATL 스타일인 것이다. 여러가지 template class 로부터 상속을 받고 있는데, 이것들은 다음 시간에 알아보도록 하겠습니다.




:

트레이 영역 구하는 함수 - GetTrayWndRect

개발 2007. 8. 12. 00:11

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

윈도우의 트레이 영역을 구하는 함수이다.
윈도우가 트레이로 최소화 될때 DrawAnimatedRects(m_hWnd, IDANI_CAPTION, rcFrom, rcTo); 함수를 이용하면 최소화 되는 것처럼 트레이 영역으로 이동하는 것을 볼 수 있다.



void GetTrayWndRect(RECT *pRect)
{
    HWND hwndTaskBar=::FindWindow(_T("Shell_TrayWnd"), NULL);
    if (hwndTaskBar){
        HWND hwndTray=::FindWindowEx(hwndTaskBar, NULL, _T("TrayNotifyWnd"), NULL);
        if (hwndTray)
            ::GetWindowRect(hwndTray, pRect);
        else
       {    //tray부분을 못찾으면 task바의 구석탱이를 그렇다고 믿게 하자.
            ::GetWindowRect(hwndTaskBar, pRect);
            pRect->left=pRect->right-20;
            pRect->top=pRect->bottom-20;
        }
    }
    else
    {   //task바를 못찾으면 그냥 화면 하단부
        int nWidth = GetSystemMetrics(SM_CXSCREEN);
        int nHeight = GetSystemMetrics(SM_CYSCREEN);
        SetRect(pRect, nWidth-40, nHeight-20, nWidth, nHeight);
    }
}


:

윈도우 탐색기(shell) 재시작시 Tray에 등록하기

개발 2007. 8. 11. 23:58

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

윈도우 탐색기가 가끔가다가 죽는 경우가 있는데, 보통은 자동으로 다시 실행이 된다.
자동으로 실행이 않되면 작업관리자를 실행시켜서 새작업 실행으로 explorer.exe 를 실행시키면 된다.
그런데 윈도우 탐색기가 다시 실행되면 Tray 영역에 있던 아이콘이 사라지게 된다. 그러나 MSN 같은 몇몇 프로그램은 Trya 에 아이콘이 있는데, 그것을 다음과 같이 하면 된다.


// 메시지 등록
UINT g_uShellRestart;
g_uShellRestart = RegisterWindowsMessage(__Text(“TaskbarCreated”));

// Message Map 에서
ON_REGISTERED_MESSAGE(g_uShellRestart, OnTrayShow)

// 메시지 핸들러
LRESULT CMyDlg::OnTrayShow(WPARAM wParam, LPARAM lParam)
{
    // TrayIcon을 다시 보여줍니다. ShowTray는 Tray를 보여주는 함수입니다.
    m_Tray.ShowTray();
}


위에서 보면 알겠지만, explorer가 다시 실행될때 TaskbarCreated 라는 메세지가 발생이 된다.
이것을 잡아서 처리하면 되는 것이다.


:

[TinyXML] 사용해보기 - xml로 만들기

개발 2007. 8. 10. 17:02

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

TimyXML 사용해보기 - xml로 만들기


저자 : hanburn
날짜 : 2007.08.10
환경 : VS-2003, TinyXML 2.5.3

앞에서는 xml 파일이나 xml문자열에서 파싱을 해서 원하는 정보를 뽑아오는 것을 해보았다.
그러면 이제는 반대로 설정이나 원하는 정보를 xml 형식으로 만들어 보자.
앞에서 사용한 xml을 만들어 보도록 하자

<?xml version="1.0" ?>
<MyApp>
    <!-- Settings for MyApp -->
    <Messages>
        <Welcome>Welcome to MyApp</Welcome>
        <Farewell>Thank you for using MyApp</Farewell>
    </Messages>
    <Windows>
        <Window name="MainFrame" x="5" y="15" w="400" h="250" />
    </Windows>
    <Connection ip="192.168.0.1" timeout="123.456000" />
</MyApp>


일단 xml 의 형식선언부터 시작해 보자..

TiXmlDocument doc; 
TiXmlElement* msg;
TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" ); 
doc.LinkEndChild( decl );



이렇게 하면 <?xml version="1.0" ?> 이 생성된다.
다음으로는, 서브 노드를 추가해보자.

TiXmlElement * root = new TiXmlElement( "MyApp" ); 
doc.LinkEndChild( root ); 


간단하다. 그리고 new로 생성한 TiXmlElement를 해제할 필요가 없다. 내부에서 자동으로 삭제를 해주기 때문이다. (편리하군~ ^^)
그런 다음 주석문장을 추가해 보자.

TiXmlComment * comment = new TiXmlComment();
comment->SetValue(" Settings for MyApp " ); 
root->LinkEndChild( comment ); 


주석은 TiXmlComment 클래스를 사용하면 된다. 편리하군..
다음으로는  Message 서브노드와 하위 노드및 데이터를 추가해보자

TiXmlElement * msgs = new TiXmlElement( "Messages" ); 
root->LinkEndChild( msgs ); 

msg = new TiXmlElement( "Welcome" ); 
msg->LinkEndChild( new TiXmlText( "Welcome to MyApp" )); 
msgs->LinkEndChild( msg ); 

msg = new TiXmlElement( "Farewell" ); 
msg->LinkEndChild( new TiXmlText( "Thank you for using MyApp" )); 
msgs->LinkEndChild( msg ); 



역시 쉽니다. 다음에는 노드를 추가하고 Attribute를 설정해보자
레벨을 맞추기 위해서 root의 하위로 추가 한것을 주의 깊게 봐야 한다.

TiXmlElement * windows = new TiXmlElement( "Windows" ); 
root->LinkEndChild( windows ); 

TiXmlElement * window;
window = new TiXmlElement( "Window" ); 
windows->LinkEndChild( window ); 
window->SetAttribute("name", "MainFrame");
window->SetAttribute("x", 5);
window->SetAttribute("y", 15);
window->SetAttribute("w", 400);
window->SetAttribute("h", 250);



다음은 마지막으로 Double 값 (소수점 값) 을 설정하는 예를 보자

TiXmlElement * cxn = new TiXmlElement( "Connection" ); 
root->LinkEndChild( cxn ); 
cxn->SetAttribute("ip", "192.168.0.1");
cxn->SetDoubleAttribute("timeout", 123.456); // floating point attrib



이렇게 하면 우리가 원하는 xml이 doc에 만들어 졌다. 이것을 파일로 저장할 수도 있고 xml 문자열로 만들수도 있다. 방법은 아래를..

// 파일로 저장
doc.SaveFile("text.xml");

//문자열로..
TiXmlPrinter printer;
printer.SetStreamPrinting();
Doc.Accept( &printer );
char* pAA = printer.CStr();                    // char* 를 반환한다.
std::string str = printer.Str();                  // std::string으로 반환한다.


이로써 간단하게 TinyXML의 사용법을 마칠까 한다.



:

[TinyXML] 사용해보기 - 읽어오기

개발 2007. 8. 10. 14:57

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.


TimyXML 사용해보기 - xml에서 읽어오기


저자 : hanburn
날짜 : 2007.08.10
환경 : VS-2003, TinyXML 2.5.3


XML에 대해서는 이미 알고 있다고 가정합니다.
(모르면 공부하고 다시 오세요 ^^)

일단 XML을 파일에서 읽을수도 있고 문자열로 읽을 수도 있다.
아래 예에서 사용할 xml 파일은 다음과 같다.

<?xml version="1.0" ?>
<MyApp>
    <!-- Settings for MyApp -->
    <Messages>
        <Welcome>Welcome to MyApp</Welcome>
        <Farewell>Thank you for using MyApp</Farewell>
    </Messages>
    <Windows>
        <Window name="MainFrame" x="5" y="15" w="400" h="250" />
    </Windows>
    <Connection ip="192.168.0.1" timeout="123.456000" />
</MyApp>


먼저 파일에서 읽을때는,

TiXmlDocument document;
document.LoadFile(_File_Name_);


문자열로 읽을때는,

TiXmlDocument document;
document.Parse(szXML);


너무 쉽다. 그런 다음에는 원하는 값을 찾아오면 된다.
먼저 노드와 엘리먼트를 가지고 오는 방법을 알아보자.
( 노드는 자식을 가지고 있는 것이고 엘리먼트는 마지막에 있는 놈이다. )

TiXmlElement* pRoot = document.FirstChildElement("MyApp");
if( NULL == pRoot ) return FALSE;   // 해당 Element가 없으면 널이므로.. 체크해주는게 좋다.


그럼, <Welcome> 태그로 가서 데이터를 가지고 와보자.

pElement = pRoot->FirstChildElement("Message");
pElement = pElement->FirstChildElement("Welcome");
char* pAA = pElement->Value();                 // pAA 은  "Welcome" 이다.
pAA = pElement->GetText();                       // pAA 은  "Welcome to MyApp" 이다.


이번에는 다음에 windows 태그로 가서 name 속성을 읽어 와보자.

pElement = pRoot->FirstChildElement("Windows");
char* pAA = pElement->Attribute("name");   // pAA에 "MainFrame"이 들어온다.
int x;
pElement->Attribute("x", &x);                    // x 에 숫자 5가 들어온다.


그다음에는 루프를 돌면서 child 노드를 순환하는 방법이다.


pNode = pRoot->FirstChild("sub_node");
 for( pNode ; pNode ; pNode = pNode->NextSibling())
 {
  pAA = pNode->Value();  

  pElement = pNode->FirstChildElement("item");  
  pAA = pElement->GetText();
}


 




 



: