How do I make SetThreadDesktop API work from a console application?

前端 未结 2 1134
旧时难觅i
旧时难觅i 2020-12-12 06:08

I saw Stack Overflow question How to switch a process between default desktop and Winlogon desktop?.

And I have produced a minimal test-case creating a cons

相关标签:
2条回答
  • 2020-12-12 06:41

    The answer by Dmitriy is accurate in that the function fails because the calling thread has windows or hooks, although it doesn't explain how so.

    The reason SetThreadDesktop is failing with ERROR_BUSY is, you have "forms.pas" in your uses list. Although it's missing in the code you posted (semicolon in "uses" clause is also missing hinting more units), the use of the Screen global variable makes it evident that you have "forms" in uses. "Forms" pulls in "controls.pas" which initializes the Application object. In its constructor, the Application creates a utility window for its PopupControlWnd. There may be other windows created but this one is enough reason for the function to fail.

    You use Screen for its width/height. Un-use "forms", you can use API to retrieve that information.

    There are other issues in the code like missing/wrong error checking which have been mentioned in the comments to the question, but they are not relevant to why SetThreadDesktop fails.


    Below sample program demonstrates there's no problem calling SetThreadDesktop in the main thread of a console application, provided there's a desktop with name 'default_set' in the window station in which the program is running and has access rights to.

    program Project1;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      System.SysUtils,
    //  Vcl.Forms,  // uncomment to get an ERROR_BUSY
      Winapi.Windows;
    
    var
      hSaveDesktop, hDesktop: HDESK;
    begin
      hSaveDesktop := GetThreadDesktop(GetCurrentThreadId);
      Win32Check(hSaveDesktop <> 0);
    
      hDesktop := OpenDesktop('default_set', 0, True, GENERIC_ALL);
      Win32Check(hDesktop <> 0);
      try
        Win32Check(SetThreadDesktop(hDesktop));
        try
    
          // --
    
        finally
          Win32Check(SetThreadDesktop(hSaveDesktop));
        end;
      finally
        Win32Check(CloseDesktop(hDesktop));
      end;
    end.
    
    0 讨论(0)
  • 2020-12-12 06:52

    From the SetThreadDesktop() documentation:

    The SetThreadDesktop function will fail if the calling thread has any windows or hooks on its current desktop (unless the hDesktop parameter is a handle to the current desktop).

    0 讨论(0)
提交回复
热议问题