2007년 4월 24일 화요일

Elisha Cuthbert






Elisha Cuthbert






Elisha Cuthbert






Elisha Cuthbert

Hey, she's back!!!



2007년 4월 23일 월요일

MemDC를 이용한 비트맵 출력

// OnDraw(CDC* pDC) 내에서 경우

CDC MemDC;
MemDC.CreateCompatibleDC(pDC);

CBitmap bitmap;
bitmap.LoadBitmap(IDB_ME); // Bitmap 리소스
CBitmap *pOldBitmap = (CBitmap *)MemDC.SelectObject(&bitmap);

pDC->BitBlt(0, 0, 100, 100, &MemDC, 0, 0, SRCCOPY);

MemDC.SelectObject(pOldBitmap);

// End

별그리기 (CRgn)

// 다각형의 모양을 가지는 점들의 집합을 준비합니다.
// 여기는 별만 그리지만 삼각형도 똑 같습니다.
// 그리는 모양은 마음대로 바꾸세요.
CPoint points[11];

// 72' 씩 회전된 꼭지점으로 이루어진 점 생성
// 여기서 알아서 모양을 만드세요.
double Pi = 3.14159265359;

for ( int i = 0; i < 10; i += 2 )
{
// 별의 바깥쪽 꼭지점 (큰 반지름으로 만듬)
points[i].x = (long)(25*cos((double)(i*72*Pi)/360.0));
points[i].y = (long)(25*sin((double)(i*72*Pi)/360.0));

// 별의 안쪽 꼭지점 (작은 반지름으로 만듬)
points[i+1].x = (long)(10*cos((double)((i+1)*72*Pi)/360.0));
points[i+1].y = (long)(10*sin((double)((i+1)*72*Pi)/360.0));
}

// 끝점은 첫점과 같게 맞춤니다.
points[10] = points[0];

CRgn rgnStar;
rgnStar.CreatePolygonRgn(points, 11, WINDING);

// 클라이언트 영역을 가져옵니다.
CRect r;
GetClientRect(&r);

// 그림 그릴 브러시를 초기화합니다.
CBrush brush;
brush.CreateSolidBrush(RGB(0,0,0));

// 영역을 초기화 합니다.
CRgn rgn;
rgn.CreateRectRgn(0, 0, 0, 0);
rgn.CopyRgn(&rgnStar);
rgn.OffsetRgn(point.x, point.y);

// 별을 그립니다.
dc.FillRgn(&rgn, &brush);

데스크탑윈도우의 DC를 얻어서 사용하는 방법

Very simple, uhh~

CRect r;
GetClientRect(&r);
CClientDC desktopDC(GetDesktopWindow());
pDC->BitBlt(0, 0, r.Width(), r.Height(), &desktopDC, 0, 0, SRCCOPY);

2007년 4월 19일 목요일

Using DirectX with MFC (2)

DirectX는 제대로 설치되어 있다고 가정한다.

SDI로 App 를 생성하고 Document/View Architecture 를 Uncheck 한다.
기타 원하는 대로 만든다.

프로젝트가 생성이 되면 ChildView.h 및 ChildView.cpp 를 삭제한다.
DirectX 프로그래밍에서는 별도의 View가 필요가 없다.

MainFrm.h 에서

#include "ChildView.h"

를 삭제한다. 그 다음

CMainFrame 내의

CChildView m_wndView;

도 삭제한다.

CMainFrame::OnCreate() 내의

// create a view to occupy the client area of the frame
if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
{
TRACE0("Failed to create view window\n");
return -1;
}

부분을 삭제하고 대신

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;


/////////////////////////////////////////////////////////////////////
// 여기에DirectX의초기화를수행한다.
/////////////////////////////////////////////////////////////////////
HWND hDevice, hFocus;
HRESULT hr;

hDevice = GetSafeHwnd();
hFocus = GetTopLevelParent() ->GetSafeHwnd();

GetClientRect(&m_rectClient);

// Create Direct3D object
m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);

D3DDISPLAYMODE d3ddm;
m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);

// D3DPRESENT_PARAMETERS 구조체의설정
::ZeroMemory(&m_d3dpp, sizeof(m_d3dpp));
m_d3dpp.Windowed = TRUE;
m_d3dpp.BackBufferCount = 1;
m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
m_d3dpp.EnableAutoDepthStencil = TRUE;
m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
m_d3dpp.hDeviceWindow = hDevice;
m_d3dpp.BackBufferWidth = m_rectClient.Width();
m_d3dpp.BackBufferHeight = m_rectClient.Height();
m_d3dpp.BackBufferFormat = d3ddm.Format;
m_d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;

// 디바이스작성
hr = m_pD3D->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hFocus,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&m_d3dpp,
&m_pd3dDevice
);

m_pd3dDevice->SetDialogBoxMode(TRUE);
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

////////////////////////////////////////////////////////////////////
// 여기까지DirectX의초기화부분임
////////////////////////////////////////////////////////////////////

return 0;
}

와 같이 필요한 초기화를 수행한다.

CMainFrame::OnSetFocus() 함수를 삭제한다.
CMainFrame::OnCmdMsg() 함수를 삭제한다.



“stdafx.h” 에 다음 줄들을 추가한다.
그때 그때 필요한 부분을 알아서 추가해야 한다.

필요한 헤더 파일들과 링크할 라이브러리 파일들이다.

// Direct3D includes
#include
#include
#include

// DirectSound includes
#include
#include
#include

#pragma comment( lib, "dxerr.lib" )
#pragma comment( lib, "dxguid.lib" )
#if defined(DEBUG) defined(_DEBUG)
#pragma comment( lib, "d3dx9d.lib" )
#else
#pragma comment( lib, "d3dx9.lib" )
#endif
#pragma comment( lib, "d3d9.lib" )
#pragma comment( lib, "winmm.lib" )
#pragma comment( lib, "comctl32.lib" )


CMainFrame 의 헤더파일에 아래를 추가한다.

// Attributes
public:
CRect m_rectClient; // Client window size
IDirect3D9* m_pD3D; // The IDirect3D9 interface
IDirect3DDevice9* m_pd3dDevice; // D3D Device
D3DPRESENT_PARAMETERS m_d3dpp; // The present parameters.
bool m_bReady; // Is DX9 ready to render?

// Operations
public:
void Render(); // Render


Constructor에서 필요한 초기화를 수행한다.

CMainFrame::CMainFrame()
{
// 필요한초기화를수행한다.
m_pD3D = NULL;
m_pd3dDevice = NULL;
m_bReady = false;
}

ReleaseAllObject() 라는 함수를 하나 만들고 아래와 같이 추가한다.

void CMainFrame::ReleaseAllObject()
{
// DirectX가시동되었으면삭제
if ( m_pD3D != NULL )
{
if ( m_pd3dDevice != NULL)
{
m_pd3dDevice->Release();
m_pd3dDevice = NULL;
}
m_pD3D->Release();
m_pD3D = NULL;
}
}

WM_ACTIVATEAPP 의 Event handler 를 만들고 아래를 추가한다.

void CMainFrame::OnActivateApp(BOOL bActive, DWORD dwThreadID)
{
CFrameWnd::OnActivateApp(bActive, dwThreadID);

// 준비 완료
m_bReady = bActive;
}

WM_DESTROY 의 Event handler 를 만들어 주고 아래를 추가한다.

void CMainFrame::OnDestroy()
{
ReleaseAllObject();

CFrameWnd::OnDestroy();

// TODO: Add your message handler code here

}

당연히 Render() 함수도 구현해 준다.

void CMainFrame::Render()
{
m_pd3dDevice->Clear(
0,
NULL,
D3DCLEAR_TARGET D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0, 0, 0),
1.0f,
0
);

if(SUCCEEDED(m_pd3dDevice->BeginScene()))
{
m_pd3dDevice->EndScene();
}

m_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}

이제 Test 겸 다음과 같이 실행해 본다.

void CMainFrame::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CFrameWnd::OnPaint() for painting messages
Render();
}

검은 색 화면이 나오면 일단 성공한 것이다.

Using DirectX with MFC

우선 “stdafx.h”에

// Direct3D includes
#include <d3d9.h>
#include <d3dx9.h>
#include <dxerr.h>

// DirectSound includes
#include <mmsystem.h>
#include <mmreg.h>
#include <dsound.h>

#pragma comment( lib, "dxerr.lib" )
#pragma comment( lib, "dxguid.lib" )
#if defined(DEBUG) || defined(_DEBUG)
#pragma comment( lib, "d3dx9d.lib" )
#else
#pragma comment( lib, "d3dx9.lib" )
#endif
#pragma comment( lib, "d3d9.lib" )
#pragma comment( lib, "winmm.lib" )
#pragma comment( lib, "comctl32.lib" )

를 추가한다. 그때 그때 필요한 헤더파일과 라이브러리를 포함해야 한다.

그리고 XXXView.h 파일을 열고 아래 내용들을 추가한다.

CRect m_rectClient;         // Client window size
IDirect3D9* m_pD3D;         // The IDirect3D9 interface
IDirect3DDevice9* m_pd3dDevice; // D3D Device
D3DPRESENT_PARAMETERS m_d3dpp;  // The present parameters.
bool m_bReady;          // Is DX9 ready to render?
void Render();          // Render


XXXView.cpp 파일을 열고 OnInitialUpdate() 함수를 override하고 아래 내용을 추가한다.

void XXXView::OnInitialUpdate()
{
    CView::OnInitialUpdate();

    // TODO: Add your specialized code here and/or call the base class
    HWND hDevice, hFocus; 
HRESULT hr; 

hDevice = GetSafeHwnd(); 
hFocus  = GetTopLevelParent() ->GetSafeHwnd(); 

GetClientRect(&m_rectClient); 

// Create Direct3D object
        m_pD3D = Direct3DCreate9(D3D_SDK_VERSION); 

D3DDISPLAYMODE d3ddm; 
m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); 

// D3DPRESENT_PARAMETERS 구조체의설정
::ZeroMemory(&m_d3dpp, sizeof(m_d3dpp)); 
m_d3dpp.Windowed            = TRUE; 
m_d3dpp.BackBufferCount     = 1; 
m_d3dpp.SwapEffect          = D3DSWAPEFFECT_DISCARD; 
m_d3dpp.EnableAutoDepthStencil  = TRUE; 
m_d3dpp.AutoDepthStencilFormat  = D3DFMT_D16; 
m_d3dpp.hDeviceWindow       = hDevice; 
m_d3dpp.BackBufferWidth     = m_rectClient.Width(); 
m_d3dpp.BackBufferHeight        = m_rectClient.Height(); 
m_d3dpp.BackBufferFormat        = d3ddm.Format
m_d3dpp.Flags                 |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;

// 디바이스작성
hr = m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, 
D3DDEVTYPE_HAL, 
hFocus, 
D3DCREATE_SOFTWARE_VERTEXPROCESSING, 
&m_d3dpp, 
&m_pd3dDevice);

    m_pd3dDevice->SetDialogBoxMode(TRUE);
    m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

m_bReady = TRUE;
}

Render() 함수는 아래와 같다.

void CeConsoleView::Render()
{
m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

    if(SUCCEEDED(m_pd3dDevice->BeginScene())) 
    {
        m_pd3dDevice->EndScene(); 
    }

    m_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}

마지막으로 OnDraw() 함수에 아래 내용을 추가하면 준비는 완료

    // TODO: add draw code for native data here
    if( m_bReady )
        Render();


2007년 4월 16일 월요일

Using DirectShow

Getting the SDK package

At the first stage, you have to download following DirectSDK which of version is
February 2005.

http://www.microsoft.com/downloads/details.aspx?FamilyID=8af0afa9-1383-44b4-bc8b-7d6315212323&DisplayLang=en

Then install the extra package in the appropriate directory.

Setting the environmental variables

In the VS.NET, select Tools>Options>VC++ Directories.

Add the include/lib directory in the "Include files" and "Library files".
You can find them in the combo box.

Using the SDK

Test with next code. If there's no error when compiling and excuting, all done.




#include <DShow.h>

#pragma comment(lib, "strmiids.lib")

void main(void)
{
    IGraphBuilder *pGraph = NULL;
    IMediaControl *pControl = NULL;
    IMediaEvent   *pEvent = NULL;

    // Initialize the COM library.
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        printf("ERROR - Could not initialize COM library");
        return;
    }

    // Create the filter graph manager and query for interfaces.
    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
                        IID_IGraphBuilder, (void **)&pGraph);
    if (FAILED(hr))
    {
        printf("ERROR - Could not create the Filter Graph Manager.");
        return;
    }

    hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
    hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

    // Build the graph. IMPORTANT: Change this string to a file on your system.
    hr = pGraph->RenderFile(L"C:\\Example.avi", NULL);
    if (SUCCEEDED(hr))
    {
        // Run the graph.
        hr = pControl->Run();
        if (SUCCEEDED(hr))
        {
            // Wait for completion.
            long evCode;
            pEvent->WaitForCompletion(INFINITE, &evCode);

            // Note: Do not use INFINITE in a real application, because it
            // can block indefinitely.
        }
    }
    pControl->Release();
    pEvent->Release();
    pGraph->Release();
    CoUninitialize();
}

2007년 4월 12일 목요일

Sierpinski Carpet Demo



void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);

    CRect clientRect;
    GetClientRect(&clientRect);
    SolidBrush brush(Color(255, 0, 0, 0));

    SierpinskiCarpet3(g, brush, clientRect.Width()/2, clientRect.Height()/2, 120);

}

void CGdiplusDemoView::SierpinskiCarpet1(Graphics& g, SolidBrush& brush, int x, int y, int r)
{
    if ( r <= 0 )
        return;

    SierpinskiCarpet1(g, brush, x-2*r, y+2*r, r/3);
    SierpinskiCarpet1(g, brush, x-2*r, y, r/3);
    SierpinskiCarpet1(g, brush, x-2*r, y-2*r, r/3);
    SierpinskiCarpet1(g, brush, x, y+2*r, r/3);
    SierpinskiCarpet1(g, brush, x, y-2*r, r/3);
    SierpinskiCarpet1(g, brush, x+2*r, y+2*r, r/3);
    SierpinskiCarpet1(g, brush, x+2*r, y, r/3);
    SierpinskiCarpet1(g, brush, x+2*r, y-2*r, r/3);
    g.FillRectangle(&brush, x-r/4, y-r/4, r/2, r/2);
}

void CGdiplusDemoView::SierpinskiCarpet2(Graphics& g, SolidBrush& brush, int x, int y, int r)
{
    if ( r <= 0 )
        return;

    SierpinskiCarpet2(g, brush, x-2*r, y+2*r, r/2);
    SierpinskiCarpet2(g, brush, x-2*r, y, r/2);
    SierpinskiCarpet2(g, brush, x-2*r, y-2*r, r/2);
    SierpinskiCarpet2(g, brush, x, y+2*r, r/2);
    SierpinskiCarpet2(g, brush, x, y-2*r, r/2);
    SierpinskiCarpet2(g, brush, x+2*r, y+2*r, r/2);
    SierpinskiCarpet2(g, brush, x+2*r, y, r/2);
    SierpinskiCarpet2(g, brush, x+2*r, y-2*r, r/2);
    g.FillRectangle(&brush, x-r/4, y-r/4, r/2, r/2);
}

void CGdiplusDemoView::SierpinskiCarpet3(Graphics& g, SolidBrush& brush, int x, int y, int r)
{
    if ( r <= 0 )
        return;

    SierpinskiCarpet3(g, brush, x-r, y+r, r/2);
    SierpinskiCarpet3(g, brush, x+r, y+r, r/2);
    SierpinskiCarpet3(g, brush, x-r, y-r, r/2);
    SierpinskiCarpet3(g, brush, x+r, y-r, r/2);
    g.FillRectangle(&brush, x-r/3, y-r/3, r/3, r/3);
}


2007년 4월 10일 화요일

CInternetSession, CHttpConnection, CHttpFile 예제

#include "stdafx.h"
#include "main.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

using namespace std;

void ParseCmdLine(int argc, TCHAR* argv[], TCHAR* envp[]);
void Say(CString status);

int TMainApp(int argc, TCHAR* argv[], TCHAR* envp[]) {

    Say("Parsing command line...");
    ParseCmdLine(argc, argv, envp);

    Say("Allocating variables...");
    CString m_sURL = "http://www.digital.go.kr/rss/fc_textxml.jsp?row=120&col=61®ion=7&locationcode=4111573000";
    CInternetSession m_Session;
    CHttpConnection* m_pHttpConnection=NULL;
    CHttpFile* m_pHttpFile = NULL;

    Say("Connecting...");
    try {
        m_pHttpConnection = m_Session.GetHttpConnection(m_sURL,(INTERNET_PORT)80, NULL, NULL);
        if( m_pHttpConnection == NULL )
            throw CString("Http connection failed");

        m_pHttpFile = (CHttpFile*)m_Session.OpenURL(m_sURL);
    
        if( !m_pHttpFile ) {
            m_pHttpFile->Close();
            delete m_pHttpFile;
            throw CString("HttpFile connection failed");
        }
    }
    catch ( CInternetException *pEx ) {
        if ( m_pHttpFile) {
            m_pHttpFile->Close();
            delete m_pHttpFile;
        }
        if ( m_pHttpConnection ) {
            m_pHttpConnection->Close();
            delete m_pHttpConnection;
        }
        TCHAR lpszErrorMessage[255];
        pEx->GetErrorMessage(lpszErrorMessage, 255);
        pEx->Delete();
        cout << lpszErrorMessage << endl;
        return 1;
    }
    catch (CString e) {
        cout << "Error : " << (LPCTSTR)e << endl;
        cout << "Program aborted..." << endl;
        return -1;
    }
    Say("Connection established.");

    Say("Listing file...");
    CString line;
    while ( m_pHttpFile->ReadString(line) != NULL ) {
        // line += "\r\n";
        wcout << (LPCTSTR)line << endl;
    }
    Say("Listing complete");

    Say("Shutdown process started");
    Say("Deleting m_pHttpFile...");
    if ( m_pHttpFile) {
        m_pHttpFile->Close();
        delete m_pHttpFile;
    }
    Say("Deleting m_pHttpConnection...");
    if ( m_pHttpConnection ) {
        m_pHttpConnection->Close();
        delete m_pHttpConnection;
    }

    return 0;
}

void ParseCmdLine(int argc, TCHAR* argv[], TCHAR* envp[]) {

//  if ( argc != 2 )
//      throw CString(L"Usage : inet.exe ip_address");

}

void Say(CString status) {
    cout << (LPCTSTR)status << endl;
}


2007년 4월 8일 일요일

MFC Using registry key

리지스트리 이용하기
Using registry key

InitInstance()에

    ...
    SetRegistryKey(_T("My App"));
    ...
    
라고 하면

    HKEY_CURRENT_USER\Software\My App\(Project name)
    
아래에 저장된다.


이것은 Demo only로 OnDraw에 이런 짓은 하지 말기를...
AfxGetApp()->WriteProfileXXX()
AfxGetApp()->GetProfileXXX()
함수 참조

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);
    CString sTest;

    AfxGetApp()->WriteProfileString(L"Section", L"Entry", L"Value");

    // Create font
    FontFamily fontFamily(L"Arial");
    Font font(&fontFamily, 24, FontStyleBold, UnitPixel);

    // Create brush
    SolidBrush brush(Color(255, 0, 0, 255));

    // Center alignment
    StringFormat stringFormat;
    stringFormat.SetAlignment(StringAlignmentCenter);
    stringFormat.SetLineAlignment(StringAlignmentCenter);

    sTest = AfxGetApp()->GetProfileString(L"Section", L"Entry");
    PointF pointF(100, 100);
    g.DrawString(sTest, sTest.GetLength(), &font, pointF, &stringFormat, &brush);
}


Ogura Yuko

She's also hot girl...








GDI+ coordinate transform

이 예제는 Visual C++.NET programming Bible - Young Jin 에서 발췌한 것이다.

// OnInitialUpdate override

void CGdiplusDemoView::OnInitialUpdate()
{
    CView::OnInitialUpdate();

    // TODO: Add your specialized code here and/or call the base class
    SetTimer(0, 100, NULL);
}

// OnTimer override

void CGdiplusDemoView::OnTimer(UINT_PTR nIDEvent)
{
    // TODO: Add your message handler code here and/or call default
    Invalidate();

    CView::OnTimer(nIDEvent);
}


#define R_SUN   50
#define R_EARTH 30
#define R_MOON  20

#define EARTH_TO_SUN    300
#define EARTH_TO_MOON   70

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);

    static int angleEarth, angleLunar;
    CRect rect;
    GetClientRect(rect);

    Pen pen(Color(255, 0, 0, 0), 3);
    SolidBrush brush(Color(255, 0, 0, 255));

    // Create font
    FontFamily fontFamily(L"Arial");
    Font font(&fontFamily, 12, FontStyleBold, UnitPixel);

    // Text output format
    StringFormat stringFormat;
    stringFormat.SetAlignment(StringAlignmentCenter);
    stringFormat.SetLineAlignment(StringAlignmentCenter);

    // Draw sun
    g.ResetTransform();
    g.TranslateTransform((REAL)rect.Width()/2, (REAL)rect.Height()/2);
    g.DrawEllipse(&pen, -R_SUN, -R_SUN, 2*R_SUN, 2*R_SUN);
    g.DrawString(L"SUN", 3, &font, PointF(0, 0), &stringFormat, &brush);

    // Draw earth
    g.RotateTransform((REAL)angleEarth);
    g.TranslateTransform(EARTH_TO_SUN, 0);
    g.DrawEllipse(&pen, -R_EARTH, -R_EARTH, 2*R_EARTH, 2*R_EARTH);
    g.DrawString(L"EARTH", 5, &font, PointF(0, 0), &stringFormat, &brush);

    // Draw moon
    g.RotateTransform((REAL)angleLunar);
    g.TranslateTransform(EARTH_TO_MOON, 0);
    g.DrawEllipse(&pen, -R_MOON, -R_MOON, 2*R_MOON, 2*R_MOON);
    g.DrawString(L"MOON", 4, &font, PointF(0, 0), &stringFormat, &brush);

    angleEarth++;
    angleLunar += 12;
}


GDI+ mapping mode

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);

    Pen pen(Color(255, 0, 0, 0), 3);

    /*
    enum Unit
    {
        UnitWorld,      // 0 -- World coordinate (non-physical unit)
        UnitDisplay,    // 1 -- Variable -- for PageTransform only
        UnitPixel,      // 2 -- Each unit is one device pixel.
        UnitPoint,      // 3 -- Each unit is a printer's point, or 1/72 inch.
        UnitInch,       // 4 -- Each unit is 1 inch.
        UnitDocument,   // 5 -- Each unit is 1/300 inch.
        UnitMillimeter  // 6 -- Each unit is 1 millimeter.
    };
    */

    // Pixel mapping
    g.SetPageUnit(UnitPixel);
    g.DrawRectangle(&pen, 30, 30, 60, 60);

    // Milimeter mapping
    g.SetPageUnit(UnitMillimeter);
    g.DrawRectangle(&pen, 30, 30, 60, 60);
}


GDI+ clipping region

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);

    // Create region
    Point points[] = {
        Point(10, 30), Point(200, 10), Point(150, 50), Point(170, 150)
    };
    GraphicsPath path;
    path.AddPolygon(points, 4);
    Region region(&path);

    // Draw region
    Pen pen(Color(255, 0, 0, 0));
    g.DrawPath(&pen, &path);

    // Clipping
    g.SetClip(®ion);

    // Display text
    FontFamily fontFamily(L"Arial");
    Font font(&fontFamily, 36, FontStyleBold, UnitPixel);
    SolidBrush brush(Color(255, 255, 0, 0));

    g.DrawString(L"Clipping", 20, &font, PointF(15, 25), &brush);
}


GDI+ text display

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);

    CRect rect;
    GetClientRect(rect);
    
    WCHAR string[] = L"Hi, I'm a man who used XT long time ago";

    /*
    enum FontStyle
    {
        FontStyleRegular    = 0,
        FontStyleBold       = 1,
        FontStyleItalic     = 2,
        FontStyleBoldItalic = 3,
        FontStyleUnderline  = 4,
        FontStyleStrikeout  = 8
    };
    enum Unit
    {
        UnitWorld,      // 0 -- World coordinate (non-physical unit)
        UnitDisplay,    // 1 -- Variable -- for PageTransform only
        UnitPixel,      // 2 -- Each unit is one device pixel.
        UnitPoint,      // 3 -- Each unit is a printer's point, or 1/72 inch.
        UnitInch,       // 4 -- Each unit is 1 inch.
        UnitDocument,   // 5 -- Each unit is 1/300 inch.
        UnitMillimeter  // 6 -- Each unit is 1 millimeter.
    };
    */

    // Create font
    FontFamily fontFamily(L"Arial");
    Font font(&fontFamily, 24, FontStyleBold, UnitPixel);

    // Create brush
    SolidBrush brush(Color(255, 0, 0, 255));

    // Center alignment
    StringFormat stringFormat;
    stringFormat.SetAlignment(StringAlignmentCenter);
    stringFormat.SetLineAlignment(StringAlignmentCenter);

    // Display text in the middle of the window
    PointF pointF(rect.Width()/2, rect.Height()/2);
    g.DrawString(string, (INT)wcslen(string), &font, pointF, &stringFormat, &brush);

    // Adjust display quality
    g.SetTextRenderingHint(TextRenderingHintClearTypeGridFit);

    // Display text int the middle of the rectangle
    RectF rectF(300, 20, 200, 100);
    g.DrawString(string, (INT)wcslen(string), &font, rectF, &stringFormat, &brush);

    Pen pen(Color(255, 255, 0, 0));
    g.DrawRectangle(&pen, rectF);
}


GDI+ draw image

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);

    // Read image file, *.bmp, *.gif, *.png, *.jpg format supported
    Image image(L"test.jpg");
    int width = image.GetWidth();
    int height = image.GetHeight();

    // Display image
    g.DrawImage(&image, 10, 10, width, height);

    // Display distorted image
    Point points[] = {
        Point(250, 20), Point(150, 100), Point(300, 50)
    };
    g.DrawImage(&image, points, 3);

    // Magnified display
    g.SetInterpolationMode(InterpolationModeNearestNeighbor);
    g.DrawImage(&image, 10, 150, width*2, width*2);

    g.SetInterpolationMode(InterpolationModeHighQualityBilinear);
    g.DrawImage(&image, 220, 150, width*2, width*2);
}


GDI+ paint with pattern brush

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);

    for ( int i = 0; i < HatchStyleTotal; i++ ) {
        HatchBrush brush((Gdiplus::HatchStyle)i,
            Color(255, 0, 0, 0), Color(255, 255, 255, 0));
        g.FillRectangle(&brush, 20+(i%7)*90, 20+(i/7)*60, 80, 50);
    }
}


GDI+ paint with gradient brush

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);

    LinearGradientBrush linearBrush(Point(50, 100), Point(250, 200), Color(255, 255 , 0, 0), Color(255, 0, 0, 255));
    g.FillRectangle(&linearBrush, 50, 100, 200, 100);

    GraphicsPath path;
    path.AddEllipse(300, 100, 200, 100);

    int count = 1;
    PathGradientBrush pathBrush(&path);
    pathBrush.SetCenterColor(Color(255, 255, 0, 0));
    pathBrush.SetSurroundColors(&Color(255, 255, 255, 0), &count);

    g.FillEllipse(&pathBrush, 300, 100, 200, 100);
}


GDI+ paint with brush(alpha blending)

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);

    SolidBrush brush(Color(128, 255, 0, 0));
    g.FillRectangle(&brush, 50, 100, 200, 100);

    brush.SetColor(Color(128, 0, 255, 0));
    g.FillEllipse(&brush, 150, 150, 200, 100);

    brush.SetColor(Color(128, 255, 255, 0));
    g.FillPie(&brush, 50, 130, 200, 200, 135, 90);

    brush.SetColor(Color(128, 0, 0, 255));
    Point points[] = {
        Point(80, 50), Point(170, 70), Point(220, 30),
        Point(200, 110), Point(150, 90), Point(100, 150)
    };
    /*
    enum FillMode
    {
        FillModeAlternate,        // 0
        FillModeWinding           // 1
    };
    */
    g.FillClosedCurve(&brush, points, 6, FillModeAlternate, 1);
}


GDI+ line pattern

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);

    Pen pen(Color(255, 0, 0, 0), 3);
    
    /*
    enum DashStyle
    {
        DashStyleSolid,          // 0
        DashStyleDash,           // 1
        DashStyleDot,            // 2
        DashStyleDashDot,        // 3
        DashStyleDashDotDot,     // 4
        DashStyleCustom          // 5
    };
    */
    // 실선
    pen.SetDashStyle(DashStyleSolid);
    g.DrawLine(&pen, 50, 50, 400, 50);
    // 파선
    pen.SetDashStyle(DashStyleDash);
    g.DrawLine(&pen, 50, 100, 400, 100);
    // 점선
    pen.SetDashStyle(DashStyleDot);
    g.DrawLine(&pen, 50, 150, 400, 150);
    // 일점 쇄선
    pen.SetDashStyle(DashStyleDashDot);
    g.DrawLine(&pen, 50, 200, 400, 200);
    // 이점 쇄선
    pen.SetDashStyle(DashStyleDashDotDot);
    g.DrawLine(&pen, 50, 250, 400, 250);
    // 시작점을 5 픽셀 이동
    pen.SetDashOffset(5);
    g.DrawLine(&pen, 50, 260, 400, 260);
    // 사용자 정의 패턴
    REAL dashVals[4] = { 5, 1, 2, 1 };
    pen.SetDashPattern(dashVals, 4);
    g.DrawLine(&pen, 50, 310, 400, 310);
}


GDI+ line cap shape/join shape

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);

    Pen capPen(Color(255, 0, 0, 0), 5);
    
    /*
    enum LineCap
    {
        LineCapFlat             = 0,
        LineCapSquare           = 1,
        LineCapRound            = 2,
        LineCapTriangle         = 3,

        LineCapNoAnchor         = 0x10, // corresponds to flat cap
        LineCapSquareAnchor     = 0x11, // corresponds to square cap
        LineCapRoundAnchor      = 0x12, // corresponds to round cap
        LineCapDiamondAnchor    = 0x13, // corresponds to triangle cap
        LineCapArrowAnchor      = 0x14, // no correspondence

        LineCapCustom           = 0xff, // custom cap

        LineCapAnchorMask       = 0xf0  // mask to check for anchor or not.
    };
    */

    // Line 
    capPen.SetStartCap(LineCapSquare);
    capPen.SetEndCap(LineCapRound);
    g.DrawLine(&capPen, 50, 50, 400, 50);

    capPen.SetStartCap(LineCapTriangle);
    capPen.SetEndCap(LineCapNoAnchor);
    g.DrawLine(&capPen, 50, 100, 400, 100);

    capPen.SetStartCap(LineCapSquareAnchor);
    capPen.SetEndCap(LineCapRoundAnchor);
    g.DrawLine(&capPen, 50, 150, 400, 150);

    capPen.SetStartCap(LineCapDiamondAnchor);
    capPen.SetEndCap(LineCapArrowAnchor);
    g.DrawLine(&capPen, 50, 200, 400, 200);

    /*
        enum LineJoin
    {
        LineJoinMiter        = 0,
        LineJoinBevel        = 1,
        LineJoinRound        = 2,
        LineJoinMiterClipped = 3
    };
    */

    // Set line join style
    Pen joinPen(Color(255, 0, 0, 0), 10);

    joinPen.SetLineJoin(LineJoinBevel);
    g.DrawRectangle(&joinPen, 50, 250, 100, 100);

    joinPen.SetLineJoin(LineJoinMiter);
    g.DrawRectangle(&joinPen, 180, 250, 100, 100);

    joinPen.SetLineJoin(LineJoinRound);
    g.DrawRectangle(&joinPen, 310, 250, 100, 100);
}


GDI+ Pen thickness/alignment

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);
    Pen blackPen(Color(255, 0, 0, 0), 1);
    Pen greenPen(Color(255, 0, 255, 0), 10);

    /*
    !!! Only PenAlignmentCenter & PenAlignmentInset are defined
    typedef enum {
        PenAlignmentCenter = 0,
        PenAlignmentInset = 1
    } PenAlignment;
    */

    // Draw line
    /*
    greenPen.SetAlignment(PenAlignmentLeft);
    g.DrawLine(&greenPen, 50, 200, 200, 50);
    g.DrawLine(&blackPen, 50, 200, 200, 50);
    */

    greenPen.SetAlignment(PenAlignmentCenter);
    g.DrawLine(&greenPen, 150, 200, 300, 50);
    g.DrawLine(&blackPen, 150, 200, 300, 50);

    /*
    greenPen.SetAlignment(PenAlignmentRight);
    g.DrawLine(&greenPen, 250, 200, 400, 50);
    g.DrawLine(&blackPen, 250, 200, 400, 50);
    */

    // Draw rectangle(closed curve
    greenPen.SetAlignment(PenAlignmentInset);
    g.DrawRectangle(&greenPen, 50, 250, 100, 100);
    g.DrawRectangle(&blackPen, 50, 250, 100, 100);

    greenPen.SetAlignment(PenAlignmentCenter);
    g.DrawRectangle(&greenPen, 180, 250, 100, 100);
    g.DrawRectangle(&blackPen, 180, 250, 100, 100);

    /*
    greenPen.SetAlignment(PenAlignmentOutset);
    g.DrawRectangle(&greenPen, 310, 250, 100, 100);
    g.DrawRectangle(&blackPen, 310, 250, 100, 100); 
    */
}


Ogura Yuko

She's one of my favorite Japanese girl.








GDI+ line/polygon/curve

먼저 GDI+ 를 사용하기 위한 기본 설정은
For the proper use of GDI+ refer

    Using GDI+ in VS.NET 2005
    
를 참조한다.


1. Lines

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);
    Pen pen(Color(255, 0, 0, 0), 3);        // Pen with thickness = 3

    g.DrawLine(&pen, 50, 50, 500, 50);
    g.DrawRectangle(&pen, 50, 100, 200, 100);
    g.DrawEllipse(&pen, 300, 100, 200, 100);
    g.DrawPie(&pen, 50, 250, 200, 200, 225, 90);
    g.DrawArc(&pen, 300, 250, 200, 200, 225, 90);
}

2. Polygon and curves

void CGdiplusDemoView::OnDraw(CDC* pDC)
{
    Graphics g(pDC->m_hDC);
    Pen pen(Color(255, 0, 0, 0), 3);

    // Set coordinates
    Point points[] = {
        Point(30, 30), Point(120, 50), Point(170, 10), Point(150, 90), Point(90, 70), Point(50, 130)
    };

    // Polygon
    g.DrawPolygon(&pen, points, 6);
    
    // Closed curve
    for ( int i = 0; i < 6; i++ )
        points[i].X += 200;
    g.DrawClosedCurve(&pen, points, 6, 0.5f);

    // Closed curve
    for ( int i = 0; i < 6; i++ )
        points[i].X += 200;
    g.DrawClosedCurve(&pen, points, 6, 1);

    // Opened curve
    for ( int i = 0; i < 6; i++ ) {
        points[i].X -= 400;
        points[i].Y += 150;
    }
    g.DrawCurve(&pen, points, 6, 0);

    // Opened curve
    for ( int i = 0; i < 6; i++ )
        points[i].X += 200;
    g.DrawCurve(&pen, points, 6, 0.5);

    // Opend curve
    for ( int i = 0; i < 6; i++ )
        points[i].X += 200;
    g.DrawCurve(&pen, points, 6, 1);
}


2007년 4월 5일 목요일

MFC Collection Class

MFC Collection Class


Non-Template Version
























Template Version





사용자 정의 클래스를 템플릿 컬렉션에 저장하기 위해서는
To store user-created class in the template collection

생성자 함수를 구현
implement constructor function
== 오버로딩
overload == operator

해야 한다.

CStringArray = CArray
CMapStringToString = CMap

템플릿 버전의 첫 번째는 데이타형을 두 번째는 전달되는 인자의 형을 의미한다.
The first type in the template denotes data type while sencond denotes type of parameter-passed

CArray strings;
strings.Add("First");
strings.Add("Second");


2007년 4월 4일 수요일

VS.NET 에서 Build Number 자동 증가 (1)

빌드 넘버 자동 증가
Build number automatic increasement

VS 6.0  이용자들은 다음 링크 사용
For VS 6.0 users

    http://www.support.microsoft.com/default.aspx?scid=kb;en-us;237870
    
VS.NET 2003, 2005 이용자들은 여기 적힌대로 적용한다.
현재 몇몇 매크로들이 제대로 작동을 하지 않아서 직접 약간 수정을 했다.
기본적인 방법은 대부분 같다. MFC 프로젝트를 기준으로 설명한다.

For VS.NET 2003, 2005 users, you just need to follow the explaination below.

프로젝트명은 MyProject라고 했다고 가정한다.

Let us assume the project name as MyProject.

MFC 프로젝트로 생성했다면 프로젝트 폴더에 MyProject.rc 와 \res 폴더에
MyProject.rc2 라는 파일을 연다. 그냥 Win32 Application으로  생성했다면
다른 MFC 프로젝트 폴더에서 \res 폴더를 그대로 카피해와서 MyProject.rc2
파일만 남기고 모두 지운다.(파일명을 바꾸어야 할 것이다.)

If you create MFC project, open up the MyProject.rc and
\res\MyProject.rc2 files. If you create Win32 Application project,
just copy the \res\xxxx.rc2 file from another MFC project folder and
rename it.

MyProject.rc 파일에서 다음 부분을 cut 한다.

Cut next section from MyProject.rc

   ////////////////////////////////////////////////////////
   //
   // Version
   //
   VS_VERSION_INFO VERSIONINFO
   FILEVERSION 1,0,0,1
   PRODUCTVERSION 1,0,0,1
   FILEFLAGSMASK 0x3fL
   .
   .
   .
      BLOCK "VarFileInfo"
       BEGIN
           VALUE "Translation", 0x409, 1200
       END
   END

Win32App 프로젝트라면 MyProject.rc 파일에 다음 부분을 추가해야 한다.

Add next line if your project is Win32App.

   ...
   2 TEXTINCLUDE
   BEGIN
    "#include ""afxres.h""\r\n"
    "#include ""res\\ProjectName.rc2""  // <------- Here
    "\0"
   END
   ...

MyProject.rc2 파일의 다음 위치에 paste 한다.

Paste the copied text in the MyProject.rc2.

   ...
   ////////////////////////////////////////////////////////
   // Add manually edited resources here...

   ////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////
   //
   // Version
   //
   #include "VersionNo.h"              // <------- Here
   VS_VERSION_INFO     VERSIONINFO
   FILEVERSION       FILEVER           // <------- Here
   PRODUCTVERSION    PRODUCTVER        // <------- Here
   FILEFLAGSMASK 0x3fL

   ...
        BEGIN
            VALUE "FileDescription", "MyProject Application"
            VALUE "FileVersion", STRFILEVER
                                                   // <------- Here
            VALUE "InternalName", "MyProject"
            VALUE "LegalCopyright", "Copyright (C) 2003"
            VALUE "OriginalFilename", "MyProject.exe"
            VALUE "ProductName", " MyProjectApplication"
            VALUE "ProductVersion", STRPRODUCTVER
                                                   // <------- Here
        END
   ...

VersionNo.h 라는 파일을 만들고 다음과 같은 내용으로 채운다. 일단 여기에
있는 내용을 그대로 옮기기 바란다.

Create a VersionNo.h file and copy and paste next 4 lines.

   #define FILEVER        1,0,0,1
   #define PRODUCTVER     1,0,0,1
   #define STRFILEVER     "1, 0, 0, 1"
   #define STRPRODUCTVER  "1, 0, 0, 1"

Tools->Macros->New Macro Project 를 실행한다.

Select Tools->Macros->New Macro Project

Macro Explorer 창이 나타날 것이다. "+" 키를 누르면 기본적으로 "Module1"
이라는 마크로가 있을 것이다. 이것을 원하는 이름으로 변경한다.
그것을 더블클릭하면 Macro IDE가 나타날 것이다.

It will open up "Macro Explorer" window. Press "+" in the macro project
and it displays "Module1". You can rename it to whatever you want.
Double click the module to open Macro IDE.

에디터 창에 있는 모든 내용을 지우고 다음으로 채워 넣는다.
Delete all existing code and copy and paste next  code.

======= FROM NEXT ================================================
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics

Public Module IncreaseBuildNo

    Function GetProjectDir(ByVal FullName)

        Dim proj_path
        proj_path = Split(StrReverse(FullName), "\", -1, 1)

        Dim count
        count = UBound(proj_path)

        Dim full_path
        full_path = ""
        Dim i

        For i = 1 To count
            full_path = full_path & "\" & proj_path(i)
        Next

        GetProjectDir = StrReverse(full_path)

    End Function

    Sub ReplaceText(ByVal objSel As TextSelection, ByVal count As Integer, ByVal incrementby As Integer, ByVal Type As Integer)

        'selection represents the TextSelection object
        'count represents the position of the version number
        'to be incremented
        'incrementally represents a number that will be added
        'to the existing version number

        Dim strTemp As String
        Dim i

        strTemp = ""
        objSel.EndOfLine()


        If Type = 0 Then
            For i = 1 To count
                If strTemp.StartsWith(",") = True Then
                    Exit For
                Else
                    objSel.CharLeft(True, 1)
                    strTemp = objSel.Text
                End If
            Next
            strTemp = strTemp.Remove(0, 1)
            strTemp = strTemp + incrementby
            objSel.Text = "," & strTemp
        Else
            For i = 1 To count
                If strTemp.StartsWith(" ") = True Then
                    Exit For
                Else
                    objSel.CharLeft(True, 1)
                    strTemp = objSel.Text
                End If
            Next
            strTemp = strTemp.Remove(0, 1)
            strTemp = strTemp.Remove(strTemp.Length - 1, 1)
            strTemp = strTemp + incrementby
            objSel.Text = " " & strTemp & """"
        End If

    End Sub

    Dim WithEvents bldevents As BuildEvents
    Dim applicationObject As EnvDTE.DTE

    Sub BuildDoneEvents()
        Dim addInInstance As EnvDTE.AddIn

        applicationObject = CType(Application, EnvDTE.DTE)
        bldevents = CType(applicationObject.Events. _
                          BuildEvents, EnvDTE.BuildEvents)
    End Sub

    Private Sub bldevents_OnBuildDone(ByVal _
                          Scope As EnvDTE.vsBuildScope, _
                          ByVal Action As EnvDTE. _
                          vsBuildAction) Handles _
                          bldevents.OnBuildDone
        'This event will be triggered after every build
        'of a project

        'Obtain the full path of the active project
        Dim full_path
        full_path = GetProjectDir(DTE.ActiveDocument.Path)

        full_path = full_path & "VersionNo.h"

        'Open the VersionNo.h file
        Dim doc As Document
        DTE.ItemOperations.OpenFile(full_path)

        Dim objDoc As TextDocument

        'Obtain the TextSelection object
        objDoc = DTE.ActiveDocument.Object("TextDocument")

        Dim objSel As TextSelection = _
                      DTE.ActiveDocument.Selection

        objSel.StartOfDocument()


        'Increment the version information
        ReplaceText(objSel, 5, 1, 0)
        objSel.LineDown()
        objSel.StartOfLine()
        ReplaceText(objSel, 5, 1, 0)
        objSel.LineDown()
        objSel.StartOfLine()
        ReplaceText(objSel, 7, 1, 100)
        objSel.LineDown()
        objSel.StartOfLine()
        ReplaceText(objSel, 7, 1, 100)

        ActiveDocument.Save()
        ActiveDocument.Close()
    End Sub

End Module
======= TO HERE ==========================================

매크로를 저장하고 VS.NET으로 돌아 와서 Macro Explorer 에서 해당 모듈을
오른클릭해서 "Run" 을 선택해서 실행시킨다.

Save the macro and in the VS.NET, in  the "Macro Explorer",
right-click it and choose "Run".



따라 하기만 하면 빌드할 때마다 VersionNo.h 파일의 Build 번호가 자동으로
증가할 것이다.

If nothing wrong, you can see the build number is increased after the build.

MFC 메시지를 이용한 통신

메시지를 이용한 통신

메시지를 보내는 데는 다음과 같이 두 가지 방법이 있다.

    - SendMessage 함수를 이용하는 방법
    - PostMessage 함수를 이용하는 방법
    
CWnd::SendMessage 함수

    SendMessage 함수는 윈도우에 메시지를 보내는 함수로서 다음과 같이 정의되어 있다.
    
    LRESULT SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);
    
    이 함수는 매개변수로 메시지의 종류와 추가적인 정보를 담기 위한 wParam, lParam을
    인자로 넣어 주도록 되어 있다. 또, 이 함수는 CWnd 클래스의 멤버 함수라는 점에
    주목하자. CFrameWnd 클래스에서 SendMessage 함수를 호출하면 프레임 윈도우로
    메시지가 날아가고 CView 클래스에서 SendMessage 함수를 호출하면 뷰 윈도우로
    메시지가 날아 가게 된다.
    
    그러나 CWnd 클래스에서 상속받지 않은 CWinApp 클래스나 CDocument 파생 클래스에
    서는 SendMessage 함수를 호출할 수 없다. 만약 메인 프레임 클래스 밖에서 메인
    프레임 윈도우로 메시지를 보내고 싶으면 다음과 같이 하면 된다.
    
    AfxGetMainWnd()->SendMessage(..., ..., ...);
    
    SendMessage 함수를 이용하여 어떤 윈도우에 WM_MOUSEMOVE 메시지를 보내면 마우스를
    움직이지 않고도 마우스가 움직일 때 수행되는 동작을 하도록 할 수 있고 WM_KEYDOWN
    메시지를 보내면 키보드를 누르지 않고도 키보드가 눌린 것처럼 동작을 시킬 수가
    있다.
    
    또한 메인 프레임 윈도우로 WM_COMMAND 메시지를 보내면 메뉴를 선택하지 않고도
    메뉴가 선택됐을 때 하는 동작을 수행하도록 할 수 있다.
    
    예를 들면,
    
    AfxGetMainWnd()->SendMessage(WM_COMMAND, ID_FILE_OPEN);
    
    이라고 메시지를 보내주면 프로그램은 사용자가 메뉴에서 파일 열기 항목을 선택했을
    때와 똑같은 동작을 수행하게 된다.
    
CWnd::PostMessage 함수

    SendMessage 함수와 비슷하게 메시지를 보내는 기능을 하는 함수로 PostMessage 함수가
    있다.
    
    BOOL PostMessage(UINT message, WPARAM wParam = 0, LPARAM = lParam = 0);
    
    이 함수와 SendMessage 함수의 차이점은 메시지 큐를 거치느냐 아니냐 하는 것이다.
    SendMessage 함수를 이용하여 메시지를 보내면 메시지가 메시지 큐를 거치지 않고
    직접 메시지 처리기를 호출한다. 따라서, SendMessage 함수를 호출함과 동시에
    해당하는 메시지 처리기가 호출된다.
    
    반면 PostMessage 함수는 메시지를 메시지 큐에 넣어 주는 일만 한다. 따라서
    PostMessage 함수를 이용하여 메시지를 보내주면 현재 수행되고 있는 함수가
    완전히 끝나고, 메시지 큐에 쌓여 있던 메시지들의 처리기가 다 수행되고 난
    후에야 PostMessage 함수로 보낸 메시지의 처리기가 호출된다.
    
    

MFC의 뼈대를 이루는 클래스들의 상호 참조

프로그램의 뼈대를 이루는 클래스들 간의 상호 참조

1. CWinApp 참조
    
    AfxGetApp 함수는 CWinApp 파생클래스의 인스턴스 포인터를 반환해 준다.
    
    CWinApp* AfxGetApp();
    
2. 메인 프레임 윈도우 참조

    AfxGetMainWnd 함수는 메인 프레임 클래스의 인스턴스 포인터를 반환해 준다.
    
    CWnd* AfxGetMainWnd();
    
3. 뷰에서 프레임 윈도우/다큐먼트 참조

    뷰에서 다큐먼트 참조
    
    CDocument* CView::GetDocument() const;
    
    GetDocument()는 CView 클래스의 멤버 함수이다.
    
4. 뷰에서 자식 프레임 윈도우 참조

    뷰 클래스에서 그 뷰를 둘러싸고 있는 프레임 윈도우를 참조하려면 GetParentFrame 함수를 사용한다.
    프레임 윈도우는 비단 뷰뿐 아니라, 일반적인 윈도우를 둘러싸는 틀로써 사용될 수 있기 때문에
    GetParentFrame 함수는 CWnd 클래스의 멤버 함수로 되어 있다. 물론 CView에서도 사용할 수 있다.
    
    CFrameWnd* CWnd::GetParaentFrame() const;
    
    단일 다큐먼트 프로그램에서는 메인 프레임 윈도우를 얻는 AfxGetMainWnd 함수와 GetParentFrame
    함수의 반환값이 같다. 그러나 다중 다큐먼트 프로그램에서는 메인 프레임 윈도우의 포인터를
    반환하는 AfxGetMainWnd 함수와 자식 프레임 윈도우의 포인터를 반환하는 GetParentFrame 함수가
    서로 구별된다.
    
5. 다큐먼트에서 뷰/프레임 윈도우 참조

    다큐먼트에서 뷰 참조
    
    다큐먼트에서 뷰의 포인터를 얻으려면 GetFirstViewPosition 함수와 GetNextView 함수를 조합하여
    사용하여야 한다. 다큐먼트에서 뷰를 참조하는 것이 함수 하나로 안되고 복잡해지는 이유는
    하나의 다큐먼트에 여러 개의 뷰가 결합될 수 있기 때문이다.
    
    다큐먼트에는 이와 연결된 뷰가 리스트로 관리되고 있다. GetFirstViewPosition 함수를 호출하면
    첫 번째 뷰가 매달려 있는 포인터가 얻어지고 GetNextView를 반복 호출하면 다음 뷰들이 차례로
    얻어진다. 다음은 다큐먼트와 연결된 모든 뷰 클래스를 차례로 얻어 뷰 클래스의 멤버 함수인
    UpdateWindow 함수를 호출하는 예이다.
    
    void CMyDoc::OnRepaintAllViews() {
        POSITION pos = GetFirstViewPosition();
        while ( pos != NULL ) {
            CView* pView = GetNextView(pos);
            pView->UpdateWindow();
        }
    }
    
    다큐먼트에 뷰가 오직 하나만 연결되어 있는 경우에는 다음과 같이 간단하게 뷰 클래스의 인스턴스
    포인터를 얻어낼 수 있다. m_viewList는 CDocument 클래스의 멤버 변수로서 뷰를 관리하는 리스트이다.
    이것을 이용하여 GetHead 함수를 호출하면 리스트에 들어 있는 첫 번째 뷰가 얻어진다.
    
    void CMyDoc::OnRepaintViews() {
        CView* pView = m_viewList.GetHead();
        pView->UpdateWindow();
    }
    
    다큐먼트에서 프레임 윈도우 참조
    
    다큐먼트에서 프레임 윈도우를 직접 참조하는 일은 없다. 단일 다큐먼트 프로그램의 경우에는 그냥
    AfxGetMainWnd 함수를 호출하면 되지만 다중 다큐먼트 프로그램의 경우에는 먼저 다큐먼트의
    뷰를 얻고 그 뷰에서 자신을 포함하는 프레임 윈도우를 얻는 단계를 밟아야 한다.
    
6. 프레임 윈도우에서 뷰 참조

    프레임 윈도우에서 뷰를 참조하려면 GetActiveView 함수를 사용한다.
    
    CView* CFrameWnd::GetActiveView() const;
    
    하나의 프레임 윈도우에는 분할 윈도우를 이용하여 두 개 이상의 뷰가 들어갈 수 있다.
    GetActiveView 함수는 현재 프레임 윈도우와 연결된 뷰 중 활성화 된 것의 포인를 반환한다.
    
7. 프레임 윈도우에서 다큐먼트 참조

    프레임 윈도우 클래스에서 다큐먼트 클래스를 참조하려면 GetActiveDocument 함수를 사용한다.
    
    virtual CDocument* CFrameWnd::GetActiveDocument();
    
    이 함수는 현재 프레임 윈도우와 연결된 다큐먼트 중 활성화 된 것의 포인터를 반환한다.
    
8. 다큐먼트 템플릿에서 다큐먼트/뷰/자식 프레임 윈도우 참조

    다중 다큐먼트 프로그램에는 여러 개의 다큐먼트/뷰/자식 프레임 윈도우가 있을 수 있으며
    다큐먼트 템플릿을 이용하면 이들 모두 하나하나 참조가 가능하다.
    
    같은 타입의 클래스의 인스턴스가 두 개 이상 존재하는 것들은 모두 연결 리스트로
    이루어져 있습니다. 연결 리스트에 매달려 있는 노드를 참조하는 함수는 모두 다음과 같은
    형식으로 되어 있다.
    
    POSITION pos = GetFirstXXXPosition();
    while ( pos != NULL )
        XXX xx = (XXX *)GetNextXXX( pos );
        
    즉, 첫 번째 노드의 위치를 알려면 GetFirstXXXPosition 함수를 호출하면 되고, GetNextXXX
    함수를 반복 호출함으로써 다음 노드를 참조할 수 있다.
    
    다큐먼트 템플릿 얻기
    
    예를 들어 CWinApp 클래스에 CMultiDocTemplate 이 두 개 매달려 있을 때, 두 번째
    CMultiDoc 의 인스턴스를 얻고 싶으면 먼저 GetFirstDocTemplatePosition 함수를 호출하여
    첫 번째 노드의 포인터를 얻은 후 GetNextDocTemplate 함수를 두 번 반복 호출하면 된다.
    
    POSITION CWinApp::GetFirstDocTemplatePosition();
    CDocTemplate* CWinApp::GetNextDocTemplate(POSITION& pos);
    
    이 함수들이 모두 CWinApp 클래스의 멤버 함수이며 GetNextDocTemplate 함수의 반환값은
    CDocTemplate 의 포인터이다.
    
    다큐먼트 얻기
    
    같은 방법으로 CMultiDocTemplate 클래스에 CDocument가 두 개 매달려 있을 때, 두 번째
    CDocument의 인스턴스를 얻고 싶으면 먼저 GetFirstDocPosition 함수를 호출하여 첫 번째
    노드의 포인터를 얻은 후 GetNextDoc 함수를 두 번 반복 호출하면 된다.
    
    virtual POSITION CDocTemplate::GetFirstDocPosition();
    virtual CDocument* CDocTemplate::GetNextDoc(POSITION& rPos);
    
    이 함수들은 모두 CDocTemplate 클래스의 멤버함수이며 GetNextDoc 함수의 반환 값은
    CDocument의 포인터이다.
    
    뷰 얻기
    
    역시 마찬가지 방법으로 CDocument 클래스에 CView가 두 개 매달려 있을 때 두 번째
    CView의 인스턴스를 얻고 싶으면 먼저 GetFirstViewPosition 함수를 호출하여 첫 번째
    노드의 포인터를 얻은 후 GetNextView 함수를 두 번 반복 호출하면 된다.
    
    virtual POSITION CDocument::GetFirstViewPosition();
    virtual CView* CDocument::GetNextView(POSITION& rPosition);
    
    이 함수들은 모두 CDocument 클래스의 멤버 함수이며 GetNextView 함수의 반환 값은
    CView의 포인터이다.
    
    사용 예
    
    예를 들어, 현재 프로그램에 존재하는 모든 뷰의 포인터를 얻어내고 Invalidate 함수를
    호출하여 모든 뷰의 화면이 다시 그려지도록 하기 위해서는
    
    void CMyClass::OnUpdateAllViews() {
        CWinApp *pApp = AfxGetApp();
        POSITION posTemplate = pApp->GetFirstDocTemplatePosition();
        while ( posTemplate ) {
            CDocTemplate* pTemplate = pApp->GetNextDocTemplate(posTemplate);
            POSITION posDoc = pTemplate->GetFirstDocPosition();
            while ( posDoc ) {
                CDocument* pDoc = pTemplate->GetNextDoc(posDoc);
                POSITION posView = pDoc->GetFirstViewPosition();
                while ( posView ) {
                    CView* pView = pDoc->GetNextView(posView);
                    pView->Invalidate();
                }
            }
        }
    }
    
    와 같이 하면 된다.