简体   繁体   中英

EnableWindow(hWnd, false) doesn't disable keyboard input

I am attempting to disable a window under certain conditions using EnableWindow(hWnd, false);

According to the documentation , this should "disable mouse and keyboard input to the specified window".

The problem I am seeing is that it does, in fact, disable like it says, except if the cursor is currently inside of a text box in the window and the window has the focus that does not get disabled. I was thinking of doing some sort of code to take the focus off of the window as well.

Is there a better way to go about this?

Note: The window being disabled is a binary ran via _spawnl() .

I'm not sure if this is a Windows feature or a bug. Either way, disabling the foreground window is not a good idea.

If you are able to modify the program you start with _spawnl() then that is a better solution. You could make it respond to WM_APP or something like that when you need to control it.

If it is a 3rd-party application then you are left with hacks.

You could try to change the foreground window with SetForegroundWindow but this will only work if you do it very soon after _spawnl() before your thread loses the foreground lock. Using LockSetForegroundWindow before _spawnl() might be able to help you keep the lock longer. There are also various other hacks to change the foreground with AttachThreadInput etc.

If you don't want to change the foreground I was able to come up with a workaround:

  ShellExecute(NULL, NULL, TEXT("Notepad"), NULL, NULL, SW_SHOW);
  Sleep(2000);
  HWND hNP = FindWindow(TEXT("Notepad"), NULL);
  Sleep(2000); // Start typing in Notepad now...
  if (hNP)
  {
    DWORD tid = GetWindowThreadProcessId(hNP, NULL);
    GUITHREADINFO gti;
    gti.cbSize = sizeof(gti);
    if (tid && GetGUIThreadInfo(tid, &gti))
    {
      HWND hChild = NULL;
      if (gti.hwndFocus != hNP && gti.hwndFocus)
      {
        EnableWindow(hChild = gti.hwndFocus, false);
      }
      if (GetForegroundWindow() == hNP)
      {
        SendNotifyMessage(hNP, WM_ACTIVATE, WA_INACTIVE, NULL);
        SendNotifyMessage(hNP, WM_ACTIVATE, WA_ACTIVE, NULL);
        SendNotifyMessage(hNP, WM_SETFOCUS, NULL, NULL);
        // SendNotifyMessage(hNP, WM_NCACTIVATE, false, NULL); // Uncomment to make it look like it is inactive
      }
      EnableWindow(hNP, false);
      if (hChild)
      {
        EnableWindow(hChild, true);
      }
    }
    MessageBox(NULL, TEXT("Done?"), NULL, MB_TOPMOST);
    SetForegroundWindow(hNP);
    PostMessage(hNP, WM_CLOSE, 0, 0);
  }

This is certainly not optimal, it leaves Notepad in a state where it looks like it is enabled but it is really not. The idea is to disable the focused child window and trigger a fake activation change and forcing the focus to change. It might not work with other applications, who knows.

If you are willing to risk a deadlock you can do this instead:

    DWORD tid = GetWindowThreadProcessId(hNP, NULL);
    GUITHREADINFO gti;
    gti.cbSize = sizeof(gti);
    if (tid && GetGUIThreadInfo(tid, &gti))
    {
      if (GetForegroundWindow() == hNP)
      {
        if (AttachThreadInput(GetCurrentThreadId(), tid, true))
        {
          SetFocus(NULL);
          AttachThreadInput(GetCurrentThreadId(), tid, false);
        }
      }
      EnableWindow(hNP, false);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM