C++ GetForegroundWindow不总是正确的?

C++ GetForegroundWindow不总是正确的?,c++,touchscreen,hwnd,C++,Touchscreen,Hwnd,我有一些代码似乎有错误。我没有写,实际上它是在C++中,直到几周前我从未在C++中编写任何代码。 我们有一个用于触摸屏的键盘,当需要键盘输入时,我们会将其打开,当不需要时,我们会将其关闭。我们的软件可以在信息亭上使用,而无需使用多年前开发的触摸屏键盘(限于a-z、0-9、enter、shift、tab) 键盘位于Windows 7的某些计算机上的应用程序“后面”(可能是其他计算机,但在其他操作系统上未发现问题) 工作多年。我更新了其他部分以最终使用Windows7,现在我们安装的Windows7

我有一些代码似乎有错误。我没有写,实际上它是在C++中,直到几周前我从未在C++中编写任何代码。 我们有一个用于触摸屏的键盘,当需要键盘输入时,我们会将其打开,当不需要时,我们会将其关闭。我们的软件可以在信息亭上使用,而无需使用多年前开发的触摸屏键盘(限于a-z、0-9、enter、shift、tab)

键盘位于Windows 7的某些计算机上的应用程序“后面”(可能是其他计算机,但在其他操作系统上未发现问题)

工作多年。我更新了其他部分以最终使用Windows7,现在我们安装的Windows7中有66%的键盘根本没有出现(在应用程序后面)。起初在我的电脑上,我以为它能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;
  } 
  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;
  } 
我试过一些东西。
捕获ShellExecute的HWND并将其传递给SetActiveWindow(ShellHand)似乎有一些效果。但仍然不一致。 HWND shellHand=ShellExecute(NULL,“打开”,ShowFile.c_str(),Params.c_str(),NULL,SW_SHOWNORMAL)

在HWND Hand=getforegroundindow()之前添加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= 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;
  } 
  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;
  } 
bool ShowKeyBoad(bool Show)
{
int WizHeight=422;
int键宽、键高、键左、键顶;
解析参数;
AnsiString ShowFile=GetFullPath(GetExeDir(),“OnscreenKeyboard.exe”);
AnsiString HideFile=GetFullPath(GetExeDir(),“bkecekeyboard.exe”);
KeyHeight=屏幕->高度-WizHeight;
KeyWidth=屏幕->宽度;
如果(键宽度>屏幕->宽度)
KeyWidth=屏幕->宽度;
KeyLeft=(屏幕->宽度-键宽度)/2;
按键高度=(屏幕->高度)-按键高度;
Params=“x-”+IntToStr(键左)+“y-”+IntToStr(键顶)+
“h-”+IntToStr(键高)+“w-”+IntToStr(键宽);
如果(显示)
{
右手;
int intfail=1000;//在这种情况下倒计时似乎是正确的,但通常不正确
while(Hand=NULL)
{ 

如果(intfail
ShellExecute()
不返回
HWND
。其返回值是一个整数错误代码类型,转换为
HINSTANCE
句柄指针(用于向后兼容16位代码)。若要定位生成的进程的
HWND
,请改用
FindWindow()
(可能您在编写该exe之后就知道了它的类名),或者使用
CreateProcess()
,然后调用
EnumWindows()'运行一个
GetWindowThreadProcessId()`循环,查找与生成的进程匹配的
HWND
s。如果您使用
CreateProcess()
ShellExecuteEx())
,您可以访问进程句柄,您可以将其传递到
WaitForInputIdle()
而不是
Sleep()
。我猜HWND Hand=GetForeGroundIndow()中的“Hand”=NULL就是这个问题。为什么它只在某些Windows 7安装中出现是非常奇怪的。