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 함수이다.
1. 먼저 ActiveSync를 실행해 주세요 (Windows Mobile 6.x 기준 입니다)
2. ActiveSync 메뉴 에서 [서버 소스 추가] 혹은 [Add Server Source...]을 눌러주세요.
3. 자신의 구글 메일 주소를 입력합니다
하단에 [Attempt to detect Exchange Server Settings Automatically] 가 체크되어 있는데...
한글판에는 [Exchange Server 설정 자동 검색]으로 간단하게 나와있습니다....
아무튼 체크... (기본으로 체크 되어 있습니다)
3. [User name] 혹은 [사용자 이름]에 자신의 Gmail 주소
[Password] 혹은 [암호]에 Gmail의 암호를 입력합니다
[Domain] 혹은 [도메인]은 빈칸으로 유지합니다
[Save password] 혹은 [암호 저장]은 체크하여 자동화 동기가 이루어지게 합니다
4. 마지막으로 [Server address] 혹은 [서버 주소]에 m.google.com 을 입력하고
[SSL 암호화]에 체크 하여 줍니다
5. 마지막으로 동기화가 필요한 항목 [Contacts] 혹은 [연락처]
[Calendar] 혹은 [일정]을 체크하고 [Finish] 혹은 [마침]을 누릅니다
6. Microsoft Exchange를 통해 정보가 동기화 되는 것을 확인 할 수 있습니다
설치 완료 후 가장 먼저 해 본 것이 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: