-
.NET Form에서 MFC DLL 불러오기 두번째Programming/C# 2014. 3. 26. 15:04
2008/09/03 09:46
http://kfship.blog.me/100054512014
이미 지난번 글에서 .NET Form에서 MFC DLL을 불러와 사용하는 방법을 소개한적이 있지만 새롭게 알게된 방법이 있어서 다시한번 글을 쓰려고 한다. 아마도 이번에 소개하려는 방법이 지난번에 소개했던 방법보다 더 쉽고 효율적인 방법이 될 것 같다. 물론 개인적인 생각이긴 하지만..
지난번에 소개했던 방법을 간략하게 이야기 하면 .NET Form에서 Regular Dll로 작성한 Dll을 호출하고, Regular Dll에서 Modaless로 띄운 Dialog에 MFC Extension Dll을 올려놓는 방법이었다. 이 방법은 .NET Form과 Regular DLL 그리고 MFC Extension Dll이 같은 메모리 상에 존재하기 때문에 매개변수를 상호 전달하기 쉽다는 장점이 있지만, MFC Extension Dll에서 발생하는 Window Message를 자기 자신이 받는 것이 아니라 .NET Form에서 받기 때문에 이벤트를 처리하는데 있어서 많은 제약이 있었다. (이벤트 후킹 방법을 사용해면 해결 할 수 있지만, 이것 또한 프로그램의 성능 저하와 Message 가 발생한 컨트롤을 알 수 없다는 단점이 발생한다)
이번에 소개하려는 방법은 지난번과 같이 같은 메모리 상에 MFC Extension Dll을 올려놓는 것이 아니라 서로 다른 Process에 Dll을 올려놓는 방법이다.
1. Dialog 형의 MFC(exe) 프로그램을 생성한다
먼저 exe 파일로 실행할 수 있는 Dialog형의 MFC 프로그램을 생성한다. 현재 생성하는 Dialog 위에 MFC의 Extension Dll을 올려놓을 것이다.
2. C# Form에서 위에서 생성된 MFC 프로그램을 실행한다
System.Diagnostics.Process _process = System.Diagnostics.Process.Start("Proxy.exe");
위와 같이 새로운 Process에 프로그램을 실행한다. 지난번 글에서 Dll 을 실행시켰던것과는 다르게 새로운 Process에 프로그램을 띄우는 이유는 1번 과정에서 생성된 MFC Dialog가 실질적인 Main Form의 역할을 하게 하기 위해서이다. MFC Dialog를 새로운 Process에 띄웠기 때문에 그 위에 다시 띄워지게되는 MFC Extension Dll들은 C#이 아닌 MFC Dialog를 최상위 윈도우로 인식하게 된다
3. MFC Dialog 안에서 C# Form의 핸들을 구해 SetParent 설정을 해준다
MFC Extension Dll을 띄울 프로그램을 새로운 프로세스 위에 띄운것 까지는 좋지만 역시 몇가지 문제가 생긴다. 말 그대로 위의 두 프로그램은 완전 별개의 프로그램이기 때문에 두 창이 동시에 움직이지도 않을 뿐더러 각각 따로 따로 행동하게 된다. 때문에 MFC Dialog 안에서 C# Form을 Parent로 지정하게 되면 MFC Dialog는 C# Form 안으로 들어가게 되며 마치 두 프로그램이 같은 프로그램인것처럼 행동하게 된다.
//.NET 폼의 핸들을 가져온다
g_hMain = ::FindWindow(NULL, "MainForm");
if(g_hMain != NULL)
{
//.NET 폼을 Parent로 설정
::SetParent(GetSafeHwnd(), g_hMain);
//현재 MFC폼의 Handle을 .NET 폼으로 보낸다
::SendMessage(g_hMain, WM_HANDLE, (WPARAM)GetSafeHwnd(), 0);
}
한가지 설명이 안된것이 있는데 SetParent로 .NET Form을 Parent로 설정해준 이후에 .NET Form에도 현재 Dialog의 핸들을 알려주기위해 현재 Dialog의 핸들값을 SendMessage로 .NET Form에 전송한다. WM_HANDLE 값은 사용자가 알맞게 정의한 사용자 정의 Message이다.
TIP. 여기서 MFC Dialog의 Style에서 Title Bar를 표시해주지 않으면 MFC Dialog는 움직이거나 크기 조정을 할 수 없게 된다. 이 상태에서 .NET Form의 Size가 변경될 때 마다 Message를 호출해서 MFC Dialog의 Size를 알맞게 변경해준다면 두개의 프로그램은 완벽히 같은 프로그램으로 보이게 된다.
4. MFC Dialog에서 전송된 Dialog의 핸들값 받아서 전역변수로 선언하기
MFC 프로그램에서 SendMessage로 전송된 Message를 받기 위해서는 .NET의 WndProc 함수를 재정의 해야한다. 또한 계속해서 MFC Dialog와 통신하기 위해서는 Dialog의 핸들값을 전역번수로 선언해 놓는다
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HANDLE)
{
ProxyHandle = new IntPtr(m.WParam.ToInt32());
}base.WndProc(ref m);
}
위에서 WM_HANDLE 값 역시 MFC Dialog에서 정의한 것과 같은 값으로 정의해 놓는다
private const int WM_HANDLE = 0X500; 이 같은 방식으로 저장하면 된다.
위에서 ProxyHandle은 전역변수로 선언되어 있는 Dialog 핸들변수이다 타입은 IntPtr 형이다.
5. .NET Form에서 MFC Dialog로 Messaage 전송하기
MFC Dialog에서 .NET Form으로 메시지를 보내는 방식은 살펴봤기 때문에 .NET에서 MFC Dialog로 메시지를 전송하는 방식만 알게된다면, 우리는 .NET Form과 MFC Dialog 두 윈도우가 서로 호출이 가능하도록 프로그래밍 할 수 있다. .NET에서 MFC Dialog로 Message를 전송하기 위해서는 MFC Dialog에서와 마찬가지로 SendMessage를 이용해야 한다. 하지만 .NET Framework에는 Sendmessage를 전송해주지 않기 때문에 어쩔 수 없이 Window Api를 불러와 이용해야 한다. 방법은 간단하다.
우선 이와 같은 인터페이스를 선언해준다. using System.Runtime.InteropServices; 그리고 나서
[DllImport("User32.dll")]
public extern static long SendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
DllImport를 이용해 Window Api를 부르면 된다.
이후에는 SendMessage를 클래스 안에서 자유롭게 사용하면 된다. 직접 사용하는 방법을 살펴보면 아래와 같다.
SendMessage(ProxyHandle, WM_FORMRESIZE, new IntPtr(this.Width), new IntPtr(this.Height));
위의 명령을 살펴보면 먼저번에 받아온 MFC Dialog의 핸들로 개발자가 정의한 WM_HANDLE 이라는 Message를 전송한다. 이 때 WPARAM 값은 현재 Form의 Width 값, LPARAM 값은 현재 Form의 Height값으로 설정한다.
6. MFC Dialog에서 .NET Form으로 부터 온 Message 받기
.NET Form으로 부터 전송된 Message는 WindowProc 함수를 재정의해서 받는다.
LRESULT CKOLAS3_PROXYDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_FORMSIZECHANGE)
{
DialogResize((INT)wParam, (INT)lParam,);
}
return CDialog::WindowProc(message, wParam, lParam);
}
위에서 DialogResize 함수는 개발자가 임의로 정의한 함수이다. message와 필요하다면 wParam, lParam을 이용해 Message의 종류를 구분해 각각의 Message에 맞는 처리를 해주면 된다.
7. WPARAM, LPARAM값 이외의 형태 전송하기
위의 방식과 같이 .NET Form과 MFC Dialog가 통신한다면 두 윈도우는 숫자 형태의 자료를 최대 2개까지밖에 전송하지 못하는 한계를 갖게 될 것이다. 그렇다면 그 밖에 문자열과 같은 자료를 어떻게 전송할 수 있을까.. 몇가지 해결방안이 있겠지만 여기서 소개하고 싶은 방법은 WM_COPYDATA 를 이용하는 방법이다. 이에 대한 방법은 직접 기록하지 않고 관련 페이지를 링크하도록 하겠다. CODEPROJECT 사이트에서 WM_COPYDATA로 검색해보면 쉽게 위의 자료를 찾을 수 있을 것이다.
http://www.codeproject.com/csharp/wm_copydata_use.asp
일단 위와 같이 두 윈도우간에 통신이 가능하다면, MFC Dialog 위에 Extension Dll을 올려놓기만 하면 된다. Dialog와 Dll은 둘 다 모두 MFC 기반이기 때문에 통신하는데 큰 제약이 없다.출처: http://blog.naver.com/kfship/100054512014
'Programming > C#' 카테고리의 다른 글
C# 간단정리 (0) 2014.03.26 .NET 프로그램에서 확장(Extension) DLL 불러오기 (0) 2014.03.26 대화창 자동 스크롤 (0) 2013.12.12 String Builder (0) 2013.12.12 명명 규칙 (C#) (0) 2013.11.13