我有一些似乎有错误的代码。它不是我写的,实际上它是用 c++ 编写的,直到几周前我还没有用 c++ 编写过任何代码。
我们有一个用于触摸屏的键盘,当需要键盘输入时我们会打开它,不需要时关闭它。我们的软件可以在没有物理键盘的信息亭上使用我们多年前开发的触摸屏键盘(仅限于 az、0-9、enter、shift、tab)。
在某些装有 Windows 7 的计算机上,键盘位于应用程序的“后面”(可能是其他计算机,但在其他操作系统上没有看到问题)。
工作多年。我更新了其他部分以最终与 Windows 7 一起使用,现在在我们 66% 的 Windows 7 安装中,键盘根本没有出现(在应用程序后面)。在我的电脑上,起初我认为它出现了 100% 的时间,但继续测试发现它出现了 95-99% 的时间,因此很难排除故障。
此外,大多数关于 GetForegroundWindow() 的帖子都必须处理向其他应用程序发送或接收消息,而不是关于分层应用程序(就像我需要的那样)。
当我开始时,代码如下所示:
bool ShowKeyBoad(bool Show)
{
int WizHeight = 422;
int KeyWidth,KeyHeight,KeyLeft, KeyTop;
AnsiString Params;
AnsiString ShowFile = GetFullPath(GetExeDir(), "OnscreenKeyboard.exe");
AnsiString HideFile = GetFullPath(GetExeDir(), "bkecekeyboard.exe");
KeyHeight = Screen->Height - WizHeight;
KeyWidth = Screen->Width;
if (KeyWidth > Screen->Width)
KeyWidth = Screen->Width;
KeyLeft = (Screen->Width - KeyWidth) / 2;
KeyTop = (Screen->Height) - KeyHeight;
Params = "x-" + IntToStr(KeyLeft) + " y-" + IntToStr(KeyTop) +
" h-" + IntToStr(KeyHeight) + " w-" + IntToStr(KeyWidth);
if (Show)
{
HWND Hand= GetForegroundWindow();
ShellExecute(NULL, "open", ShowFile.c_str(), Params.c_str(), NULL, SW_SHOWNORMAL);
Sleep(100);
SetForegroundWindow(Hand);
SetActiveWindow(Hand);
}
else
ShellExecute(NULL, "open", HideFile.c_str(), "/stop", NULL, SW_HIDE);
return true;
}
我已经尝试了几件事。
捕获 ShellExecute 的 HWND 并将其传递给 SetActiveWindow(ShellHand) 似乎有一些效果。但仍然不一致。HWND shellHand = ShellExecute(NULL, "open", ShowFile.c_str(), Params.c_str(), NULL, SW_SHOWNORMAL);
在 HWND Hand= GetForegroundWindow() 之前添加 Sleep(25); 对 GUI 产生了最好的影响 - 但我不想依赖恰到好处的时间。
各种互联网搜索向我指出了一些看起来也不错的代码。但它会更改注册表设置,这似乎不是一个明智的选择。
使用该解决方案,我们将 SetForeground 更改为 SetForegroundInternal
void SetForegroundWindowInternal(HWND hWnd)
{
if(!::IsWindow(hWnd)) return;
//relation time of SetForegroundWindow lock
DWORD lockTimeOut = 0;
HWND hCurrWnd = ::GetForegroundWindow();
DWORD dwThisTID = ::GetCurrentThreadId(),
dwCurrTID = ::GetWindowThreadProcessId(hCurrWnd,0);
//we need to bypass some limitations from Microsoft :)
if(dwThisTID != dwCurrTID)
{
::AttachThreadInput(dwThisTID, dwCurrTID, TRUE);
::SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,0,&lockTimeOut,0);
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,0,SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
::AllowSetForegroundWindow(ASFW_ANY);
}
::SetForegroundWindow(hWnd);
if(dwThisTID != dwCurrTID)
{
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,(PVOID)lockTimeOut,SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
::AttachThreadInput(dwThisTID, dwCurrTID, FALSE);
}
}
更新 猜测 Hand = NULL 是我的问题我使代码如下所示:
bool ShowKeyBoad(bool Show)
{
int WizHeight = 422;
int KeyWidth,KeyHeight,KeyLeft, KeyTop;
AnsiString Params;
AnsiString ShowFile = GetFullPath(GetExeDir(), "OnscreenKeyboard.exe");
AnsiString HideFile = GetFullPath(GetExeDir(), "bkecekeyboard.exe");
KeyHeight = Screen->Height - WizHeight;
KeyWidth = Screen->Width;
if (KeyWidth > Screen->Width)
KeyWidth = Screen->Width;
KeyLeft = (Screen->Width - KeyWidth) / 2;
KeyTop = (Screen->Height) - KeyHeight;
Params = "x-" + IntToStr(KeyLeft) + " y-" + IntToStr(KeyTop) +
" h-" + IntToStr(KeyHeight) + " w-" + IntToStr(KeyWidth);
if (Show)
{
HWND Hand;
int intfail=1000; // count down seems correct in this case, usually don't
while (Hand = NULL)
{
if (intfail <=0)
break;
Hand = GetForegroundWindow();
intfail--;
}
if (Hand == NULL)
{
// Send Message to screen giving instructions to try again
return false;
}
ShellExecute(NULL, "open", ShowFile.c_str(), Params.c_str(), NULL, SW_SHOWNORMAL);
Sleep(100);
SetForegroundWindow(Hand);
SetActiveWindow(Hand);
}
else
ShellExecute(NULL, "open", HideFile.c_str(), "/stop", NULL, SW_HIDE);
return true;
}
看来可以解决问题了。