c# SendMessage에 IntPtr은 굳이 쓸 필요가 없다

복잡하게 마셜링할 필요 없다. 문자열 보내는데 자꾸들 마셜링으로 코드를 복잡하게 하는 건 메떠드 선언을 잘 모르고 해서 그렇다.

SendMessage의 레퍼런쓰를 보면 변수들의 타입이 제각각이다. Msg를 빼고는 결국 모두 포인터들인데 포인터라는 게 별 게 아니라 메모리상의 주소를 나타내는 정수다. 이런 걸 생각하지 못하고 IntPtr로 받으면 마셜링이라는 샛길로 빠져 헤매게 된다.

string도 그렇다. 이거 자체가 포인터다. 따라서 위와 같이 포인터들은 그냥 int와 string으로 처리하면 된다.

아래 예제는 SendMessage로 문자열을 보내고 엔터를 입력하는 거다.

[DllImport("user32")]
static extern int SendMessage(int hWnd, int Msg, int wParam, string lParam);

private void Form1_Click(object sender, EventArgs e)
{
    SendMessage(handle, 0x000C, 0, new string("abcde")); // wm_settext
    SendMessage(handle, 0x0100, 0x0D, null); // enter wm_KeyDown
}

그러나 SendMessage를 꼭 핸들 값을 찾은 대상에 문자열 보낼 때에만 쓰는 게 아니다. 한 번 선언한 뒤에 다른 목적으로 SendMessage를 써야 할 경우도 있다. 이럴 땐 원칙대로 아래와 같이 써야 한다.

c++ 써버로 보낼 땐 StringToHGlobalAnsi를 써야 한다.

[DllImport("user32")]
static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam); // when non string argument

IntPtr intPtr = Marshal.StringToHGlobalUni("abcde");

SendMessage(textBox1.Text, 0x000C, 0, intPtr);
SendMessage(textBox1.Text, 0x0100, 0x0D, IntPtr.Zero);

참고로 wm_KeyDown를 처리한 뒤에 꼭 wm_KeyUp도 보내야 하는 건 아니다. wm_KeyUp 메씨지를 이어서 보내지 않아도 된다. wm_KeyUp을 하지 않는다고 계속 눌려진 채로 있는 건 아니다.