[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);elsereturn GetWindowLongPtr32(hWnd, nIndex);}public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, long dwNewLong){if (IntPtr.Size == 8)return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);elsereturn 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 windowlong style = GetWindowLongPtr(hwnd, GWL_STYLE).ToInt64();style &= ~WS_OVERLAPPEDWINDOW;style |= WS_POPUP;SetWindowLongPtr(hwnd, GWL_STYLE, style );// change style of the parent HighGui windowIntPtr 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);elsereturn GetWindowLongPtr32(hWnd, nIndex);}public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, long dwNewLong){if (IntPtr.Size == 8)return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);elsereturn 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로 끝나는 함수를 호출하면 잘 될것 같은데 끝
참조
[2] https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/nf-winuser-getwindowlonga