Welcome, Guest
Guest Settings
Help

Thread: Trying to make IVirtualDesktopManager work


This question is not answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 4 - Last Post: Jan 30, 2017 11:44 AM Last Post By: Remy Lebeau (Te... Threads: [ Previous | Next ]
John Abels

Posts: 2
Registered: 2/22/17
Trying to make IVirtualDesktopManager work  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 21, 2017 10:51 PM
Hi,

I'm trying to use IVirtualDesktopManager in windows 10. I wrote this unit below, but the function always returns true, even if it is not on the current desktop.
Anyone any ideas?

unit VDMUnit;
 
interface
 
uses ActiveX, Comobj;
 
Const
 IID_VDM: TGUID ='{A5CD92FF-29BE-454C-8D04-D82879FB3F1B}';
 CLSID_VDM: TGUID ='{AA509086-5CA9-4C25-8F95-589D3C07B48A}';
 
type
  {$EXTERNALSYM IVirtualDesktopManager}
  IVirtualDesktopManager = interface(IUnknown)
    ['{A5CD92FF-29BE-454C-8D04-D82879FB3F1B}']
    function IsWindowOnCurrentVirtualDesktop(Wnd:cardinal; var IsTrue: boolean): HResult; stdcall;
    function GetWindowDesktopId(Wnd:cardinal; var DesktopID: cardinal): HResult; stdcall;
    function MoveWindowToDesktop(Wnd:cardinal; PStruture: pointer; DesktopID: cardinal): HResult; stdcall;
  end;
 
function IsOnCurrentDesktop(wnd:cardinal):boolean;
 
implementation
 
var
  vdm:IVirtualDesktopManager;
 
function IsOnCurrentDesktop(wnd:cardinal):boolean;
begin
  CoInitialize(nil);
  OleCheck(CoCreateInstance(CLSID_VDM, nil, CLSCTX_INPROC_SERVER,IVirtualDesktopManager,vdm));
  OleCheck(vdm.IsWindowOnCurrentVirtualDesktop(wnd,result));
  CoUninitialize;
end;
 
end.
 
Remy Lebeau (Te...


Posts: 7,723
Registered: 12/23/01
Re: Trying to make IVirtualDesktopManager work  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 23, 2017 11:12 AM   in response to: John Abels in response to: John Abels
John Abels wrote:
function IsWindowOnCurrentVirtualDesktop(Wnd:cardinal; var IsTrue:
boolean): HResult; stdcall;

This declaration is wrong. The first parameter expects an HWND handle, not a Cardinal integer. The second parameter expects a pointer to a BOOL, not a pointer to a Boolean (BOOL and Boolean are very different data types - BOOL is an alias for LongBool, which is 4 bytes, whereas Boolean is 1 byte instead). Use this declaration instead:

function IsWindowOnCurrentVirtualDesktop(Wnd: HWND; out IsTrue: BOOL): HResult; stdcall;


function GetWindowDesktopId(Wnd:cardinal; var DesktopID:
cardinal): HResult; stdcall;

This declaration is also wrong. The first parameter expects an HWND handle, not a Cardinal. The second parameter expects a pointer to a GUID, not a pointer to a Cardinal. A GUID is a 16-byte record, whereas Cardinal is a 4-byte integer. Use this declaration instead:

function GetWindowDesktopId(Wnd: HWND; out DesktopID: TGUID): HResult; stdcall;


function MoveWindowToDesktop(Wnd:cardinal; PStruture: pointer;
DesktopID: cardinal): HResult; stdcall;

This declaration is also wrong. For starters, this method only has 2 parameters, but you declared 3 parameters. The first parameter expects an HWND handle. The second parameter expects a pointer to a GUID. Use this declaration instead:

function MoveWindowToDesktop(Wnd: HWND; var DesktopID: TGUID): HResult; stdcall;


function IsOnCurrentDesktop(wnd:cardinal): Boolean;

Same thing with the parameter. Use HWND instead of Cardinal. Also, get rid of the Co(Un)Initialize() calls, they don't belong in the function. The caller is responsible for calling them when it decides which COM threading model it wants to use when accessing COM. Individual functions should not make that decisions on the caller's behalf. COM must be initialized on a per-thread basis, so your threads needs to call CoInitialize() before calling IsOnCurrentDesktop().

var
vdm: IVirtualDesktopManager;

This variable belongs inside your IsOnCurrentDesktop() function, not in global memory. You are risking a crash when the compiler tries to release the interface during unit finalization after CoUninitialize() has already been called.

With all of that said, try this code instead:

unit VDMUnit;
 
interface
 
uses
  Windows, ActiveX, Comobj;
 
const
  IID_VDM: TGUID = '{A5CD92FF-29BE-454C-8D04-D82879FB3F1B}';
  CLSID_VDM: TGUID = '{AA509086-5CA9-4C25-8F95-589D3C07B48A}';
 
type
  {$EXTERNALSYM IVirtualDesktopManager}
  IVirtualDesktopManager = interface(IUnknown)
    ['{A5CD92FF-29BE-454C-8D04-D82879FB3F1B}']
    function IsWindowOnCurrentVirtualDesktop(Wnd: HWND; out IsTrue: BOOL): HResult; stdcall;
    function GetWindowDesktopId(Wnd: HWND; out DesktopID: TGUID): HResult; stdcall;
    function MoveWindowToDesktop(Wnd: HWND; var DesktopID: TGUID): HResult; stdcall;
  end;
 
function IsOnCurrentDesktop(wnd: HWND): Boolean;
 
implementation
 
function IsOnCurrentDesktop(wnd: HWND): Boolean;
var
  vdm: IVirtualDesktopManager;
  bOnDesktop: BOOL;
begin
  OleCheck(CoCreateInstance(CLSID_VDM, nil, CLSCTX_INPROC_SERVER, IVirtualDesktopManager, vdm));
  OleCheck(vdm.IsWindowOnCurrentVirtualDesktop(wnd, bOnDesktop));
  Result := bOnDesktop;
end;
 
end.


Lastly, note that IVirtualDesktopManager is only available on Windows 10 and later, so if you don't want your code to crash on earlier Windows versions, you should remove the OleCheck() on CoCreateInstance() so you can handle the error more gracefully, eg:

function IsOnCurrentDesktop(wnd: HWND): Boolean;
var
  vdm: IVirtualDesktopManager;
  hres: HResult;
  bOnDesktop: BOOL;
begin
  hres := CoCreateInstance(CLSID_VDM, nil, CLSCTX_INPROC_SERVER, IVirtualDesktopManager, vdm);
  if Succeeded(hres) then
  begin
    OleCheck(vdm.IsWindowOnCurrentVirtualDesktop(wnd, bOnDesktop));
    Result := bOnDesktop;
  end else begin
    // do something else...
  end;
end;


--
Remy Lebeau (TeamB)
John Abels

Posts: 2
Registered: 2/22/17
Re: Trying to make IVirtualDesktopManager work  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 23, 2017 10:21 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thanks, for the corrections!
I noticed something else strange. When I check if the form (form1.handle) is on the current desktop I always get the answer yes. But when I use application.handle then i get correct answers when the desktop is switched to another desktop.
So seems I can only check application handles?
Remy Lebeau (Te...


Posts: 7,723
Registered: 12/23/01
Re: Trying to make IVirtualDesktopManager work  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 24, 2017 10:14 AM   in response to: John Abels in response to: John Abels
John wrote:

I noticed something else strange. When I check if the form
(form1.handle) is on the current desktop I always get the
answer yes.

If Windows says it is, then it really is. Chances are, the Form's window
got recreated after the current virtual desktop was changed, thus the new
window became associated with the now-active desktop. Remember, TWinControl
can (and sometimes does) recreate its window dynamically (potentially even
multiple times) during the object's lifetime.

But when I use application.handle then i get correct answers
when the desktop is switched to another desktop.

The TApplication window is created only once, at app startup. It is not
recreated dynamically, like TWinControl windows can be.

--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 7,723
Registered: 12/23/01
Re: Trying to make IVirtualDesktopManager work  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 30, 2017 11:44 AM   in response to: John Abels in response to: John Abels
John wrote:

function IsWindowOnCurrentVirtualDesktop(Wnd:cardinal; var IsTrue:
boolean): HResult; stdcall;

This declaration is wrong. The first parameter expects an HWND handle, not
a Cardinal integer. The second parameter expects a pointer to a BOOL, not
a pointer to a Boolean (BOOL and Boolean are very different data types
- BOOL is an alias for LongBool, which is 4 bytes, whereas Boolean is 1 byte
instead). Use this declaration instead:

function IsWindowOnCurrentVirtualDesktop(Wnd: HWND; out IsTrue: BOOL): HResult; 
stdcall;


function GetWindowDesktopId(Wnd:cardinal; var DesktopID:
cardinal): HResult; stdcall;

This declaration is also wrong. The first parameter expects an HWND handle,
not a Cardinal. The second parameter expects a pointer to a GUID, not a
pointer to a Cardinal. A GUID is a 16-byte record, whereas Cardinal is a
4-byte integer. Use this declaration instead:

function GetWindowDesktopId(Wnd:cardinal; out DesktopID: TGUID): HResult; 
stdcall;


function MoveWindowToDesktop(Wnd:cardinal; PStruture: pointer;
DesktopID: cardinal): HResult; stdcall;

This declaration is also wrong. For starters, this method only has 2 parameters,
but you declared 3 parameters. The first parameter expects an HWND handle.
The second parameter expects a pointer to a GUID. Use this declaration
instead:

function MoveWindowToDesktop(Wnd: HWND; var DesktopID: TGUID): HResult; stdcall;


function IsOnCurrentDesktop(wnd:cardinal): Boolean;

Same thing with the parameter. Use HWND instead of Cardinal. Also, get
rid of the Co(Un)Initialize() calls, they don't belong in the function.
The caller is responsible for calling them when it decides which COM threading
model it wants to use when accessing COM. Individual functions should not
make that decisions on the caller's behalf. COM must be initialized on a
per-thread basis, so your threads needs to call CoInitialize() before calling
IsOnCurrentDesktop().

var
vdm: IVirtualDesktopManager;

This variable belongs inside your IsOnCurrentDesktop() function, not in global
memory. You are risking a crash when the compiler tries to release the interface
during unit finalization after CoUninitialize() has already been called.

With all of that said, try this code instead:

unit VDMUnit;
 
interface
 
uses
  Windows, ActiveX, Comobj;
 
const
  IID_VDM: TGUID = '{A5CD92FF-29BE-454C-8D04-D82879FB3F1B}';
  CLSID_VDM: TGUID = '{AA509086-5CA9-4C25-8F95-589D3C07B48A}';
 
type
  {$EXTERNALSYM IVirtualDesktopManager}
  IVirtualDesktopManager = interface(IUnknown)
    ['{A5CD92FF-29BE-454C-8D04-D82879FB3F1B}']
    function IsWindowOnCurrentVirtualDesktop(Wnd: HWND; out IsTrue: BOOL): 
HResult; stdcall;
    function GetWindowDesktopId(Wnd: HWND; out DesktopID: TGUID): HResult; 
stdcall;
    function MoveWindowToDesktop(Wnd: HWND; var DesktopID: TGUID): HResult; 
stdcall;
  end;
 
function IsOnCurrentDesktop(wnd: HWND): Boolean;
 
implementation
 
function IsOnCurrentDesktop(wnd: HWND): Boolean;
var
  vdm: IVirtualDesktopManager;
  bOnDesktop: BOOL;
begin
  OleCheck(CoCreateInstance(CLSID_VDM, nil, CLSCTX_INPROC_SERVER, IVirtualDesktopManager, 
vdm));
  OleCheck(vdm.IsWindowOnCurrentVirtualDesktop(wnd, bOnDesktop));
  Result := bOnDesktop;
end;
 
end.


Lastly, note that IVirtualDesktopManager is only available on Windows 10
and later, so if you don't want your code to crash on earlier Windows versions,
you should remove the OleCheck() on CoCreateInstance() so you can handle
the error more gracefully, eg:

function IsOnCurrentDesktop(wnd: HWND): Boolean;
var
  vdm: IVirtualDesktopManager;
  hres: HResult;
  bOnDesktop: BOOL;
begin
  hres := CoCreateInstance(CLSID_VDM, nil, CLSCTX_INPROC_SERVER, IVirtualDesktopManager, 
vdm);
  if Succeeded(hres) then
  begin
    OleCheck(vdm.IsWindowOnCurrentVirtualDesktop(wnd, bOnDesktop));
    Result := bOnDesktop;
  end else begin
    // do something else...
  end;
end;


--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02