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의 선언은 다음과 같다.
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(
HWNDhWnd,// handle to window
LPRECTlpRect// 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 함수이다.
설치 완료 후 가장 먼저 해 본 것이 VS2005에서 C++ 프로젝트 생성 , C++ 클래스 생성 등
웹 페이지 형식으로 동작되는 기능창이 실행되는가 하는 것 이었습니다.
역시나...
Internet Explorer7과 마찬가지로 버그가 존재하더군요
원인은 VS2005의 위자드 엔진에서 IE8의 IInternetSecurityManager interface의 보안정책에 위반되기 때문이랍니다
해결방법은 아래와 같습니다
Visual C++ 팀이 Visual C++를 사용하는 개발자 분들이 Internet Explorer 8 설치 후에 겪는 문제에 대해 블로그를 통해 우회 방법을 소개했습니다. 방법은 아래와 같습니다.
- regedit 실행
- “HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones”에서 “1000” 키 생성
- DWORD 엔트리 생성 (Name=1207, Type=REG_DWORD, Data=0x000000)
Visual C++ 사용하는 개발자가 Internet Explorer 8을 설치하고 나서, Visual Studio에서 마법사를 통해 함수 추가, 변수 추가, Smart Device 프로젝트 생성, Smart Device 클래스 추가 등과 같은 것을 실행할 때 예기치 않은 메시지와 함께 제대로 동작하지 않는 문제가 있습니다. Internet Explorer의 custom security manager 처리에서 순조롭지 않은 일이 발생했다고 하는데, 좀 더 자세한 것은 지켜봐야겠습니다.
This function is not supported. Instead, your application should call CoInitializeEx using the COINIT_MULTITHREADED constant in the second parameter, like this:
CoInitializeEx(x, COINIT_MULTITHREADED);
If your application uses calls to CoInitialize, you can use a #define directive to map CoInitialize to CoInitializeEx, like this: