任务管理器的“切换到”在Windows 7上与DirectX 8应用程序无法正常工作
嗨!我有一个非常具体和奇怪的问题。 我的游戏正在使用DirectX 8.主循环看起来像这样:
while( WM_QUIT != msg.message )
{
if(IsIconic(m_hWnd))
{
if(GetMessage( &msg, NULL, 0U, 0U))
{
// Translate and dispatch the message
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
else
{
// Use PeekMessage() if the app is active, so we can use idle time to
// render the scene. Else, use GetMessage() to avoid eating CPU time.
if(PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE))
{
// Translate and dispatch the message
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
m_pGame->Render();
}
}
}
渲染功能有一些基本功能:
void CGame::Render()
{
//...
HRESULT hr = m_pD3DDevice->TestCooperativeLevel();
if(hr == D3DERR_DEVICENOTRESET)
Reset();
else if( SUCCEEDED( hr ) )
{
// Render
//...
}
//...
}
在全屏模式下,当应用程序失去焦点时(通过Alt + Tab,Windows按钮,Ctrl + Shift + Esc等),它只会最小化,保留在任务栏中并且不使用任何资源。没问题。然后我可以使用Alt + Tab或单击任务栏图标来激活它。也很完美:应用程序激活并全屏重置Direct3D设备。 但使用任务管理器的“切换到”功能会导致奇怪的事情:我的应用程序窗口展开,然后突然最小化! 我试图分析消息输入。看起来我的窗口在激活消息之后接收停用按摩。就像任务管理器一样,激活我的应用程序并再次停用它。
首先我试过
LockSetForegroundWindow(LSFW_LOCK);
它有助于主板集成GPU速度慢的机器,但奇怪的是它对GPU速度更快的机器没有帮助。有时候它有效。但大多数时候它没有。
然后我尝试使用SetForegroundWindow强制将窗口置于前台:
DWORD dwTimeout;
SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &dwTimeout, 0);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, 0);
SetForegroundWindow(hWindow);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)dwTimeout, 0);
LockSetForegroundWindow(LSFW_LOCK);
没有用,所以我尝试了另一个黑客:
HWND hCurrWnd;
int iMyTID;
int iCurrTID;
hCurrWnd = GetForegroundWindow();
iMyTID = GetCurrentThreadId();
iCurrTID = GetWindowThreadProcessId(hCurrWnd,0);
AttachThreadInput(iMyTID, iCurrTID, TRUE);
SetForegroundWindow(hWindow);
AttachThreadInput(iMyTID, iCurrTID, FALSE);
LockSetForegroundWindow(LSFW_LOCK);
不工作。
为什么任务经理行为如此奇怪?我还能做什么?
/////////////////////////////////////////////// //// UPPDATE +解。
所以,我解决了这个问题,虽然我完全不明白为什么它会起作用。 我找到了两个解决方案。它们中的每一个都适用于特定的计算机组。一个用于较旧和较弱的计算机(或较旧的操作系统,如WindowsXP),另一个用于具有更快视频卡和Windows 7的更高级计算机。我设法联合这两个解决方案,现在我的游戏响应“切换到”没有问题。
对于较旧和较弱的计算机,我只将LockSetForegroundWindow(LSFW_LOCK)置于关键位置,如主循环开始之前和WM_ACTIVATE消息中。
对于速度更快的计算机,我只需要调整窗口大小(使其变小),并在停用时调用WindowsUpdate。当我的窗口再次激活设备重置时,在设备重置期间,我只需自动恢复窗口的全屏大小。
LRESULT APIENTRY WndProc(HWND hWnd,UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_ACTIVATE:
if((LOWORD(wParam)==WA_ACTIVE)||(LOWORD(wParam)==WA_CLICKACTIVE))
{
if(m_pGame->m_bFullScreen)
LockSetForegroundWindow(LSFW_LOCK);
break;
}
else
{
if(m_pGame->m_bFullScreen)
{
SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,
128,64,SWP_NOMOVE);
UpdateWindow(hWnd);
};
break;
};
//...
}
}