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

카테고리

분류 전체보기 (2737)
Unity3D (817)
Programming (474)
Python (8)
TinyXML (5)
STL (13)
D3D (3)
MFC (1)
C/C++ (54)
C++/CLI (45)
C# (250)
WinForm (6)
WPF (5)
Math (10)
A.I. (1)
Win32API (11)
Algorithm (3)
Design Pattern (7)
UML (1)
MaxScript (1)
FMOD (4)
FX Studio (1)
Lua (2)
Terrain (1)
Shader (3)
boost (2)
Xml (2)
JSON (4)
Etc (11)
Monad (1)
Html5 (4)
Qt (1)
Houdini (0)
Regex (10)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (58)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (53)
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
04-20 00:00

현재 윈도우 해상도 얻기
Size Bounds = Screen.PrimaryScreen.Bounds.Size;
MessageBox.Show(Bounds.ToString());
(결과) Width=2560, Height=1600

작업 표시줄 제외한 윈도우 영역 크기 얻기
Size WorkingArea = Screen.PrimaryScreen.WorkingArea.Size;
MessageBox.Show(WorkingArea.ToString());
(결과) Width=2560, Height=1570

※ 결과 : 2560*1600 해상도에서 테스트 한 결과
반응형
Posted by blueasa
, |

MagneticForm.zip
윈도우(Form)가 바탕화면 가장자리에 가까이 가면 자동으로 붙도록 만드는 것은 그다지 어렵지 않습니다.

현재 윈도우의 좌표가 바탕화면 가장자리 좌표와 일정 수준 이상 가깝게 되면 윈도우를 강제로 바탕화면 가장자리 근처로 이동시키는게 로직의 전부입니다.

그러나 C#의 기본 Form 이벤트는 윈도우가 이동이 완료된 후의 이벤트밖에 없습니다. 자석윈도우를 만들려면 윈도우가 이동중일 때의 이벤트가 필요한데 말이죠.

아래 코드는 별다른 로직은 없고 윈도우 메시지를 직접 받아서 처리하는 코드입니다.

간단히 코드를 설명하면 WndProc 함수를 오버라이드해서 WM_WINDOWPOSCHANGING(윈도우가 이동중) 메시지를 받습니다.

그리고 SetDockWindow() 함수를 호출하는데 첫번째 매개변수에는 자석윈도우로 만들 Form을 넘겨줍니다. 두번째 매개변수는 윈도우가 바탕화면 가장자리에 어느정도 가까이 가면 붙도록 할 것인지를 결정하는 수치로 픽셀단위의 정수형 값을 넘겨줍니다. 마지막 매개변수는 WndProc 함수에서 받은 Message 객체를 그대로 전달해줍니다.

SetDockWindow() 함수에서는 Screen.FromHandle()을 이용해서 현재 폼이 위치한 화면의 작업 영역을 얻어옵니다. 이렇게 함으로써 듀얼모니터 지원이 가능합니다.

나머지 코드들은 그냥 좌표 계산이 전부인데 Math.Abs() 함수를 써서 윈도우가 화면안에 있을때나 바깥에 있을 때 모두 자석효과가 가능하도록 처리해줍니다.

01 public const Int32 WM_WINDOWPOSCHANGING = 0x0046;
02   
03 [StructLayout(LayoutKind.Sequential)]
04 public struct WINDOWPOS
05 {
06     public IntPtr hwnd;
07     public IntPtr hwndInsertAfter;
08     public int x;
09     public int y;
10     public int cx;
11     public int cy;
12     public int flags;
13 }
14           
15 protected override void WndProc(ref Message m)
16 {
17     switch(m.Msg)
18     {
19         case WM_WINDOWPOSCHANGING:
20             SetDockWindow(this, 25, ref m);
21             break;
22     }
23     base.WndProc(ref m);
24 }
25   
26 private void SetDockWindow(Form form, int dockMargin, ref Message message)
27 {
28     //현재 Form이 위치한 화면의 작업영역 가져옴(WorkingArea = 작업표시줄을 제외한 영역)
29     Rectangle currentDesktopRect = (Screen.FromHandle(form.Handle)).WorkingArea;
30               
31     WINDOWPOS winPos = (WINDOWPOS)message.GetLParam(typeof(WINDOWPOS));
32   
33     //left
34     if (Math.Abs(winPos.x - currentDesktopRect.Left) <= dockMargin)
35     {
36         winPos.x = currentDesktopRect.Left;
37     }
38   
39     //top
40     if (Math.Abs(winPos.y - currentDesktopRect.Top) <= dockMargin)
41     {
42         winPos.y = currentDesktopRect.Top;
43     }
44   
45     //right
46     if (Math.Abs(winPos.x + winPos.cx - currentDesktopRect.Left - currentDesktopRect.Width) <= dockMargin)
47     {
48         winPos.x = currentDesktopRect.Right - winPos.cx;
49     }
50   
51     //bottom
52     if (Math.Abs(winPos.y + winPos.cy - currentDesktopRect.Top - currentDesktopRect.Height) <= dockMargin)
53     {
54         winPos.y = currentDesktopRect.Bottom - form.Bounds.Height;
55     }
56   
57     Marshal.StructureToPtr(winPos, message.LParam, false);
58     message.Result = (IntPtr)0;
59 }
(사용언어 / 제작툴 / .Net Framework버전 : C# / VS2010 / 2.0)


출처 : http://www.gungume.com/187
반응형
Posted by blueasa
, |

닷넷 경향

.NET Framework 3.0이 나왔습니다만, WPF 같은 최신 기술은 거의 윈도우 비스타에서만 적용되기 때문에 2.0을 주로 씁니다. 오래 전에 닷넷을 도입한 곳은 1.1을 아직 쓰기도 하구요. 저는 2.0을 권합니다.


추천 서적

제가 C# 공부할 때는 .NET Framework 1.1이었기 때문에 요즘엔 입문용으로 어느 책이 좋은지 모르겠습니다. 그래도 아래 두 권 정도는 읽어두시면 좋습니다.

  • Effective C#1

    필독서! 이 책 안 읽고 닷넷이 느리다는 둥의 소리를 하면 한대 맞아야 함. -_-;;

  • Head First Design Patterns2

    디자인 패턴을 하루면 익힐 수 있습니다. 예제가 전부 자바로 구성되어 있지만, 정말 조금만 손보면 C# 코드가 됩니다. 자바 코드를 어떻게 C# 코드로 바꿔야 하는지 모르겠다 하시는 분은 제가 쓴 Converting C# to Java3를 읽어보세요.

입문 시기가 지난 후에 닷넷 서적을 살 땐, 용도에 맞춰 잘 골라야 합니다. ASP.NET, XML Webservices 등 각 분야마다 유명한 책이 따로 있습니다.


공부용으로 볼만한 샘플 코드

System Monitor4

  • 마소 칼럼5 쓸 때 써먹었던 예제 코드입니다.

    이 정도의 기능을 이토록 간단하게 만들 수 있구나!라는 생각이 드실 겁니다. 디자인 패턴을 어떻게 활용하는지 제대로 보여주는 예제입니다.


추천 사이트 및 라이브러리

  • Microsoft Patterns & Practices6

    북마크 해둘 만한 사이트.

    밑에 소개할 Enterprise Library를 비롯해 다양한 라이브러리를 무료로 제공하고, 디자인 패턴 등과 관련된 읽어볼 만한 문서도 많습니다.

  • MSDN Magazine7

    모르시는 분 계시나요? 요즘은 한국어로도 기사가 제공됩니다.

  • CodePlex8

    오픈 소스 프로젝트가 활발히 진행되고 있는 사이트입니다. 소스포지와 비슷합니다.

  • Enterprise Library9

    Microsoft Patterns & Practices 팀이 만든 기업용 소프트웨어 라이브러리입니다.

    캐싱, 데이터베이스, 예외처리, 로깅, 암호화 라이브러리 등을 제공하는데, 특히 데이터베이스, 예외처리, 그리고 로깅 라이브러리는 한번쯤 도입을 고려해봐야 합니다. 이 세 개의 라이브러리만 도입해도 개발 시간을 줄이고 코드를 깔끔하게 유지할 수 있습니다.

    단점.
    • 관련 문서가 영어로만 제공된다는 점

    • 기존 Entlib의 기능을 확장하려면 디자인 패턴을 숙지하고 있어야 한다는 점


개발 도구

  • Visual Studio 사용자를 위한 리팩토링 도구10

    Visual Studio 2005에 기본 탑재된 리팩토링 기능은 너무 미흡하죠.

    [스크린캐스트] C# 리팩토링11를 보시면 어떻게 활용하는지 감 잡을 수 있을 겁니다.

  • [Redbook] 공통 도구 집합 - 윈도우 편12

    제가 인턴할 때 쓴 글이죠? 기억하시나 모르겠네요. 꼭 C#용 도구만 다룬 글은 아닙니다만, 제가 C# 프로그래밍할 때 많이 쓰던 도구를 소개합니다.특히 정규식 도구나 웹 개발 도구를 많이 썼었죠.

  • CruiseControl .NET13

    통합 빌드 서버입니다. 하나 장만해둬야 하는 필수품입니다. 한번 쓰기 시작하면 코드의 품질이 점점 나아지는 걸 체감하실 겁니다. 이쯤에서 광고 한번 하자면, 제가 번역한 Ship It!14을 읽어보시면 왜 통합 빌드 서버가 필요한지 이해하실 수 있습니다. ^^

  • NUnit15

    Visual Studio 2005부터 단위테스트 프레임워크가 제공되니 꼭 NUnit를 쓸 필요는 없습니다. 하지만 .NET Framework 1.1 때만 하더라도 필수 품목이었습니다.

  • NAnt16

    빌드 스크립트 도구입니다. Visual Studio에 빌드 버튼이 있는데, 왜 이런 게 필요하냐라고 물으신다면 다시 한번 Ship It!14을 권해드려야겠군요. ^^


추천 글

  • 마이크로소프트웨어 기고 칼럼17

    제가 쓴 글입니다. CLR Profiler, CPU Profiler, Web Application Stress Tool 등을 이용한 성능 분석에 대한 내용이 주를 이룹니다. 이런 말하기 쑥스럽지만, 성능 분석 방법을 다룬 한글 자료로는 아마 이만한 게 없을 겁니다. (돌려 말하면 영문으론 많습니다. ㅠ.ㅠ)

  • 닷넷 프레임워크 기반의 소켓 프로그래밍 가이드18

    제가 쓴 글입니다. C++에서 패킷을 struct로 정의해놓고 소켓 통신을 하는 경우가 많은데, C#에서 동일한 방식을 지원하려면 손이 많이 가서 만들었던 라이브러리입니다.

  • [RedBook C#] 문서 자동화편19

    이것도 인턴할 때 쓴 글입니다. 문서화를 해야 할 때 읽어보시면 좋습니다.

  • C# 성능향상에 관한 글20

    .NET Framework 1.1 때의 글을 모아놓은 것이지만, 지금도 유효할 겁니다.

Links

  1. http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200701040010
  2. http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200508240010
  3. http://kaistizen.net/EE/index.php/project/csharp/csharp_java.htm/
  4. http://blogs.msdn.com/coding4fun/archive/2006/10/31/912382.aspx
  5. http://kaistizen.net/EE/index.php/imaso/200611_system_monitor.html
  6. http://msdn2.microsoft.com/ko-kr/practices/default.aspx
  7. http://msdn.microsoft.com/msdnmag/
  8. http://www.codeplex.com/
  9. http://www.codeplex.com/entlib
  10. http://kaistizen.net/EE/index.php/weblog/comments/refactoring_tools_for_visual_studio/
  11. http://kaistizen.net/EE/index.php/weblog/comments/screencast_csharp_refactoring/
  12. http://kaistizen.net/EE/index.php/weblog/comments/redbook_tools_for_windows/
  13. http://cruisecontrol.sourceforge.net/
  14. http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200707250014
  15. http://www.nunit.org/
  16. http://nant.sourceforge.net/
  17. http://kaistizen.net/EE/index.php/imaso/content.html
  18. http://kaistizen.net/EE/index.php/project/csharp/socket_programming_guidelines_on_dotnet.htm/
  19. http://kaistizen.net/EE/index.php/weblog/comments/redbook_csharp_documentation/
  20. http://kaistizen.net/EE/index.php/weblog/comments/csharp_performance_articles/


출처: http://kaistizen.net/ee/index.php/weblo ··· nners%2F


출처 : http://jongkok4.net/76
반응형
Posted by blueasa
, |

Try: Process.GetCurrentProcess().Handle;


출처 : http://www.gamedev.net/community/forums/topic.asp?topic_id=411575
반응형
Posted by blueasa
, |

 

.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
, |

using System;
using System.Windows.Forms;
using System.Threading; // Mutex를 사용하려면 반드시 포함시켜야 합니다.

namespace Test
{
       ///
       /// Test를 위한 UI입니다.
       ///

       public class FormTest : System.Windows.Forms.Form
       {

              //-----------------(중략)-----------------

              ///
              /// 해당 응용 프로그램의 주 진입점입니다. -> 중복 실행 방지
              ///

              [STAThread]
              static void Main()
              {
                     bool bNew;

                     Mutex mutex = new Mutex(true, "Test", out bNew);

                     // 한번만 실행되도록...
                     if (bNew)
                     {
                            Application.EnableVisualStyles();
                            Application.Run(new FormTest());
                            mutex.ReleaseMutex();
                     }
              }

              //-----------------(중략)-----------------

       }
}


//------------------------------------------------------------------------


반응형
Posted by blueasa
, |
protected override void WndProc(ref Message m)
{
       // Listen for operating system messages.
       switch (m.Msg)
       {
              // The WM_ACTIVATEAPP message occurs when the application
              // becomes the active application or becomes inactive.
              case WM_ACTIVATEAPP:

              // The WParam value identifies what is occurring.
              appActive = (((int)m.WParam != 0));

              // Invalidate to get new text painted.
              this.Invalidate();

              break;
       }
       base.WndProc(ref m);
}


참고한 주소: Control.WndProc Method (System.Windows.Forms)


출처 : http://wslee13.blogspot.com/2008/12/c-windows-message-wndproc.html
반응형
Posted by blueasa
, |
반응형
Posted by blueasa
, |

개요

Win32 API를 불러올 때, 함수의 명칭, 인자, 리턴 값을 가지고 불러오게 되어 있다. 하지만, C#에서 타입들이 모두 객체(Object)의 형식이며, 일반적인 C 의 데이터 형과 상이한 모양을 가진다. 이러한 문제들을 해결할 수 있는 것이 PInvoke 기능이다.

 

PInvoke( Platform Invocation Service)는 관리화 코드에서 비관리화 코드를 호출할 방법을 제공한다. 일반적인 용도는 Win32 API의 호출을 위해 사용한다.

 

namespace PinvokeExample

{

using System;

 

             using System.Runtime.InteropServices; // 반드시 입력해야 한다.

 

             public class Win32

             {

                           [DllImport(“user32.dll”)]

                           public static extern int FindWindow(string a, string b);

                          

             }

}

 

위 예제는 FindWindow라는 user32.dll C함수를 사용하는 모습을 보여주고 있다. 실제 FindWindow의 선언은 다음과 같다.

 

             HWND FindWindow(LPCSTR swClassName, LPCSTR swTitle);

 

HWND는 윈도우 핸들을 표현하는 32비트 정수 이므로, int형으로 치환되고 LPCSTR 형은 NULL로 끝나는 문자열을 표현한다. 이때 PInvoke string을 자동으로 LPCSTR로 치환해 주는 역할을 하게 된다.

이 문서에서는 이처럼 Win32 API 함수의 여러 유형들을 어떻게 C#에서 사용 할 것인지에 대하여 알아보자.

 

WIN32 데이터형의 치환

Win32 API에서 일반적으로 사용하고 있는 데이터형은 모두 C#의 데이터 형으로 치환될 수 있다.

 

Win32 API TYPE

C#

BOOL, BOOLEAN

bool

BYTE

byte

CALLBACK

delegate

COLORREF

int

DWORD

int

DWORD_PTR

long

DWORD32

uint

DWORD64

ulong

FLOAT

float

HACCEL

int

HANDLE

int

HBITMAP

int

HBRUSH

int

HCONV

int

(모든 HANDLE 타입) Hxxxx

int

LPARAM

long

LPCSTR

[in] string [out] StringBuilder

LPBOOL

ref bool

이외 LP*

ref 형식

UINT

uint

Uxxxx

unsigned 타입들..

WORD

Short

WPARAM

Uint

 

 

Structure 의 전달

예를 들어 POINT 형의 경우,

typedef struct t_Point {

             int x;

             int y;

} POINT;

 

이것은 기본적으로 다음과 같이 선언될 수 있다.

[순차적]

[StructLayout(LayoutKind.Sequential)]
public struct Point {
      public int x;
      public int y;
}

 

[명시적]

[StructLayout(LayoutKind.Explicit)]
public struct Point {
      [FieldOffset(0)] public int x;
      [FieldOffset(4)] public int y;
}

 

일차적으로 할당되는 메모리 레이아웃이 동일하다면, C#에서 바로 받아 들이 수 있다.

 

// BOOL SetWindowPos(POINT pos); 이런 함수가 있다고 가정하면… ^^

 

[DllImport (“user32.dll”)]

public static extern bool SetWindowPos(Point pos);

 

사용할 함수 이름 바꾸기

여기서 함수의 이름을 바꿔서 사용하고 싶다면 다음과 같이 변경하면 된다.

 

// BOOL SetWindowPos(POINT pos);

 

[DllImport (“user32.dll”, EntryPoint = “SetWindowPos”)]

public static extern bool ShowAt(Point pos);

레퍼런스형 전달하기

 

LPPOINT형은 POINT의 포인터 형이므로 ref Point와 같이 사용 할 수 있다. 실제 사용하는 형식은 다음과 같다.

C 언어의 포인터의 경우 레퍼런스로 사용하려고 하면, ref 키워드를 사용하는 방법이 있다.

// BOOL SetWindowPos(HWND hWnd, LPRECT lpRect);

[DllImport(“user32.dll”)]

public static extern bool SetWindowPos(int hWnd, ref Rect lpRect);

 

Out형 함수 인자 사용하기

MSDN 같은 곳에서 함수의 선언을 살펴보면 다음과 같은 형식의 함수를 볼 수 있을 것이다. 이러한 형식은 레퍼런스 형으로 결과를 함수의 인자에 보내겠다는 말이다. 이러한 형식은 Win32 API에서 많이 쓰이고 있고, 포인터를 사용하므로, 많은 주의를 기울여야 한다.

 

BOOL GetWindowRect(
  HWND hWnd,      // handle to window
  LPRECT lpRect   // window coordinates
);

Parameters

hWnd

[in] Handle to the window.

lpRect

[out] Pointer to a RECT structure that receives the screen coordinates of the upper-left and lower-right corners of the window.

 

여기서 LPRECT는 앞 절에서 설명한 Structure의 전달을 참고하여 치환 될 수 있다.

여기서 lpRect RECT의 포인터이며, GetWindowRect 함수 내에서 이 포인터에 직접 값을 쓰게 되어 있다. 즉 이 포인터는 값을 기록하기 위한 인자이지, 값을 전달하기 위한 인자는 아닌 것이다. 이것은 또 다른 C# 레퍼런스 연산자인 out 키워드를 사용하여 쉽게 해결 할 수 있다.

public static extern bool GetwindowRect(int hWnd, out Rect lpRect);

 

실제 사용하는 모습은 다음과 같다.

public static extern bool GetWindowRect(int hWnd, out Rect lpRect);

public static void UseFunction() {

        Rect _rect; // 값을 대입하지 않아도 된다.

        Win32.GetWindowRect(hwnd, out _rect);

}

 

참고로 ref 키워드는 입력과 출력 둘 다 사용 할 수 있다. 그러나 ref를 사용하는 변수가 값이 설정되어 있다는 가정을 하고 있으므로, 이전에 반드시 어떠한 값을 입력해야 한다.

실제 사용 예는 다음과 같다.

public static extern bool GetWindowRect(int hWnd, ref Rect lpRect);

public static void UseFunction() {

        Rect _rect = new Rect(); // 꼭 값을 대입해야 한다.

       

        _rect.top = 20; _rect.left = 30;

        _rect.bottom = 50; _rect.right = 60;

 

        Win32.GetWindowRect(hwnd, ref _rect);

}

 

여기서 잠깐

대중없이 Rect라는 구조체가 나오는데 이는 API에서 RECT형을 C#으로 바꾸어 사용하는 structure이다. 앞의 예제들은 다음과 같은 선언을 하였다고 가정한다.

[StructLayout(LayoutKind.Explicit)]
public struct Point {
      [FieldOffset(0)] public int top;
[FieldOffset(4)] public int left;
[FieldOffset(8)] public int bottom;
[FieldOffset(12)] public int right;

}

 

 

CALLBACK 함수의 선언

C 언어에서 콜백 함수는 함수 포인터로 존재하게 된다. 이것은 함수 인스턴스의 포인터로, 함수 자체를 전달하게 되는 방식이다. 대표적으로 사용되는 부분은 EnumWindows 함수이다.

// BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam)

이 함수는 현재 열려 있는 모든 윈도우 핸들을 열거하기 위한 함수로 실제 처리하는 부분은 함수 포인터, 즉 콜백함수인 lpEnumFunc에서 처리하게 되어 있다. WNDENUMPROC 타입의 선언은 다음과 같다.

// typedef BOOL (CALLBACK* WNDENUMPROC)(HWND, LPARAM);

public delegate bool Callback(int hWnd, long lParam);

이러한 콜백 함수 역할을 하는 C#의 프리미티브는 delegate이다. CALLBACK delegate로 지환된다.

 

결과적으로 다음과 같이 사용하게 된다.

namespace ada.appshare

{

             public delegate bool Callback(int hwnd, int lParam);

            

             internal class Win32

             {

               

                           internal static extern int EnumWindows(CallBack x, int y);

                           [DllImport("user32.dll")]

 

                public static bool EnumWindowsCallback(int hWnd, int lParam)
                {

                        System.Console.WriteLine(“” + hWnd);

                        return true;

                }

                

             }

 

        public static void Main(String []args)

        {

                Win32.Callback call
= new Win32.Callback(Win32.EnumWindowsCallback);

                Win32.EnumWindows(call, 0);

        }

}

반응형
Posted by blueasa
, |

윈도우에 열려있는 창을 제어하기 위한 핸들값을 가져오는 API 함수
창의 클래스명이나 캡션명은 Spy++ 로 알 수 있다.
※주의사항
함수명의 대소문자가 틀리면 안된다.
FindWindowEx() 함수를 FindWindowEX() 로 했더니 에러 발생.

[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
-> 창의 클래스명이나 창 캡션명으로 최상위 핸들값을 가져옴.
예)
int i = FindWindow(null, "Windows Messenger");  // 창의 캡션명으로 찾기
int j = FindWindow("MSBLClass", null);  // 창의 클래스명으로 찾기

[DllImport("user32.dll")]
public static extern int FindWindowEx(int hWnd1, int hWnd2, string lpsz1, string lpsz2);
-> 인자값으로 받은 핸들의 자식 핸들을 가져옴. lpsz1 은 클래스명, lpsz2 는 캡션명.
예)
int hw2 = FindWindowEx(hw1, 0, "PluginHostClass", null);  // PluginHostClass 의 핸들값 가져옴.
int hw3 = FindWindowEx(hw2, 0, "MSBLGeneric", null);  // MSBLGeneric 클래스의 핸들값.
int hw4 = FindWindowEx(hw3, 0, MSBLGeneric", "Task List");  // MSBLGeneric 클래스이며 Task List 캡션명의 핸들값. 
반응형
Posted by blueasa
, |