블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2794)
Unity3D (852)
Programming (478)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (185)
협업 (11)
3DS Max (3)
Game (12)
Utility (68)
Etc (98)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (55)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday

 

.NET Control: WndProc, WmCreate (C#)

.NET Framework 상태에서 윈도우 메시지를 가로채는 것은 Win32 API 함수를 이용하는 것보다 더 쉬울 수도 있습니다.

하나의 방법은 System.Windows.Forms 네임스페이스에 있는 메시지 필터 인터페이스(IMessageFilter)를 사용하면 메시지가 컨트롤 또는 폼으로 처리(Dispatch)되기 전에 응용 프로그램에서 메시지를 가로챌 수 있습니다. 이 인터페이스를 상속받고, PreFilterMessage 함수를 구현하면 가능한데, 대부분의 마우스, 키보드 이벤트처럼 메시지 큐(Message Queue)에 전달되어 대기중인 이벤트에 대한 처리만 가능합니다. WM_CREATE, WM_ACTIVATE 이벤트처럼, Window API 함수로 직접 전달되는 함수에 대한 처리는 불가능합니다. (이 기법은 나중에 살펴보겠습니다.)

이에 대한 설명은 다음의 문서를 참고하시길 바랍니다. (MFC 라이브러리에 적용되는 내용이긴 하지만, .NET 프레임워크에서도 문서에서 설명하는 것과 마찬가지로 적용됩니다.)

http://support.microsoft.com/kb/166212

또 다른 방법은 WndProc 함수를 다시 정의(Override)하는 것입니다.

Visual Studio 환경 구성에서 .NET Framework Source 디버깅을 지원하도록 설정한 뒤에, Windows Forms 응용 프로그램을 만들고, 폼에 버튼(또는 다른 컨트롤)을 하나 올려보겠습니다. 그리고, 컨트롤을 생성하는 코드에 중단점을 설정하고 디버그로 프로젝트를 실행합니다. 중단점에 커서가 도달하면, “F11”키를 이용하여, 소스 코드의 내부로 무작정 들어갑니다. 그렇게 얼마 동안 하다 보면, “Control.CS” 파일이 나타나게 됩니다.

 

디버깅을 중지하고, “Control.CS” 파일을 살펴보겠습니다. 소스를 살펴보면, WndProc 수를 볼 수 있습니다. 이 함수에서 메시지를 처리하는 것을 보니, 전형적인 Win32 (C/C++) 코드와 비슷합니다. 단지, 언어적인 차이가 있을 뿐, 골격은 같다는 것을 알 수 있습니다. 메시지의 정의나 함수의 이름도 winuser.h 파일에 정의된 이름과 비슷합니다.

.NET Framework 기본 컨트롤 클래스는 Win32 기본 컨트롤의 속성과 이벤트 처리 함수를 감싸서(Wrapping), 만들어진 것임을 알 수 있습니다. 그러므로 .NET Framework 프로그램에서 사용된 컨트롤에 대하여, 대부분의 Win32 API 함수들의 적용이 가능합니다. 결국 모든 것은 Win32 체제로 돌아가게 되어 있는 것입니다.

 

다음의 코드에서는 버튼을 이용하여 기본 WndProc 함수를 다시 정의(Override)하여, Window 메시지를 처리해보겠습니다.

 

Windows Forms 응용 프로그램을 만들고, 클래스를 추가합니다.

추가한 클래스를 컨트롤 클래스로 만들기 위하여, 기본 컨트롤 클래스를 상속 받습니다. 추상 클래스가 아닌 어떤 클래스라도 좋습니다. (예를 들어 Control, Button, CheckBox, RadioButton……)

Win32 API 함수에서 사용되는 구조체와 함수를 정의합니다.

class MyControl : Button

    {

        private const Int32 WM_NCPAINT = 0x0085;

        private const Int32 WM_CREATE = 0x0001;

        private const Int32 WM_DRAWITEM = 0x002B;

        private const Int32 WM_REFLECT = 0x2000;

        private const Int32 WM_PAINT = 0x000F;

        private const Int32 WM_ERASEBKGND = 0x0014;

 

        [DllImport("user32.dll")]

        public extern static IntPtr BeginPaint(IntPtr hWnd, ref PAINTSTRUCT ps);

        [DllImport("user32.dll")]

        public extern static bool EndPaint(IntPtr hWnd, ref PAINTSTRUCT ps);

        [DllImport("user32.dll")]

        public extern static IntPtr GetDC(IntPtr hWnd);

        [DllImport("user32.dll")]

        public extern static bool ReleaseDC(IntPtr hWnd, IntPtr hDC);

 

        public struct PAINTSTRUCT

        {

            private IntPtr hdc;

            public bool fErase;

            public Rectangle rcPaint;

            public bool fRestore;

            public bool fIncUpdate;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]

            public byte[] rgbReserved;

        }

        [StructLayout(LayoutKind.Sequential)]

        public struct RECT

        {

            public Int32 left;

            public Int32 top;

            public Int32 right;

            public Int32 bottom;

        }

        public struct DRAWITEMSTRUCT

        {

            public Int32 ctlType;

            public Int32 ctlID;

            public Int32 itemID;

            public Int32 itemAction;

            public Int32 itemState;

            public IntPtr hWndItem;

            public IntPtr hDC;

            public RECT rcItem;

            public IntPtr itemData;

        }

 

추가한 클래스에 다음과 같이 WndProc 함수를 다시 정의(Override)합니다.

protected override void WndProc(ref Message m)

{

switch (m.Msg)

    {

    case WM_CREATE:

......

    break;

    case (WM_DRAWITEM | WM_REFLECT):

        WmDrawItem(ref m);

break;

    default:

        base.WndProc(ref m);

        break;

}

}

코드가 완성되면, case WM_CREATE: 줄에 중단점을 설정하고, 디버깅을 시도해봅니다. WndProc 함수가 호출되고, WM_CREATE 메시지가 전달된 것을 확인할 수 있습니다. 정말, Win32 (C/C++) 프로그램과 다른 것이 없습니다.

 

이런 식으로, Window(Control) 개체에 전달되는 이벤트(메시지)에 대한 처리 함수를 만들어서 기본 메시지 처리 프로시저를 대체하거나, 확장한다면, 앞서서 보았던 MFC, C 프로그램과 마찬가지로 컨트롤의 섬세한 제어가 가능합니다.

 

여기에 사용된 코드는 다음의 주소에서 다운로드 할 수 있습니다.

http://cid-1bbcdfedee1c617e.skydrive.live.com/self.aspx/.Public/SubclassBtn.7z

 

프로그램의 소스에서는 위에서 선언한 Window 메시지의 처리 프로시저를 작성했습니다. 각각의 메시지에 대한 기능은 역시 MSDN 문서를 참고하시길 바랍니다. 어렵지 않은 코드이므로 모든 주석은 생략했습니다.

 

어떤 프레임워크에서 응용 프로그램을 작성하더라도, 컨트롤에 대한 기본은 각각의 운영 체제에서 제공하는 각종 메시지 처리 프로시저와 그 컨트롤을 화면에 표현하기 위한 그래픽 처리 프로시저라고 생각합니다. 그 기본적인 코드는 역시 C/C++ 언어일 수 밖에 없습니다. 기본적으로 Windows 운영 체제를 작성한 언어 자체가 그런 언어이며, .NET Framework 역시 그 근본은 Win32이므로, 기본적인 것을 이해하는 것은 보다 향상된 프로그램을 작성하는데, 매우 도움이 됩니다.

출처 : http://stpetrus.spaces.live.com/blog/cns!1BBCDFEDEE1C617E!244.entry

반응형
Posted by blueasa
, |