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)
Connect with Us