所以我在win32 c 中創建了一個全屏功能:
uint8_t isFullscreen = 0;
RECT winRect; //Current Window Rect
RECT nonFullScreenRect; //Rect Not In Full Screen Position (used to restore window to not full screen position when coming out of fullscreen)
uint32_t screen_width = DEFAULT_SCREEN_WIDTH;
uint32_t screen_height = DEFAULT_SCREEN_HEIGHT;
void Fullscreen( HWND WindowHandle )
{
isFullscreen = isFullscreen ^ 1;
if( isFullscreen )
{
//saving off current window rect
nonFullScreenRect.left = winRect.left;
nonFullScreenRect.right = winRect.right;
nonFullScreenRect.bottom = winRect.bottom;
nonFullScreenRect.top = winRect.top;
SetWindowLongPtr( WindowHandle, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE ); //causes a resize msg
HMONITOR hmon = MonitorFromWindow(WindowHandle, MONITOR_DEFAULTTONEAREST);
MONITORINFO mi = { sizeof( mi ) };
GetMonitorInfo( hmon, &mi );
screen_width = mi.rcMonitor.right - mi.rcMonitor.left;
screen_height = mi.rcMonitor.bottom - mi.rcMonitor.top;
MoveWindow( WindowHandle, mi.rcMonitor.left, mi.rcMonitor.top, (int32_t)screen_width, (int32_t)screen_height, FALSE );
}
else
{
SetWindowLongPtr( WindowHandle, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE );
screen_width = nonFullScreenRect.right - nonFullScreenRect.left;
screen_height = nonFullScreenRect.bottom - nonFullScreenRect.top;
MoveWindow( WindowHandle, nonFullScreenRect.left, nonFullScreenRect.top, (int32_t)screen_width, (int32_t)screen_height, FALSE );
}
}
但是,當它進入全屏時,該函式會生成 2 個 WM_SIZE 訊息。而當它視窗化時,它只生成 1。
為什么會這樣?我怎樣才能讓它只為正確的全屏尺寸生成 1 條 WM_SIZE 訊息?
如何自動更新 HWND 的樣式和位置?詢問但沒有人回答
我需要這個的原因是因為我使用的是 DirectX12,并且在 WM_SIZE 上,我在調整所有交換鏈后臺緩沖區的大小之前等待命令佇列末尾的所有信號。而且我不想在切換到全屏模式時兩次調整交換鏈的大小。
case WM_SIZE:
{
screen_width = LOWORD( LParam );
screen_height = HIWORD( LParam );
//DirectX stuff here
}break;
提前致謝!
uj5u.com熱心網友回復:
更新答案:
Win32 API 允許您一次修改一個視窗的引數。當引數被修改時,API 可能會也可能不會更新視窗并觸發一個 WM_SIZE,該 WM_SIZE 將是給定當前引數的視窗大小。
由于要擁有一個完整的全屏視窗,您至少需要進行 2 次呼叫,一次更新 GWL_STYLE,另一次更新 GWL_EXSTYLE,因此您很有可能獲得 2 次 WM_SIZE 呼叫。其中一個會給你沒有選單的視窗大小,另一個是全屏視窗大小。這取決于您呼叫的順序SetWindowLongPtr,但您可能會得到 2 WM_SIZE 并且只有第二個是“正確的”,即您最終想要的那個。
對您的問題更可靠的解決方案是在 Main.cpp 頂部使用一個變數:
int isTogglingFullScreen = false;
然后在您的全屏切換代碼中(注意isTogglingFullScreen 設定的位置):
case WM_SYSKEYDOWN:
if (wParam == VK_RETURN && (lParam & 0x60000000) == 0x20000000)
{
// Implements the classic ALT ENTER fullscreen toggle
if (s_fullscreen)
{
isTogglingFullScreen = true;
SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
isTogglingFullScreen = false;
SetWindowLongPtr(hWnd, GWL_EXSTYLE, 0);
int width = 800;
int height = 600;
if (game)
game->GetDefaultSize(width, height);
SetWindowPos(hWnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
ShowWindow(hWnd, SW_SHOWNORMAL);
}
else
{
isTogglingFullScreen = true;
SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_EX_TOPMOST);
SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP);
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
isTogglingFullScreen = false;
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
}
s_fullscreen = !s_fullscreen;
}
break;
最后,在 WM_SIZE 中,更改
else if (!s_in_sizemove && game)
{
game->OnWindowSizeChanged(LOWORD(lParam), HIWORD(lParam));
}
到
else if (!s_in_sizemove && game && !isTogglingFullScreen)
{
game->OnWindowSizeChanged(LOWORD(lParam), HIWORD(lParam));
}
OnWindowSizeChanged()當您切換全屏時,這將給您一個單一的呼叫,并且呼叫將具有正確的最終大小。
--
老答案:
如果你只想觸發一個 WM_SIZE,當你切換到全屏時,你應該這樣做:
SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_EX_TOPMOST);
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
任何SetWindowLongPtr對 GWL_STYLE 的呼叫都會觸發 WM_SIZE,因此請確保它僅使用GWL_EXSTYLE. 例如,如果你都設定GWL_EXSTYLE為你想要的,然后重置GWL_STYLE為 0,你將觸發 WM_SIZE 兩次。
為了更清楚:
- 不要在 SetWindowLongPtr 中使用 GWL_STYLE,因為它會觸發無用的 WM_SIZE
- ShowWindow 會觸發 WM_SIZE
- 上面的代碼最終只會觸發一次 WM_SIZE。
原來是YMMV。第一次切換全屏時,完全有可能獲得 2 個 WM_SIZE。一個是原始尺寸,另一個是新尺寸。后續呼叫只會觸發一個 WM_SIZE。
Hence, the really bulletproof solution (which I was using anyway before playing around with the SetWindowLongPtr to answer this question, is to validate that the window size has actually changed. Because one thing that I can guarantee in the above call is that you'll never get more than 1 call with the new size. At most you'll get a WM_SIZE call with the old size, which you'll discard by checking that it's the same as the current size.
If you use the DevicesResources template for DX12, you'll see that there's a check in OnWindowSizeChanged() that does nothing if the size hasn't changed.
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/428297.html
標籤:温纳皮 视觉-C 全屏 directx-12
