gpt4 book ai didi

C++ 使用 ShowWindow 恢复窗口会禁用其最小化功能

转载 作者:行者123 更新时间:2023-11-28 02:41:32 24 4
gpt4 key购买 nike

我在仅保持一个窗口实例运行时遇到问题。

实现细节:我有一个 C++ 应用程序,它在任务栏中显示为一个图标。双击图标,我使用 ShellExecuteW 函数打开一个新的 delphi 窗口。现在我已经实现了一种逻辑,每当用户双击该图标时,它只会打开一个窗口实例,避免启动多个窗口。如果用户双击该图标,并且已经有一个窗口打开,它会将窗口置于最前面,或者如果它已最小化,它将恢复窗口。

下面的代码展示了我是如何实现上述逻辑的,它是在双击图标时触发的:

///////////////////////Double Click Code starts/////////////////////////
HWND hWnd = NULL;
HWND hWndFirst = NULL;
DWORD dw = FindProcessId("abc.exe");
if(dw == 0)
{
//Open new window
ShellExecuteW(0, L"open", acExePath, acParams, acFullPath, SW_SHOW);
hWndFirst = NULL;
}
else
{
//Open existing window
hWnd = hGetWindowHandleOfProcess(dw);
if(hWndFirst == NULL) hWndFirst = hWnd;

if(hWndFirst != hWnd)
{
//This is just a small work-around as minimizing the window was changing
//it's window handle. So I preserve the window handle the first time and
//use it whenever the window is minimized (i.e. the handle is changed)
SetForegroundWindow(hWndFirst);
ShowWindow(hWndFirst, SW_RESTORE);
}
else
{
SetForegroundWindow(hWnd);
ShowWindow(hWnd, SW_RESTORE);
}
}
///////////////////////Double Click Code ends///////////////////////////

///////////////////////Supporting functions/////////////////////////
struct ProcessHandleData
{
unsigned long lProcessId;
HWND hProcessWindowHandle;
};
//Finds the process id when given the process name
DWORD FindProcessId(char* pcProcessName)
{
char* pcBegin = strrchr(pcProcessName, '\\');
if(pcBegin)
pcProcessName = pcBegin+1;

PROCESSENTRY32 sProcessInfo;
sProcessInfo.dwSize = sizeof(sProcessInfo);

HANDLE sProcessesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if ( sProcessesSnapshot == INVALID_HANDLE_VALUE )
return 0;

Process32First(sProcessesSnapshot, &sProcessInfo);
if ( !strcmp(pcProcessName, sProcessInfo.szExeFile) )
{
CloseHandle(sProcessesSnapshot);
return sProcessInfo.th32ProcessID;
}

while ( Process32Next(sProcessesSnapshot, &sProcessInfo) )
{
if ( !strcmp(pcProcessName, sProcessInfo.szExeFile) )
{
CloseHandle(sProcessesSnapshot);
return sProcessInfo.th32ProcessID;
}
}
CloseHandle(sProcessesSnapshot);
return 0;
}

//Search predicate for EnumWindows function
BOOL CALLBACK bEnumWindowsSearcher(HWND handle, LPARAM lParam)
{
ProcessHandleData& sProcesshandleData = *(ProcessHandleData*)lParam;
unsigned long lProcessId = 0;
GetWindowThreadProcessId(handle, &lProcessId);
if (sProcesshandleData.lProcessId != lProcessId)
return true;
sProcesshandleData.hProcessWindowHandle = handle;
return false;
}

//Gets the window handle of the process (input process id)
HWND hGetWindowHandleOfProcess(unsigned long lProcessId)
{
ProcessHandleData sProcessHandleData;
sProcessHandleData.lProcessId = lProcessId;
sProcessHandleData.hProcessWindowHandle = 0;
EnumWindows(bEnumWindowsSearcher, (LPARAM)&sProcessHandleData); //enumerate all windows
return sProcessHandleData.hProcessWindowHandle;
}

问题:上面的代码工作正常。但是我面临一个问题。如果打开的窗口不是事件的或在任何窗口后面,上面的代码将它带到前面(如预期的那样)。但是,如果我最小化窗口并双击该图标,它会恢复窗口并将其置于最前面(同样符合预期)。但是执行此操作后,我无法再使用窗口右上角的最小化栏将窗口最小化。有些东西禁用(不是物理上)窗口的最小化栏。

在这方面,我们将不胜感激。如果您需要有关该问题的更多信息,请告诉我。

非常感谢。

PS:上面的代码不完全是我的,我研究了各种网站,得到了运行问题的各个部分的代码。

最佳答案

问题的根源在于您正在以错误的方式从错误的进程中恢复之前的窗口。按照您的方式进行操作,前一个窗口的状态会不同步,这就是最小化停止工作的原因。

相反,设计您的应用程序,以便新实例可以将自定义窗口消息(或您选择的任何其他形式的 IPC)发送到先前的实例,并且响应该消息,先前的实例可以使用 Application ->Restore()SetForegroundWindow() 以正确恢复自身。

此外,您的整个流程枚举逻辑简直是矫枉过正。

尝试更像这样的东西:

const UINT uiMyMsg = RegisterWindowMessage(TEXT("MY_RESTORE_MSG"));
...

if (!FindProcessId("abc.exe"))
{
//Open new window
ShellExecuteW(0, L"open", acExePath, acParams, acFullPath, SW_SHOW);
}
else
{
if (uiMyMsg != 0)
PostMessage(HWND_BROADCAST, uiMyMsg, 0, 0);
}

然后在 abc.exe 中,执行如下操作:

const UINT uiMyMsg = RegisterWindowMessage(TEXT("MY_RESTORE_MSG"));

__fastcall TMainForm::TMainForm(TComponent *Owner)
: TForm(Owner)
{
Application->HookMainWindow(&AppHook);
}

__fastcall TMainForm::~TMainForm()
{
Application->UnhookMainWindow(&AppHook);
}

bool __fastcall TMainForm::AppHook(TMessage &Message)
{
if ((Message.Msg == uiMyMsg) && (uiMyMsg != 0))
{
ShowMe();
return true;
}
return false;
}

void __fastcall TMainForm::WndProc(TMessage &Message)
{
if ((Message.Msg == uiMyMsg) && (uiMyMsg != 0))
ShowMe();
else
TForm::WndProc(Message);
}

void __fastcall TMainForm::ShowMe()
{
Application->Restore();
if (WindowState == wsMinimized)
WindowState = wsNormal;
Show();
SetForegroundWindow(Handle);
}

关于C++ 使用 ShowWindow 恢复窗口会禁用其最小化功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25807661/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com