[WinAPI] C#에서 GetWindowLong(), SetWindowLong() 호출

0. 요약

C#에서 Get/SetWindows()를 호출할 경우 32/64비트에 따라 호출할 API가 다르므로 아래와 같이 호출하자.

public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size == 8)
return GetWindowLongPtr64(hWnd, nIndex);
else
return GetWindowLongPtr32(hWnd, nIndex);
}
public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, long dwNewLong)
{
if (IntPtr.Size == 8)
return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
else
return SetWindowLongPtr32(hWnd, nIndex, (uint)dwNewLong);
}
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
public static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
public static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
public static extern IntPtr SetWindowLongPtr32(IntPtr hwnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
public static extern IntPtr SetWindowLongPtr64(IntPtr hwnd, int nIndex, long dwNewLong);

1. 문제

opencv로 화면을 출력하는데 생성하는 윈도우에 타이틀바가 함께 출력이 된다. 이 타이틀바를 완전히 없에려면 API호출이 필요하다. GetWindowLong()으로 윈도우 상태를 땡겨오고 타이틀바 삭제 등 옵션을 설정 후 SetWindowLong()하면 되는 간단한 느낌. 근데 뭐가 잘 안돌아간다. 32/64비트 호환성 문제가 좀 있는 듯 하기도 하고... 공식문서에는 아래와 같이 설명이 되어있다.

참고 포인터 또는 핸들을 검색하는 경우 이 함수는 GetWindowLongPtr 함수로 대체되었습니다. 포인터와 핸들은 32비트 Windows의 경우 32비트, 64비트 Windows에서는 64비트입니다. 32비트 및 64비트 버전의 Windows와 호환되는 코드를 작성하려면 GetWindowLongPtr을 사용합니다.

GetWindowLongPtr을 가져다 쓰면 32, 64비트 모두 호환이 될 것 같지만 어쩐일인지, 내가 잘못 가져다 쓴건지 호환지 되지 않는다. 이를 위하여 일단 비트에 관계없이 전체 펑션을 땡겨 놓고, 현재 몇비트에서 실행 중인지 판단한 후 적절한 API를 호출하도록 하도록 한다.

public static void RemoveTitleBar(IntPtr hwnd, string windowName)
{
// change style of the child HighGui window
long style = GetWindowLongPtr(hwnd, GWL_STYLE).ToInt64();
style &= ~WS_OVERLAPPEDWINDOW;
style |= WS_POPUP;
SetWindowLongPtr(hwnd, GWL_STYLE, style );
// change style of the parent HighGui window
IntPtr hParent = FindWindow(null, windowName);
style = GetWindowLongPtr(hParent, GWL_STYLE).ToInt64();
style &= ~WS_OVERLAPPEDWINDOW;
style |= WS_POPUP;
SetWindowLongPtr(hParent, GWL_STYLE, style);
}
public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex)
{
if (IntPtr.Size == 8)
return GetWindowLongPtr64(hWnd, nIndex);
else
return GetWindowLongPtr32(hWnd, nIndex);
}
public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, long dwNewLong)
{
if (IntPtr.Size == 8)
return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
else
return SetWindowLongPtr32(hWnd, nIndex, (uint)dwNewLong);
}
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
public static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
public static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
public static extern IntPtr SetWindowLongPtr32(IntPtr hwnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
public static extern IntPtr SetWindowLongPtr64(IntPtr hwnd, int nIndex, long dwNewLong);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

2. 결론

근데 왜 이렇지? get/set 모두 ptr로 끝나는 함수를 호출하면 잘 될것 같은데 끝

참조

[1] https://stackoverflow.com/questions/65138624/how-to-remove-titlebar-in-opencvsharp-cv2-imshow-c-sharp-wpf

[2] https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/nf-winuser-getwindowlonga