使用JNA调用CreateWindowEx创建固定尺寸无框窗口的尺寸异常问题
解决JNA创建无框窗口尺寸不符的问题
我明白你遇到的困扰了——用JNA创建窗口后移除标题栏,结果窗口实际尺寸和预期的50x50对不上,哪怕Spy++显示样式和JFrame的无框窗口完全一致。这其实是Windows窗口尺寸计算的典型坑,跟非客户区(标题栏、边框)的逻辑有关,我来给你捋清楚怎么解决:
问题根源
当你调用CreateWindowEx时传入的宽高参数,指的是**整个窗口(包含标题栏、边框等非客户区)**的尺寸。而你后来移除WS_CAPTION后,Windows并不会自动调整窗口大小来适配“无框”的新样式——原来的窗口尺寸是按有标题栏的情况计算的,移除标题栏后非客户区消失,但窗口整体尺寸没改,导致实际显示的内容区域(客户区)大小和预期不符。
而JFrame的setUndecorated(true)之所以能正确显示50x50,是因为Swing内部已经帮你处理了窗口样式和尺寸的适配逻辑,自动调整了窗口的实际大小。
两种解决方法
方法1:创建窗口时直接使用无框样式
最直接的方式是一开始就创建无框窗口,避免后续修改样式带来的尺寸问题。使用WS_POPUP样式(无标题栏、无边框),这样传入的宽高就是客户区的尺寸:
String windowClass = "NewWindowClass"; HMODULE hInst = Kernel32.INSTANCE.GetModuleHandle(""); WNDCLASSEX wClass = new WNDCLASSEX(); wClass.hInstance = hInst; wClass.lpfnWndProc = Main.this; wClass.lpszClassName = windowClass; User32.INSTANCE.RegisterClassEx(wClass); // 使用WS_POPUP + WS_VISIBLE创建无框窗口,尺寸直接对应客户区 int windowStyle = User32.WS_POPUP | User32.WS_VISIBLE; HWND hWnd = User32.INSTANCE.CreateWindowEx( User32.WS_EX_TOPMOST, windowClass, "This is the window title", windowStyle, 0, 0, 50, 50, null, null, hInst, null ); User32.INSTANCE.ShowWindow(hWnd, 1);
方法2:修改样式后重新计算并调整窗口尺寸
如果你需要保留原有的创建流程,修改样式后必须手动调整窗口大小并刷新框架。步骤如下:
- 移除标题栏和边框样式(不止
WS_CAPTION,还要去掉WS_BORDER,否则仍会有细边框影响尺寸) - 使用
AdjustWindowRectEx计算适配无框样式的窗口尺寸 - 调用
SetWindowPos刷新窗口并设置正确尺寸
代码示例:
// 你的原创建窗口代码... HWND hWnd = User32.INSTANCE.CreateWindowEx(User32.WS_EX_TOPMOST, windowClass, "This is the window title", 0, 0, 0, 50, 50, null, null, hInst, null); User32.INSTANCE.ShowWindow(hWnd, 1); // 修改窗口样式,移除标题栏和边框 long style = User32.INSTANCE.GetWindowLong(hWnd, User32.GWL_STYLE); style &= (~User32.WS_CAPTION & ~User32.WS_BORDER); User32.INSTANCE.SetWindowLong(hWnd, User32.GWL_STYLE, (int) style); // 计算无框窗口需要的尺寸(确保客户区为50x50) RECT clientRect = new RECT(); clientRect.right = 50; clientRect.bottom = 50; User32.INSTANCE.AdjustWindowRectEx(clientRect, (int) style, false, User32.WS_EX_TOPMOST); // 刷新窗口并设置正确尺寸 User32.INSTANCE.SetWindowPos( hWnd, null, 0, 0, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top, User32.SWP_NOZORDER | User32.SWP_FRAMECHANGED );
关键注意点
- 调用
SetWindowPos时必须加上SWP_FRAMECHANGED标志,告诉Windows重新绘制窗口框架,确保样式修改生效。 - 如果你只移除
WS_CAPTION而保留WS_BORDER,窗口仍会有细边框,导致尺寸还是不符合预期,所以要同时移除WS_BORDER。
这样处理后,你的JNA窗口尺寸应该就和JFrame的无框窗口完全一致了!
内容的提问来源于stack exchange,提问作者Jordan
相关产品推荐
相关产品推荐

