├── .gitignore
├── LICENSE.txt
├── README.markdown
├── TestVirtualDesktopAccessorWin32
├── TestVirtualDesktopAccessorWin32.cpp
├── TestVirtualDesktopAccessorWin32.h
├── TestVirtualDesktopAccessorWin32.vcxproj
├── TestVirtualDesktopAccessorWin32.vcxproj.filters
├── stdafx.cpp
├── stdafx.h
└── targetver.h
├── VirtualDesktopAccessor.sln
├── VirtualDesktopAccessor
├── VirtualDesktopAccessor.vcxproj
├── VirtualDesktopAccessor.vcxproj.filters
├── Win10Desktops.h
├── dllmain.cpp
├── dllmain.def
├── dllmain.h
├── stdafx.cpp
├── stdafx.h
└── targetver.h
└── x64
└── Release
└── VirtualDesktopAccessor.dll
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 | *VC.*
25 |
26 | # Visual Studio 2015 cache/options directory
27 | .vs/
28 | # Uncomment if you have tasks that create the project's static files in wwwroot
29 | #wwwroot/
30 |
31 | # MSTest test Results
32 | [Tt]est[Rr]esult*/
33 | [Bb]uild[Ll]og.*
34 |
35 | # NUNIT
36 | *.VisualState.xml
37 | TestResult.xml
38 |
39 | # Build Results of an ATL Project
40 | [Dd]ebugPS/
41 | [Rr]eleasePS/
42 | dlldata.c
43 |
44 | # DNX
45 | project.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 |
84 | # Visual Studio profiler
85 | *.psess
86 | *.vsp
87 | *.vspx
88 | *.sap
89 |
90 | # TFS 2012 Local Workspace
91 | $tf/
92 |
93 | # Guidance Automation Toolkit
94 | *.gpState
95 |
96 | # ReSharper is a .NET coding add-in
97 | _ReSharper*/
98 | *.[Rr]e[Ss]harper
99 | *.DotSettings.user
100 |
101 | # JustCode is a .NET coding add-in
102 | .JustCode
103 |
104 | # TeamCity is a build add-in
105 | _TeamCity*
106 |
107 | # DotCover is a Code Coverage Tool
108 | *.dotCover
109 |
110 | # NCrunch
111 | _NCrunch_*
112 | .*crunch*.local.xml
113 | nCrunchTemp_*
114 |
115 | # MightyMoose
116 | *.mm.*
117 | AutoTest.Net/
118 |
119 | # Web workbench (sass)
120 | .sass-cache/
121 |
122 | # Installshield output folder
123 | [Ee]xpress/
124 |
125 | # DocProject is a documentation generator add-in
126 | DocProject/buildhelp/
127 | DocProject/Help/*.HxT
128 | DocProject/Help/*.HxC
129 | DocProject/Help/*.hhc
130 | DocProject/Help/*.hhk
131 | DocProject/Help/*.hhp
132 | DocProject/Help/Html2
133 | DocProject/Help/html
134 |
135 | # Click-Once directory
136 | publish/
137 |
138 | # Publish Web Output
139 | *.[Pp]ublish.xml
140 | *.azurePubxml
141 | # TODO: Comment the next line if you want to checkin your web deploy settings
142 | # but database connection strings (with potential passwords) will be unencrypted
143 | *.pubxml
144 | *.publishproj
145 |
146 | # NuGet Packages
147 | *.nupkg
148 | # The packages folder can be ignored because of Package Restore
149 | **/packages/*
150 | # except build/, which is used as an MSBuild target.
151 | !**/packages/build/
152 | # Uncomment if necessary however generally it will be regenerated when needed
153 | #!**/packages/repositories.config
154 |
155 | # Windows Azure Build Output
156 | csx/
157 | *.build.csdef
158 |
159 | # Windows Azure Emulator
160 | efc/
161 | rfc/
162 |
163 | # Windows Store app package directory
164 | AppPackages/
165 |
166 | # Visual Studio cache files
167 | # files ending in .cache can be ignored
168 | *.[Cc]ache
169 | # but keep track of directories ending in .cache
170 | !*.[Cc]ache/
171 |
172 | # Others
173 | ClientBin/
174 | [Ss]tyle[Cc]op.*
175 | ~$*
176 | *~
177 | *.dbmdl
178 | *.dbproj.schemaview
179 | *.pfx
180 | *.publishsettings
181 | node_modules/
182 | orleans.codegen.cs
183 |
184 | # RIA/Silverlight projects
185 | Generated_Code/
186 |
187 | # Backup & report files from converting an old project file
188 | # to a newer Visual Studio version. Backup files are not needed,
189 | # because we have git ;-)
190 | _UpgradeReport_Files/
191 | Backup*/
192 | UpgradeLog*.XML
193 | UpgradeLog*.htm
194 |
195 | # SQL Server files
196 | *.mdf
197 | *.ldf
198 |
199 | # Business Intelligence projects
200 | *.rdl.data
201 | *.bim.layout
202 | *.bim_*.settings
203 |
204 | # Microsoft Fakes
205 | FakesAssemblies/
206 |
207 | # GhostDoc plugin setting file
208 | *.GhostDoc.xml
209 |
210 | # Node.js Tools for Visual Studio
211 | .ntvs_analysis.dat
212 |
213 | # Visual Studio 6 build log
214 | *.plg
215 |
216 | # Visual Studio 6 workspace options file
217 | *.opt
218 |
219 | # Visual Studio LightSwitch build output
220 | **/*.HTMLClient/GeneratedArtifacts
221 | **/*.DesktopClient/GeneratedArtifacts
222 | **/*.DesktopClient/ModelManifest.xml
223 | **/*.Server/GeneratedArtifacts
224 | **/*.Server/ModelManifest.xml
225 | _Pvt_Extensions
226 |
227 | # Paket dependency manager
228 | .paket/paket.exe
229 |
230 | # FAKE - F# Make
231 | .fake/
232 |
233 | !x64/Release/VirtualDesktopAccessor.dll
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, 2016 Jari Pennanen
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | # VirtualDesktopAccessor.dll
2 |
3 | DLL for accessing Windows 10 (tested with build 17134.48) Virtual Desktop features from e.g. AutoHotkey. MIT Licensed, see LICENSE.txt (c) Jari Pennanen, 2015-2018
4 |
5 | Download the VirtualDesktopAccessor.dll from directory x64\Release\VirtualDesktopAccessor.dll in the repository. This DLL works only on 64 bit Windows 10.
6 |
7 | You probably first need the [VS 2017 runtimes vc_redist.x64.exe and/or vc_redist.x86.exe](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads), if they are not installed already. I've built the DLL using VS 2017, and Microsoft is not providing those runtimes (who knows why) with Windows 10 yet.
8 |
9 | ## AutoHotkey script as example:
10 |
11 | ```AutoHotkey
12 | DetectHiddenWindows, On
13 | hwnd:=WinExist("ahk_pid " . DllCall("GetCurrentProcessId","Uint"))
14 | hwnd+=0x1000<<32
15 |
16 | hVirtualDesktopAccessor := DllCall("LoadLibrary", Str, "C:\Source\CandCPP\VirtualDesktopAccessor\x64\Release\VirtualDesktopAccessor.dll", "Ptr")
17 | GoToDesktopNumberProc := DllCall("GetProcAddress", Ptr, hVirtualDesktopAccessor, AStr, "GoToDesktopNumber", "Ptr")
18 | GetCurrentDesktopNumberProc := DllCall("GetProcAddress", Ptr, hVirtualDesktopAccessor, AStr, "GetCurrentDesktopNumber", "Ptr")
19 | IsWindowOnCurrentVirtualDesktopProc := DllCall("GetProcAddress", Ptr, hVirtualDesktopAccessor, AStr, "IsWindowOnCurrentVirtualDesktop", "Ptr")
20 | MoveWindowToDesktopNumberProc := DllCall("GetProcAddress", Ptr, hVirtualDesktopAccessor, AStr, "MoveWindowToDesktopNumber", "Ptr")
21 | RegisterPostMessageHookProc := DllCall("GetProcAddress", Ptr, hVirtualDesktopAccessor, AStr, "RegisterPostMessageHook", "Ptr")
22 | UnregisterPostMessageHookProc := DllCall("GetProcAddress", Ptr, hVirtualDesktopAccessor, AStr, "UnregisterPostMessageHook", "Ptr")
23 | IsPinnedWindowProc := DllCall("GetProcAddress", Ptr, hVirtualDesktopAccessor, AStr, "IsPinnedWindow", "Ptr")
24 | RestartVirtualDesktopAccessorProc := DllCall("GetProcAddress", Ptr, hVirtualDesktopAccessor, AStr, "RestartVirtualDesktopAccessor", "Ptr")
25 | ; GetWindowDesktopNumberProc := DllCall("GetProcAddress", Ptr, hVirtualDesktopAccessor, AStr, "GetWindowDesktopNumber", "Ptr")
26 | activeWindowByDesktop := {}
27 |
28 | ; Restart the virtual desktop accessor when Explorer.exe crashes, or restarts (e.g. when coming from fullscreen game)
29 | explorerRestartMsg := DllCall("user32\RegisterWindowMessage", "Str", "TaskbarCreated")
30 | OnMessage(explorerRestartMsg, "OnExplorerRestart")
31 | OnExplorerRestart(wParam, lParam, msg, hwnd) {
32 | global RestartVirtualDesktopAccessorProc
33 | DllCall(RestartVirtualDesktopAccessorProc, UInt, result)
34 | }
35 |
36 | MoveCurrentWindowToDesktop(number) {
37 | global MoveWindowToDesktopNumberProc, GoToDesktopNumberProc, activeWindowByDesktop
38 | WinGet, activeHwnd, ID, A
39 | activeWindowByDesktop[number] := 0 ; Do not activate
40 | DllCall(MoveWindowToDesktopNumberProc, UInt, activeHwnd, UInt, number)
41 | DllCall(GoToDesktopNumberProc, UInt, number)
42 | }
43 |
44 | GoToPrevDesktop() {
45 | global GetCurrentDesktopNumberProc, GoToDesktopNumberProc
46 | current := DllCall(GetCurrentDesktopNumberProc, UInt)
47 | if (current = 0) {
48 | GoToDesktopNumber(7)
49 | } else {
50 | GoToDesktopNumber(current - 1)
51 | }
52 | return
53 | }
54 |
55 | GoToNextDesktop() {
56 | global GetCurrentDesktopNumberProc, GoToDesktopNumberProc
57 | current := DllCall(GetCurrentDesktopNumberProc, UInt)
58 | if (current = 7) {
59 | GoToDesktopNumber(0)
60 | } else {
61 | GoToDesktopNumber(current + 1)
62 | }
63 | return
64 | }
65 |
66 | GoToDesktopNumber(num) {
67 | global GetCurrentDesktopNumberProc, GoToDesktopNumberProc, IsPinnedWindowProc, activeWindowByDesktop
68 |
69 | ; Store the active window of old desktop, if it is not pinned
70 | WinGet, activeHwnd, ID, A
71 | current := DllCall(GetCurrentDesktopNumberProc, UInt)
72 | isPinned := DllCall(IsPinnedWindowProc, UInt, activeHwnd)
73 | if (isPinned == 0) {
74 | activeWindowByDesktop[current] := activeHwnd
75 | }
76 |
77 | ; Try to avoid flashing task bar buttons, deactivate the current window if it is not pinned
78 | if (isPinned != 1) {
79 | WinActivate, ahk_class Shell_TrayWnd
80 | }
81 |
82 | ; Change desktop
83 | DllCall(GoToDesktopNumberProc, Int, num)
84 | return
85 | }
86 |
87 | ; Windows 10 desktop changes listener
88 | DllCall(RegisterPostMessageHookProc, Int, hwnd, Int, 0x1400 + 30)
89 | OnMessage(0x1400 + 30, "VWMess")
90 | VWMess(wParam, lParam, msg, hwnd) {
91 | global IsWindowOnCurrentVirtualDesktopProc, IsPinnedWindowProc, activeWindowByDesktop
92 |
93 | desktopNumber := lParam + 1
94 |
95 | ; Try to restore active window from memory (if it's still on the desktop and is not pinned)
96 | WinGet, activeHwnd, ID, A
97 | isPinned := DllCall(IsPinnedWindowProc, UInt, activeHwnd)
98 | oldHwnd := activeWindowByDesktop[lParam]
99 | isOnDesktop := DllCall(IsWindowOnCurrentVirtualDesktopProc, UInt, oldHwnd, UInt)
100 | if (isOnDesktop == 1 && isPinned != 1) {
101 | WinActivate, ahk_id %oldHwnd%
102 | }
103 |
104 | ; Menu, Tray, Icon, Icons/icon%desktopNumber%.ico
105 |
106 | ; When switching to desktop 1, set background pluto.jpg
107 | ; if (lParam == 0) {
108 | ; DllCall("SystemParametersInfo", UInt, 0x14, UInt, 0, Str, "C:\Users\Jarppa\Pictures\Backgrounds\saturn.jpg", UInt, 1)
109 | ; When switching to desktop 2, set background DeskGmail.png
110 | ; } else if (lParam == 1) {
111 | ; DllCall("SystemParametersInfo", UInt, 0x14, UInt, 0, Str, "C:\Users\Jarppa\Pictures\Backgrounds\DeskGmail.png", UInt, 1)
112 | ; When switching to desktop 7 or 8, set background DeskMisc.png
113 | ; } else if (lParam == 2 || lParam == 3) {
114 | ; DllCall("SystemParametersInfo", UInt, 0x14, UInt, 0, Str, "C:\Users\Jarppa\Pictures\Backgrounds\DeskMisc.png", UInt, 1)
115 | ; Other desktops, set background to DeskWork.png
116 | ; } else {
117 | ; DllCall("SystemParametersInfo", UInt, 0x14, UInt, 0, Str, "C:\Users\Jarppa\Pictures\Backgrounds\DeskWork.png", UInt, 1)
118 | ; }
119 | }
120 |
121 | ; Switching desktops:
122 | ; Win + Ctrl + 1 = Switch to desktop 1
123 | *#1::GoToDesktopNumber(0)
124 |
125 | ; Win + Ctrl + 2 = Switch to desktop 2
126 | *#2::GoToDesktopNumber(1)
127 |
128 | ; Moving windowes:
129 | ; Win + Shift + 1 = Move current window to desktop 1, and go there
130 | +#2::MoveCurrentWindowToDesktop(1)
131 | ```
132 |
133 | ## All functions exported by DLL:
134 |
135 | * int GetCurrentDesktopNumber()
136 | * int GetDesktopCount()
137 | * GUID GetDesktopIdByNumber(int number) // Returns zeroed GUID with invalid number found
138 | * int GetDesktopNumber(IVirtualDesktop *pDesktop)
139 | * int GetDesktopNumberById(GUID desktopId)
140 | * GUID GetWindowDesktopId(HWND window)
141 | * int GetWindowDesktopNumber(HWND window)
142 | * int IsWindowOnCurrentVirtualDesktop(HWND window)
143 | * BOOL MoveWindowToDesktopNumber(HWND window, int number)
144 | * void GoToDesktopNumber(int number)
145 | * void RegisterPostMessageHook(HWND listener, int messageOffset)
146 | * void UnregisterPostMessageHook(HWND hwnd)
147 | * int IsPinnedWindow(HWND hwnd) // Returns 1 if pinned, 0 if not pinned, -1 if not valid
148 | * void PinWindow(HWND hwnd)
149 | * void UnPinWindow(HWND hwnd)
150 | * int IsPinnedApp(HWND hwnd) // Returns 1 if pinned, 0 if not pinned, -1 if not valid
151 | * void PinApp(HWND hwnd)
152 | * void UnPinApp(HWND hwnd)
153 | * int IsWindowOnDesktopNumber(HWND window, int number) /
154 | * void RestartVirtualDesktopAccessor() // Call this during taskbar created message
155 |
156 | * void EnableKeepMinimized() // Deprecated, does nothing
157 | * void RestoreMinimized() // Deprecated, does nothing
158 |
--------------------------------------------------------------------------------
/TestVirtualDesktopAccessorWin32/TestVirtualDesktopAccessorWin32.cpp:
--------------------------------------------------------------------------------
1 | // TestVirtualDesktopAccessorWin32.cpp : Defines the entry point for the application.
2 | //
3 |
4 | #include "stdafx.h"
5 | #include "TestVirtualDesktopAccessorWin32.h"
6 | #include "dllmain.h"
7 |
8 | WCHAR szClassName[] = L"TestVirtualDesktopAccesorWin32";
9 |
10 | #define MESSAGE_OFFSET WM_USER + 60
11 |
12 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
13 | {
14 |
15 | switch (message) {
16 | case WM_DESTROY:
17 | PostQuitMessage(0);
18 | break;
19 | case MESSAGE_OFFSET + VDA_CurrentVirtualDesktopChanged:
20 | std::wcout << L"CurrentVirtualDesktopChanged old: " << wParam << " new:" << lParam << "\r\n";
21 | break;
22 | case MESSAGE_OFFSET + VDA_ViewVirtualDesktopChanged:
23 | std::wcout << L"CurrentVirtualDesktopChanged old: " << wParam << " new:" << lParam << "\r\n";
24 | break;
25 | case MESSAGE_OFFSET + VDA_VirtualDesktopCreated:
26 | std::wcout << L"CurrentVirtualDesktopChanged old: " << wParam << " new:" << lParam << "\r\n";
27 | break;
28 | case MESSAGE_OFFSET + VDA_VirtualDesktopDestroyBegin:
29 | std::wcout << L"CurrentVirtualDesktopChanged old: " << wParam << " new:" << lParam << "\r\n";
30 | break;
31 | case MESSAGE_OFFSET + VDA_VirtualDesktopDestroyed:
32 | std::wcout << L"CurrentVirtualDesktopChanged old: " << wParam << " new:" << lParam << "\r\n";
33 | break;
34 | case MESSAGE_OFFSET + VDA_VirtualDesktopDestroyFailed:
35 | std::wcout << L"CurrentVirtualDesktopChanged old: " << wParam << " new:" << lParam << "\r\n";
36 | break;
37 | default:
38 | return DefWindowProc(hWnd, message, wParam, lParam);
39 | }
40 | return 0;
41 | }
42 |
43 | int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
44 | _In_opt_ HINSTANCE hPrevInstance,
45 | _In_ LPWSTR lpCmdLine,
46 | _In_ int nCmdShow)
47 | {
48 | HWND hwnd;
49 | MSG messages;
50 | WNDCLASSEX wincl;
51 |
52 | wincl.hInstance = hInstance;
53 | wincl.lpszClassName = szClassName;
54 | wincl.lpfnWndProc = WndProc;
55 | wincl.style = CS_DBLCLKS;
56 | wincl.cbSize = sizeof(WNDCLASSEX);
57 | wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
58 | wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
59 | wincl.hCursor = LoadCursor(NULL, IDC_ARROW);
60 | wincl.lpszMenuName = NULL;
61 | wincl.cbClsExtra = 0;
62 | wincl.cbWndExtra = 0;
63 | wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
64 |
65 | if (!RegisterClassEx(&wincl))
66 | return 0;
67 |
68 | hwnd = CreateWindowEx(0,
69 | szClassName,
70 | L"TestVirtualDesktopAccesorWin32",
71 | WS_OVERLAPPEDWINDOW,
72 | CW_USEDEFAULT,
73 | CW_USEDEFAULT,
74 | 544,
75 | 375,
76 | HWND_DESKTOP,
77 | NULL,
78 | hInstance,
79 | NULL
80 | );
81 |
82 | ShowWindow(hwnd, SW_HIDE);
83 | _OpenDllWindow(hInstance);
84 |
85 | RegisterPostMessageHook(hwnd, MESSAGE_OFFSET);
86 | std::wcout << "Desktops: " << GetDesktopCount() << "\r\n";
87 | std::wcout << "Console Window's Desktop Number: " << GetWindowDesktopNumber(GetConsoleWindow()) << std::endl;
88 | std::wcout << "Current Desktop Number: " << GetCurrentDesktopNumber() << "\r\n";
89 |
90 | HWND notepad = FindWindow(_T("Notepad"), NULL);
91 | if (notepad != 0) {
92 | int number = GetCurrentDesktopNumber();
93 |
94 | std::wcout << "Is notepad on this desktop: " << IsWindowOnDesktopNumber(notepad, number) << std::endl;
95 |
96 | // Test pinning it
97 | std::wcout << "Try pinning the notepad (the window)." << std::endl;
98 | PinWindow(notepad);
99 | std::wcout << "Is notepad pinned?" << IsPinnedWindow(notepad) << std::endl;
100 | GoToDesktopNumber(number + 1);
101 | Sleep(2000);
102 | GoToDesktopNumber(number);
103 | UnPinWindow(notepad);
104 | std::wcout << "Is notepad pinned?" << IsPinnedWindow(notepad) << std::endl;
105 |
106 | Sleep(2000);
107 |
108 | // Test pinning the whole app!
109 | std::wcout << "Try pinning the notepad (the app executable)." << std::endl;
110 | PinApp(notepad);
111 | std::wcout << "Is notepad pinned app?" << IsPinnedApp(notepad) << std::endl;
112 | GoToDesktopNumber(number + 1);
113 | Sleep(2000);
114 | GoToDesktopNumber(number);
115 | UnPinApp(notepad);
116 | std::wcout << "Is notepad pinned app?" << IsPinnedApp(notepad) << std::endl;
117 |
118 | // Test moving it
119 | if (!IsWindowOnCurrentVirtualDesktop(notepad)) {
120 | MoveWindowToDesktopNumber(notepad, number);
121 | }
122 | std::wcout << "Notepad is on on the current desktop. " << std::endl;
123 | Sleep(1000);
124 | MoveWindowToDesktopNumber(notepad, number + 1);
125 | std::wcout << "Notepad should now have been moved to the next desktop." << std::endl;
126 | Sleep(1000);
127 | MoveWindowToDesktopNumber(notepad, number);
128 | }
129 | else {
130 | std::wcout << "Start notepad to try moving a window, or pinning it" << std::endl;
131 | }
132 |
133 |
134 | GUID g = GetDesktopIdByNumber(GetCurrentDesktopNumber());
135 | WCHAR text[255];
136 | StringFromGUID2(g, &text[0], 255);
137 | std::wcout << "Current Desktop GUID: " << text << std::endl;
138 |
139 | GUID g2 = GetWindowDesktopId(GetConsoleWindow());
140 | WCHAR text2[255];
141 | StringFromGUID2(g2, &text2[0], 255);
142 | std::wcout << "Console Window's Desktop GUID: " << text2 << std::endl;
143 | while (GetMessage(&messages, NULL, 0, 0))
144 | {
145 | TranslateMessage(&messages);
146 | DispatchMessage(&messages);
147 | }
148 |
149 | UnregisterPostMessageHook(hwnd);
150 |
151 | return messages.wParam;
152 | }
153 |
154 |
155 | int main() {
156 | return wWinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOW);
157 | }
158 |
--------------------------------------------------------------------------------
/TestVirtualDesktopAccessorWin32/TestVirtualDesktopAccessorWin32.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
--------------------------------------------------------------------------------
/TestVirtualDesktopAccessorWin32/TestVirtualDesktopAccessorWin32.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {FA401C23-A170-45D0-BB2C-9F21A8E07B2C}
23 | Win32Proj
24 | TestVirtualDesktopAccessorWin32
25 | 10.0
26 |
27 |
28 |
29 | Application
30 | true
31 | v143
32 | Unicode
33 |
34 |
35 | Application
36 | false
37 | v143
38 | true
39 | Unicode
40 |
41 |
42 | Application
43 | true
44 | v143
45 | Unicode
46 |
47 |
48 | Application
49 | false
50 | v143
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 |
75 |
76 | true
77 |
78 |
79 | false
80 |
81 |
82 | false
83 | $(SolutionDir)$(Platform)\$(Configuration)\
84 |
85 |
86 |
87 | Use
88 | Level3
89 | Disabled
90 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
91 | true
92 | ..\VirtualDesktopAccessor;%(AdditionalIncludeDirectories)
93 |
94 |
95 | Console
96 | true
97 |
98 |
99 |
100 |
101 | Use
102 | Level3
103 | Disabled
104 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions)
105 | true
106 | ..\VirtualDesktopAccessor;%(AdditionalIncludeDirectories)
107 |
108 |
109 | Console
110 | true
111 |
112 |
113 |
114 |
115 | Level3
116 | Use
117 | MaxSpeed
118 | true
119 | true
120 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
121 | true
122 | ..\VirtualDesktopAccessor;%(AdditionalIncludeDirectories)
123 |
124 |
125 | Console
126 | true
127 | true
128 | true
129 |
130 |
131 |
132 |
133 | Level3
134 | Use
135 | MaxSpeed
136 | true
137 | true
138 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
139 | true
140 | ..\VirtualDesktopAccessor;%(AdditionalIncludeDirectories)
141 |
142 |
143 | Console
144 | true
145 | true
146 | true
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | Create
157 | Create
158 | Create
159 | Create
160 |
161 |
162 |
163 |
164 |
165 |
166 |
--------------------------------------------------------------------------------
/TestVirtualDesktopAccessorWin32/TestVirtualDesktopAccessorWin32.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 |
29 |
30 | Source Files
31 |
32 |
33 | Source Files
34 |
35 |
36 |
--------------------------------------------------------------------------------
/TestVirtualDesktopAccessorWin32/stdafx.cpp:
--------------------------------------------------------------------------------
1 | // stdafx.cpp : source file that includes just the standard includes
2 | // TestVirtualDesktopAccessorWin32.pch will be the pre-compiled header
3 | // stdafx.obj will contain the pre-compiled type information
4 |
5 | #include "stdafx.h"
6 |
7 | // TODO: reference any additional headers you need in STDAFX.H
8 | // and not in this file
9 |
--------------------------------------------------------------------------------
/TestVirtualDesktopAccessorWin32/stdafx.h:
--------------------------------------------------------------------------------
1 | // stdafx.h : include file for standard system include files,
2 | // or project specific include files that are used frequently, but
3 | // are changed infrequently
4 | //
5 |
6 | #pragma once
7 |
8 | #include "targetver.h"
9 |
10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
11 | // Windows Header Files:
12 | #include
13 |
14 | // C RunTime Header Files
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 |
21 | // TODO: reference additional headers your program requires here
22 |
--------------------------------------------------------------------------------
/TestVirtualDesktopAccessorWin32/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/VirtualDesktopAccessor.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 16
4 | VisualStudioVersion = 15.0.27703.2018
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VirtualDesktopAccessor", "VirtualDesktopAccessor\VirtualDesktopAccessor.vcxproj", "{75640BB7-FA6D-4DED-A074-E4758CCEF7D1}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestVirtualDesktopAccessorWin32", "TestVirtualDesktopAccessorWin32\TestVirtualDesktopAccessorWin32.vcxproj", "{FA401C23-A170-45D0-BB2C-9F21A8E07B2C}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{88DF21E3-B4B2-4CE5-A9B2-C4A60BF898B5}"
11 | ProjectSection(SolutionItems) = preProject
12 | README.markdown = README.markdown
13 | EndProjectSection
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|x64 = Debug|x64
18 | Debug|x86 = Debug|x86
19 | Release|x64 = Release|x64
20 | Release|x86 = Release|x86
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {75640BB7-FA6D-4DED-A074-E4758CCEF7D1}.Debug|x64.ActiveCfg = Debug|x64
24 | {75640BB7-FA6D-4DED-A074-E4758CCEF7D1}.Debug|x64.Build.0 = Debug|x64
25 | {75640BB7-FA6D-4DED-A074-E4758CCEF7D1}.Debug|x86.ActiveCfg = Debug|Win32
26 | {75640BB7-FA6D-4DED-A074-E4758CCEF7D1}.Debug|x86.Build.0 = Debug|Win32
27 | {75640BB7-FA6D-4DED-A074-E4758CCEF7D1}.Release|x64.ActiveCfg = Release|x64
28 | {75640BB7-FA6D-4DED-A074-E4758CCEF7D1}.Release|x64.Build.0 = Release|x64
29 | {75640BB7-FA6D-4DED-A074-E4758CCEF7D1}.Release|x86.ActiveCfg = Release|Win32
30 | {75640BB7-FA6D-4DED-A074-E4758CCEF7D1}.Release|x86.Build.0 = Release|Win32
31 | {FA401C23-A170-45D0-BB2C-9F21A8E07B2C}.Debug|x64.ActiveCfg = Debug|x64
32 | {FA401C23-A170-45D0-BB2C-9F21A8E07B2C}.Debug|x64.Build.0 = Debug|x64
33 | {FA401C23-A170-45D0-BB2C-9F21A8E07B2C}.Debug|x86.ActiveCfg = Debug|Win32
34 | {FA401C23-A170-45D0-BB2C-9F21A8E07B2C}.Debug|x86.Build.0 = Debug|Win32
35 | {FA401C23-A170-45D0-BB2C-9F21A8E07B2C}.Release|x64.ActiveCfg = Release|x64
36 | {FA401C23-A170-45D0-BB2C-9F21A8E07B2C}.Release|x64.Build.0 = Release|x64
37 | {FA401C23-A170-45D0-BB2C-9F21A8E07B2C}.Release|x86.ActiveCfg = Release|Win32
38 | {FA401C23-A170-45D0-BB2C-9F21A8E07B2C}.Release|x86.Build.0 = Release|Win32
39 | EndGlobalSection
40 | GlobalSection(SolutionProperties) = preSolution
41 | HideSolutionNode = FALSE
42 | EndGlobalSection
43 | GlobalSection(ExtensibilityGlobals) = postSolution
44 | SolutionGuid = {762C7D7B-DF75-46B0-9409-DE72C96B2A3F}
45 | EndGlobalSection
46 | EndGlobal
47 |
--------------------------------------------------------------------------------
/VirtualDesktopAccessor/VirtualDesktopAccessor.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {75640BB7-FA6D-4DED-A074-E4758CCEF7D1}
23 | Win32Proj
24 | VirtualDesktopAccessor
25 | 10.0
26 |
27 |
28 |
29 | DynamicLibrary
30 | true
31 | v143
32 | Unicode
33 |
34 |
35 | DynamicLibrary
36 | false
37 | v143
38 | true
39 | Unicode
40 |
41 |
42 | DynamicLibrary
43 | true
44 | v143
45 | Unicode
46 |
47 |
48 | DynamicLibrary
49 | false
50 | v143
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 |
75 |
76 | true
77 |
78 |
79 | false
80 |
81 |
82 | false
83 | $(SolutionDir)$(Platform)\$(Configuration)\
84 | $(Platform)\$(Configuration)\
85 |
86 |
87 |
88 | Use
89 | Level3
90 | Disabled
91 | WIN32;_DEBUG;_WINDOWS;_USRDLL;VIRTUALDESKTOPACCESSOR_EXPORTS;%(PreprocessorDefinitions)
92 | true
93 |
94 |
95 | Windows
96 | true
97 | dllmain.def
98 |
99 |
100 |
101 |
102 | Use
103 | Level3
104 | Disabled
105 | _DEBUG;_WINDOWS;_USRDLL;VIRTUALDESKTOPACCESSOR_EXPORTS;%(PreprocessorDefinitions)
106 | true
107 |
108 |
109 | Windows
110 | true
111 | dllmain.def
112 |
113 |
114 |
115 |
116 | Level3
117 | Use
118 | MaxSpeed
119 | true
120 | true
121 | WIN32;NDEBUG;_WINDOWS;_USRDLL;VIRTUALDESKTOPACCESSOR_EXPORTS;%(PreprocessorDefinitions)
122 | true
123 |
124 |
125 | Windows
126 | true
127 | true
128 | true
129 | dllmain.def
130 |
131 |
132 |
133 |
134 | Level3
135 | Use
136 | MaxSpeed
137 | true
138 | true
139 | NDEBUG;_WINDOWS;_USRDLL;VIRTUALDESKTOPACCESSOR_EXPORTS;%(PreprocessorDefinitions)
140 | true
141 |
142 |
143 | Windows
144 | true
145 | true
146 | true
147 | dllmain.def
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | false
159 |
160 |
161 | false
162 |
163 |
164 | false
165 |
166 |
167 | false
168 |
169 |
170 |
171 |
172 | Create
173 | Create
174 | Create
175 | Create
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
--------------------------------------------------------------------------------
/VirtualDesktopAccessor/VirtualDesktopAccessor.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 |
32 |
33 | Source Files
34 |
35 |
36 | Source Files
37 |
38 |
39 |
40 |
41 | Source Files
42 |
43 |
44 |
--------------------------------------------------------------------------------
/VirtualDesktopAccessor/Win10Desktops.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "stdafx.h"
4 |
5 | // Status
6 | // Up to date with ae16abb6
7 |
8 | const IID IID_IServiceProvider = {
9 | 0x6D5140C1, 0x7436, 0x11CE, 0x80, 0x34, 0x00, 0xAA, 0x00, 0x60, 0x09, 0xFA };
10 |
11 | const CLSID CLSID_ImmersiveShell = {
12 | 0xC2F03A33, 0x21F5, 0x47FA, 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39 };
13 |
14 | // SID_VirtualDesktopManager
15 | const CLSID CLSID_VirtualDesktopManagerInternal = {
16 | 0xC5E0CDCA, 0x7B6E, 0x41B2, 0x9F, 0xC4, 0xD9, 0x39, 0x75, 0xCC, 0x46, 0x7B };
17 |
18 | // SID_VirtualDesktopNotificationService
19 | const CLSID CLSID_IVirtualNotificationService = {
20 | 0xA501FDEC, 0x4A09, 0x464C, 0xAE, 0x4E, 0x1B, 0x9C, 0x21, 0xB8, 0x49, 0x18
21 | };
22 |
23 | const CLSID CLSID_IVirtualDesktopManager = {
24 | 0xAA509086, 0x5CA9, 0x4C25, { 0x8f, 0x95, 0x58, 0x9d, 0x3c, 0x07, 0xb4, 0x8a }
25 | };
26 |
27 | const CLSID CLSID_VirtualDesktopPinnedApps = {
28 | 0xb5a399e7, 0x1c87, 0x46b8, 0x88, 0xe9, 0xfc, 0x57, 0x47, 0xb1, 0x71, 0xbd
29 | };
30 |
31 | // IID same as in MIDL IVirtualDesktopNotification
32 | const IID IID_IVirtualDesktopNotification = {
33 | 0xB287FA1C, 0x7771, 0x471A, { 0xA2, 0xDF, 0x9B, 0x6B, 0x21, 0xF0, 0xD6, 0x75 }
34 | };
35 |
36 | // Ignore following API's:
37 | #define IAsyncCallback UINT
38 | #define IImmersiveMonitor UINT
39 | #define APPLICATION_VIEW_COMPATIBILITY_POLICY UINT
40 | #define IShellPositionerPriority UINT
41 | #define IApplicationViewOperation UINT
42 | #define APPLICATION_VIEW_CLOAK_TYPE UINT
43 | #define IApplicationViewPosition UINT
44 |
45 | DECLARE_INTERFACE_IID_(IApplicationView, IInspectable, "372E1D3B-38D3-42E4-A15B-8AB2B178F513")
46 | {
47 | /*** IUnknown methods ***/
48 | STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR * ppvObject) PURE;
49 | STDMETHOD_(ULONG, AddRef)(THIS) PURE;
50 | STDMETHOD_(ULONG, Release)(THIS) PURE;
51 |
52 | /*** IInspectable methods ***/
53 | STDMETHOD(GetIids)(__RPC__out ULONG * iidCount, __RPC__deref_out_ecount_full_opt(*iidCount) IID * *iids) PURE;
54 | STDMETHOD(GetRuntimeClassName)(__RPC__deref_out_opt HSTRING * className) PURE;
55 | STDMETHOD(GetTrustLevel)(__RPC__out TrustLevel * trustLevel) PURE;
56 |
57 | /*** IApplicationView methods ***/
58 | STDMETHOD(SetFocus)(THIS) PURE;
59 | STDMETHOD(SwitchTo)(THIS) PURE;
60 | STDMETHOD(TryInvokeBack)(THIS_ IAsyncCallback*) PURE;
61 | STDMETHOD(GetThumbnailWindow)(THIS_ HWND*) PURE;
62 | STDMETHOD(GetMonitor)(THIS_ IImmersiveMonitor**) PURE;
63 | STDMETHOD(GetVisibility)(THIS_ int*) PURE;
64 | STDMETHOD(SetCloak)(THIS_ APPLICATION_VIEW_CLOAK_TYPE, int) PURE;
65 | STDMETHOD(GetPosition)(THIS_ REFIID, void**) PURE;
66 | STDMETHOD(SetPosition)(THIS_ IApplicationViewPosition*) PURE;
67 | STDMETHOD(InsertAfterWindow)(THIS_ HWND) PURE;
68 | STDMETHOD(GetExtendedFramePosition)(THIS_ RECT*) PURE;
69 | STDMETHOD(GetAppUserModelId)(THIS_ PWSTR*) PURE;
70 | STDMETHOD(SetAppUserModelId)(THIS_ PCWSTR) PURE;
71 | STDMETHOD(IsEqualByAppUserModelId)(THIS_ PCWSTR, int*) PURE;
72 | STDMETHOD(GetViewState)(THIS_ UINT*) PURE;
73 | STDMETHOD(SetViewState)(THIS_ UINT) PURE;
74 | STDMETHOD(GetNeediness)(THIS_ int*) PURE;
75 | STDMETHOD(GetLastActivationTimestamp)(THIS_ ULONGLONG*) PURE;
76 | STDMETHOD(SetLastActivationTimestamp)(THIS_ ULONGLONG) PURE;
77 | STDMETHOD(GetVirtualDesktopId)(THIS_ GUID*) PURE;
78 | STDMETHOD(SetVirtualDesktopId)(THIS_ REFGUID) PURE;
79 | STDMETHOD(GetShowInSwitchers)(THIS_ int*) PURE;
80 | STDMETHOD(SetShowInSwitchers)(THIS_ int) PURE;
81 | STDMETHOD(GetScaleFactor)(THIS_ int*) PURE;
82 | STDMETHOD(CanReceiveInput)(THIS_ BOOL*) PURE;
83 | STDMETHOD(GetCompatibilityPolicyType)(THIS_ APPLICATION_VIEW_COMPATIBILITY_POLICY*) PURE;
84 | STDMETHOD(SetCompatibilityPolicyType)(THIS_ APPLICATION_VIEW_COMPATIBILITY_POLICY) PURE;
85 | //STDMETHOD(GetPositionPriority)(THIS_ IShellPositionerPriority**) PURE; // removed in 1803
86 | //STDMETHOD(SetPositionPriority)(THIS_ IShellPositionerPriority*) PURE; // removed in 1803
87 | STDMETHOD(GetSizeConstraints)(THIS_ IImmersiveMonitor*, SIZE*, SIZE*) PURE;
88 | STDMETHOD(GetSizeConstraintsForDpi)(THIS_ UINT, SIZE*, SIZE*) PURE;
89 | STDMETHOD(SetSizeConstraintsForDpi)(THIS_ const UINT*, const SIZE*, const SIZE*) PURE;
90 | //STDMETHOD(QuerySizeConstraintsFromApp)(THIS) PURE; // removed in 1803
91 | STDMETHOD(OnMinSizePreferencesUpdated)(THIS_ HWND) PURE;
92 | STDMETHOD(ApplyOperation)(THIS_ IApplicationViewOperation*) PURE;
93 | STDMETHOD(IsTray)(THIS_ BOOL*) PURE;
94 | STDMETHOD(IsInHighZOrderBand)(THIS_ BOOL*) PURE;
95 | STDMETHOD(IsSplashScreenPresented)(THIS_ BOOL*) PURE;
96 | STDMETHOD(Flash)(THIS) PURE;
97 | STDMETHOD(GetRootSwitchableOwner)(THIS_ IApplicationView**) PURE;
98 | STDMETHOD(EnumerateOwnershipTree)(THIS_ IObjectArray**) PURE;
99 |
100 | STDMETHOD(GetEnterpriseId)(THIS_ PWSTR*) PURE;
101 | STDMETHOD(IsMirrored)(THIS_ BOOL*) PURE;
102 |
103 | // Unsure
104 | STDMETHOD(Unknown1)(THIS_ int*) PURE;
105 | STDMETHOD(Unknown2)(THIS_ int*) PURE;
106 | STDMETHOD(Unknown3)(THIS_ int*) PURE;
107 | STDMETHOD(Unknown4)(THIS_ int) PURE;
108 |
109 | // 17661?
110 | //STDMETHOD(Unknown5)(THIS) PURE;
111 | //STDMETHOD(Unknown6)(THIS_ int*) PURE;
112 | //STDMETHOD(Unknown7)(THIS_ int) PURE;
113 | //STDMETHOD(Unknown8)(THIS_ int, THIS_ int) PURE;
114 |
115 | };
116 |
117 | const __declspec(selectany) IID& IID_IApplicationView = __uuidof(IApplicationView);
118 |
119 | DECLARE_INTERFACE_IID_(IVirtualDesktopPinnedApps, IUnknown, "4ce81583-1e4c-4632-a621-07a53543148f")
120 | {
121 | /*** IUnknown methods ***/
122 | STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR * ppvObject) PURE;
123 | STDMETHOD_(ULONG, AddRef)(THIS) PURE;
124 | STDMETHOD_(ULONG, Release)(THIS) PURE;
125 |
126 | /*** IVirtualDesktopPinnedApps methods ***/
127 | STDMETHOD(IsAppIdPinned)(THIS_ PCWSTR appId, BOOL*) PURE;
128 | STDMETHOD(PinAppID)(THIS_ PCWSTR appId) PURE;
129 | STDMETHOD(UnpinAppID)(THIS_ PCWSTR appId) PURE;
130 | STDMETHOD(IsViewPinned)(THIS_ IApplicationView*, BOOL*) PURE;
131 | STDMETHOD(PinView)(THIS_ IApplicationView*) PURE;
132 | STDMETHOD(UnpinView)(THIS_ IApplicationView*) PURE;
133 |
134 | };
135 |
136 | // Ignore following API's:
137 | #define IImmersiveApplication UINT
138 | #define IApplicationViewChangeListener UINT
139 |
140 | DECLARE_INTERFACE_IID_(IApplicationViewCollection, IUnknown, "1841C6D7-4F9D-42C0-AF41-8747538F10E5")
141 | {
142 | /*** IUnknown methods ***/
143 | STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR * ppvObject) PURE;
144 | STDMETHOD_(ULONG, AddRef)(THIS) PURE;
145 | STDMETHOD_(ULONG, Release)(THIS) PURE;
146 |
147 | /*** IApplicationViewCollection methods ***/
148 | STDMETHOD(GetViews)(THIS_ IObjectArray**) PURE;
149 | STDMETHOD(GetViewsByZOrder)(THIS_ IObjectArray**) PURE;
150 | STDMETHOD(GetViewsByAppUserModelId)(THIS_ PCWSTR, IObjectArray**) PURE;
151 | STDMETHOD(GetViewForHwnd)(THIS_ HWND, IApplicationView**) PURE;
152 | STDMETHOD(GetViewForApplication)(THIS_ IImmersiveApplication*, IApplicationView**) PURE;
153 | STDMETHOD(GetViewForAppUserModelId)(THIS_ PCWSTR, IApplicationView**) PURE;
154 | STDMETHOD(GetViewInFocus)(THIS_ IApplicationView**) PURE;
155 | STDMETHOD(TryGetLastActiveVisibleView)(IApplicationView**) PURE;
156 | STDMETHOD(RefreshCollection)(THIS) PURE;
157 | STDMETHOD(RegisterForApplicationViewChanges)(THIS_ IApplicationViewChangeListener*, DWORD*) PURE;
158 | // STDMETHOD(RegisterForApplicationViewPositionChanges)(THIS_ IApplicationViewChangeListener*, DWORD*) PURE;
159 | STDMETHOD(UnregisterForApplicationViewChanges)(THIS_ DWORD) PURE;
160 | };
161 |
162 | MIDL_INTERFACE("3F07F4BE-B107-441A-AF0F-39D82529072C")
163 | IVirtualDesktop : public IUnknown
164 | {
165 | public:
166 | virtual HRESULT STDMETHODCALLTYPE IsViewVisible(IApplicationView * pView, int* pfVisible) = 0;
167 | virtual HRESULT STDMETHODCALLTYPE GetID(GUID* pGuid) = 0;
168 | virtual HRESULT STDMETHODCALLTYPE GetName(HSTRING* name) = 0;
169 | virtual HRESULT STDMETHODCALLTYPE GetWallpaper(HSTRING* wallpaperPath) = 0;
170 | };
171 |
172 | MIDL_INTERFACE("A871910E-6CC0-4E65-8B9B-458CE9115E30")
173 | IVirtualDesktop2 : public IUnknown
174 | {
175 | public:
176 | virtual HRESULT STDMETHODCALLTYPE IsRemote(BOOL * isRemote) = 0;
177 | };
178 |
179 | enum AdjacentDesktop
180 | {
181 | LeftDirection = 3,
182 | RightDirection = 4
183 | };
184 |
185 | MIDL_INTERFACE("4970BA3D-FD4E-4647-BEA3-D89076EF4B9C")
186 | IVirtualDesktopManagerInternal : public IUnknown
187 | {
188 | public:
189 | virtual HRESULT STDMETHODCALLTYPE GetCount(UINT * pCount) = 0;
190 |
191 | virtual HRESULT STDMETHODCALLTYPE MoveViewToDesktop(
192 | IApplicationView* pView,
193 | IVirtualDesktop* pDesktop) = 0;
194 |
195 | // Since build 10240
196 | virtual HRESULT STDMETHODCALLTYPE CanViewMoveDesktops(
197 | IApplicationView* pView,
198 | int* pfCanViewMoveDesktops) = 0;
199 |
200 | virtual HRESULT STDMETHODCALLTYPE GetCurrentDesktop(
201 | IVirtualDesktop** desktop) = 0;
202 |
203 | virtual HRESULT STDMETHODCALLTYPE GetDesktops(
204 | IObjectArray** ppDesktops) = 0;
205 |
206 | virtual HRESULT STDMETHODCALLTYPE GetAdjacentDesktop(
207 | IVirtualDesktop* pDesktopReference,
208 | AdjacentDesktop uDirection,
209 | IVirtualDesktop** ppAdjacentDesktop) = 0;
210 |
211 | virtual HRESULT STDMETHODCALLTYPE SwitchDesktop(
212 | IVirtualDesktop* pDesktop) = 0;
213 |
214 | virtual HRESULT STDMETHODCALLTYPE CreateDesktop(
215 | IVirtualDesktop** ppNewDesktop) = 0;
216 |
217 | virtual HRESULT STDMETHODCALLTYPE MoveDesktop(
218 | IVirtualDesktop* desktop,
219 | INT32 index);
220 |
221 | virtual HRESULT STDMETHODCALLTYPE RemoveDesktop(
222 | IVirtualDesktop* pRemove,
223 | IVirtualDesktop* pFallbackDesktop) = 0;
224 |
225 | // Since build 10240
226 | virtual HRESULT STDMETHODCALLTYPE FindDesktop(
227 | GUID* desktopId,
228 | IVirtualDesktop** ppDesktop) = 0;
229 |
230 | /*
231 | HRESULT GetDesktopSwitchIncludeExcludeViews([in] IVirtualDesktop *pTargetDesktop, [out] IObjectArray **ppIncludeViews, [out] IObjectArray **ppExcludeViews);
232 | HRESULT SetDesktopName([in] IVirtualDesktop* desktop, [in] HSTRING name);
233 | HRESULT SetDesktopWallpaper([in] IVirtualDesktop* desktop, [in] HSTRING wallpaperPath);
234 | HRESULT UpdateWallpaperPathForAllDesktops([in] HSTRING wallpaperPath);
235 | HRESULT CopyDesktopState([in] IApplicationView* target, [in] IApplicationView* source);
236 | */
237 | };
238 |
239 | MIDL_INTERFACE("A3175F2D-239C-4BD2-8AA0-EEBA8B0B138E")
240 | IVirtualDesktopManagerInternal2 : public IUnknown
241 | {
242 | public:
243 | virtual HRESULT STDMETHODCALLTYPE CreateRemoteDesktop(HSTRING name, IVirtualDesktop * *ppNewDesktop) = 0;
244 | virtual HRESULT STDMETHODCALLTYPE SwitchRemoteDesktop(IVirtualDesktop* pDesktop) = 0;
245 | virtual HRESULT STDMETHODCALLTYPE SwitchDesktopWithAnimation(IVirtualDesktop* pDesktop) = 0;
246 | virtual HRESULT STDMETHODCALLTYPE GetLastActiveDesktop(IVirtualDesktop** lastActiveVirtualDesktop) = 0;
247 | };
248 |
249 | MIDL_INTERFACE("a5cd92ff-29be-454c-8d04-d82879fb3f1b")
250 | IVirtualDesktopManager : public IUnknown
251 | {
252 | public:
253 | virtual HRESULT STDMETHODCALLTYPE IsWindowOnCurrentVirtualDesktop(
254 | /* [in] */ __RPC__in HWND topLevelWindow,
255 | /* [out] */ __RPC__out BOOL * onCurrentDesktop) = 0;
256 |
257 | virtual HRESULT STDMETHODCALLTYPE GetWindowDesktopId(
258 | /* [in] */ __RPC__in HWND topLevelWindow,
259 | /* [out] */ __RPC__out GUID* desktopId) = 0;
260 |
261 | virtual HRESULT STDMETHODCALLTYPE MoveWindowToDesktop(
262 | /* [in] */ __RPC__in HWND topLevelWindow,
263 | /* [in] */ __RPC__in REFGUID desktopId) = 0;
264 | };
265 |
266 | MIDL_INTERFACE("B287FA1C-7771-471A-A2DF-9B6B21F0D675")
267 | IVirtualDesktopNotification : public IUnknown
268 | {
269 | public:
270 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopCreated(
271 | IVirtualDesktop * pDesktop) = 0;
272 |
273 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyBegin(
274 | IVirtualDesktop* pDesktopDestroyed,
275 | IVirtualDesktop* pDesktopFallback) = 0;
276 |
277 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyFailed(
278 | IVirtualDesktop* pDesktopDestroyed,
279 | IVirtualDesktop* pDesktopFallback) = 0;
280 |
281 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyed(
282 | IVirtualDesktop* pDesktopDestroyed,
283 | IVirtualDesktop* pDesktopFallback) = 0;
284 |
285 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopMoved(
286 | IVirtualDesktop* pDesktop,
287 | UINT64 oldIndex,
288 | UINT64 newIndex) = 0;
289 |
290 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopNameChanged(
291 | IVirtualDesktop* pDesktop,
292 | HSTRING name) = 0;
293 |
294 | virtual HRESULT STDMETHODCALLTYPE ViewVirtualDesktopChanged(
295 | IApplicationView* pView) = 0;
296 |
297 | virtual HRESULT STDMETHODCALLTYPE CurrentVirtualDesktopChanged(
298 | IVirtualDesktop* pDesktopOld,
299 | IVirtualDesktop* pDesktopNew) = 0;
300 |
301 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopWallpaperChanged(
302 | IVirtualDesktop* pDesktop,
303 | HSTRING name) = 0;
304 |
305 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopSwitched(
306 | IVirtualDesktop* pDesktopNew) = 0;
307 |
308 | virtual HRESULT STDMETHODCALLTYPE RemoteVirtualDesktopConnected(
309 | IVirtualDesktop* remoteVirtualDesktop) = 0;
310 | };
311 |
312 | MIDL_INTERFACE("0CD45E71-D927-4F15-8B0A-8FEF525337BF")
313 | IVirtualDesktopNotificationService : public IUnknown
314 | {
315 | public:
316 | virtual HRESULT STDMETHODCALLTYPE Register(
317 | IVirtualDesktopNotification * pNotification,
318 | DWORD * pdwCookie) = 0;
319 |
320 | virtual HRESULT STDMETHODCALLTYPE Unregister(
321 | DWORD dwCookie) = 0;
322 | };
323 |
--------------------------------------------------------------------------------
/VirtualDesktopAccessor/dllmain.cpp:
--------------------------------------------------------------------------------
1 | // dllmain.cpp : Defines the entry point for the DLL application.
2 | #include "stdafx.h"
3 | #include "dllmain.h"
4 |
5 | BOOL APIENTRY DllMain( HMODULE hModule,
6 | DWORD ul_reason_for_call,
7 | LPVOID lpReserved
8 | )
9 | {
10 | switch (ul_reason_for_call)
11 | {
12 | case DLL_PROCESS_ATTACH:
13 | _OpenDllWindow(hModule);
14 | break;
15 | case DLL_THREAD_ATTACH:
16 | case DLL_THREAD_DETACH:
17 | case DLL_PROCESS_DETACH:
18 | break;
19 | }
20 | return TRUE;
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/VirtualDesktopAccessor/dllmain.def:
--------------------------------------------------------------------------------
1 | LIBRARY DLLMAIN
2 | EXPORTS
3 | GetCurrentDesktopNumber @8
4 | GetDesktopCount @1
5 | GetDesktopIdByNumber @12
6 | GetDesktopNumber @7
7 | GetDesktopNumberById @2
8 | GetWindowDesktopId @3
9 | GetWindowDesktopNumber @4
10 | IsWindowOnCurrentVirtualDesktop @5
11 | MoveWindowToDesktopNumber @6
12 | GoToDesktopNumber @9
13 | RegisterPostMessageHook @10
14 | UnregisterPostMessageHook @11
15 | IsPinnedWindow @13
16 | PinWindow @14
17 | UnPinWindow @15
18 | IsPinnedApp @16
19 | PinApp @17
20 | UnPinApp @18
21 |
22 | EnableKeepMinimized @19
23 | RestoreMinimized @20
24 | IsWindowOnDesktopNumber @21
25 | RestartVirtualDesktopAccessor @22
--------------------------------------------------------------------------------
/VirtualDesktopAccessor/dllmain.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "stdafx.h"
3 | #include "Win10Desktops.h"
4 |
5 | #define DllExport __declspec( dllexport )
6 |
7 | #define VDA_VirtualDesktopCreated 5
8 | #define VDA_VirtualDesktopDestroyBegin 4
9 | #define VDA_VirtualDesktopDestroyFailed 3
10 | #define VDA_VirtualDesktopDestroyed 2
11 | #define VDA_ViewVirtualDesktopChanged 1
12 | #define VDA_CurrentVirtualDesktopChanged 0
13 |
14 | #define VDA_IS_NORMAL 1
15 | #define VDA_IS_MINIMIZED 2
16 | #define VDA_IS_MAXIMIZED 3
17 |
18 | std::map listeners;
19 | IServiceProvider* pServiceProvider = nullptr;
20 | IVirtualDesktopManagerInternal* pDesktopManagerInternal = nullptr;
21 | IVirtualDesktopManager* pDesktopManager = nullptr;
22 | IApplicationViewCollection* viewCollection = nullptr;
23 | IVirtualDesktopPinnedApps* pinnedApps = nullptr;
24 | IVirtualDesktopNotificationService* pDesktopNotificationService = nullptr;
25 | BOOL registeredForNotifications = FALSE;
26 |
27 | DWORD idNotificationService = 0;
28 |
29 | struct ChangeDesktopAction {
30 | GUID newDesktopGuid;
31 | GUID oldDesktopGuid;
32 | };
33 |
34 | void _PostMessageToListeners(int msgOffset, WPARAM wParam, LPARAM lParam) {
35 | for each (std::pair listener in listeners) {
36 | PostMessage(listener.first, listener.second + msgOffset, wParam, lParam);
37 | }
38 | }
39 |
40 | void _RegisterService(BOOL force = FALSE) {
41 | if (force) {
42 | pServiceProvider = nullptr;
43 | pDesktopManagerInternal = nullptr;
44 | pDesktopManager = nullptr;
45 | viewCollection = nullptr;
46 | pinnedApps = nullptr;
47 | pDesktopNotificationService = nullptr;
48 | registeredForNotifications = FALSE;
49 | }
50 |
51 | if (pServiceProvider != nullptr) {
52 | return;
53 | }
54 | ::CoInitialize(NULL);
55 | ::CoCreateInstance(
56 | CLSID_ImmersiveShell, NULL, CLSCTX_LOCAL_SERVER,
57 | __uuidof(IServiceProvider), (PVOID*)&pServiceProvider);
58 |
59 | if (pServiceProvider == nullptr) {
60 | std::wcout << L"FATAL ERROR: pServiceProvider is null";
61 | return;
62 | }
63 | pServiceProvider->QueryService(__uuidof(IApplicationViewCollection), &viewCollection);
64 |
65 | pServiceProvider->QueryService(__uuidof(IVirtualDesktopManager), &pDesktopManager);
66 |
67 | pServiceProvider->QueryService(
68 | CLSID_VirtualDesktopPinnedApps,
69 | __uuidof(IVirtualDesktopPinnedApps), (PVOID*)&pinnedApps);
70 |
71 | pServiceProvider->QueryService(
72 | CLSID_VirtualDesktopManagerInternal,
73 | __uuidof(IVirtualDesktopManagerInternal), (PVOID*)&pDesktopManagerInternal);
74 |
75 | if (viewCollection == nullptr) {
76 | std::wcout << L"FATAL ERROR: viewCollection is null";
77 | return;
78 | }
79 |
80 | if (pDesktopManagerInternal == nullptr) {
81 | std::wcout << L"FATAL ERROR: pDesktopManagerInternal is null";
82 | return;
83 | }
84 |
85 | // Notification service
86 | HRESULT hrNotificationService = pServiceProvider->QueryService(
87 | CLSID_IVirtualNotificationService,
88 | __uuidof(IVirtualDesktopNotificationService),
89 | (PVOID*)&pDesktopNotificationService);
90 | }
91 |
92 |
93 | IApplicationView* _GetApplicationViewForHwnd(HWND hwnd) {
94 | if (hwnd == 0)
95 | return nullptr;
96 | IApplicationView* app = nullptr;
97 | viewCollection->GetViewForHwnd(hwnd, &app);
98 | return app;
99 | }
100 |
101 | void DllExport EnableKeepMinimized() {
102 | //_keepMinimized = true;
103 | }
104 |
105 | void DllExport RestoreMinimized() {
106 | }
107 |
108 | int DllExport GetDesktopCount()
109 | {
110 | _RegisterService();
111 |
112 | IObjectArray* pObjectArray = nullptr;
113 | HRESULT hr = pDesktopManagerInternal->GetDesktops(&pObjectArray);
114 |
115 | if (SUCCEEDED(hr))
116 | {
117 | UINT count;
118 | hr = pObjectArray->GetCount(&count);
119 | pObjectArray->Release();
120 | return count;
121 | }
122 |
123 | return -1;
124 | }
125 |
126 | int DllExport GetDesktopNumberById(GUID desktopId) {
127 | _RegisterService();
128 |
129 | IObjectArray* pObjectArray = nullptr;
130 | HRESULT hr = pDesktopManagerInternal->GetDesktops(&pObjectArray);
131 | int found = -1;
132 |
133 | if (SUCCEEDED(hr))
134 | {
135 | UINT count;
136 | hr = pObjectArray->GetCount(&count);
137 |
138 | if (SUCCEEDED(hr))
139 | {
140 | for (UINT i = 0; i < count; i++)
141 | {
142 | IVirtualDesktop* pDesktop = nullptr;
143 |
144 | if (FAILED(pObjectArray->GetAt(i, __uuidof(IVirtualDesktop), (void**)&pDesktop)))
145 | continue;
146 |
147 | GUID id = { 0 };
148 | if (SUCCEEDED(pDesktop->GetID(&id)) && id == desktopId)
149 | {
150 | found = i;
151 | pDesktop->Release();
152 | break;
153 | }
154 |
155 | pDesktop->Release();
156 | }
157 | }
158 |
159 | pObjectArray->Release();
160 | }
161 |
162 | return found;
163 | }
164 |
165 | IVirtualDesktop* _GetDesktopByNumber(int number) {
166 | _RegisterService();
167 |
168 | IObjectArray* pObjectArray = nullptr;
169 | HRESULT hr = pDesktopManagerInternal->GetDesktops(&pObjectArray);
170 | IVirtualDesktop* found = nullptr;
171 |
172 | if (SUCCEEDED(hr))
173 | {
174 | UINT count;
175 | hr = pObjectArray->GetCount(&count);
176 | pObjectArray->GetAt(number, __uuidof(IVirtualDesktop), (void**)&found);
177 | pObjectArray->Release();
178 | }
179 |
180 | return found;
181 | }
182 |
183 | GUID DllExport GetWindowDesktopId(HWND window) {
184 | _RegisterService();
185 |
186 | GUID pDesktopId = {};
187 | pDesktopManager->GetWindowDesktopId(window, &pDesktopId);
188 |
189 | return pDesktopId;
190 | }
191 |
192 | int DllExport GetWindowDesktopNumber(HWND window) {
193 | _RegisterService();
194 |
195 | GUID* pDesktopId = new GUID({ 0 });
196 | if (SUCCEEDED(pDesktopManager->GetWindowDesktopId(window, pDesktopId))) {
197 | return GetDesktopNumberById(*pDesktopId);
198 | }
199 |
200 | return -1;
201 | }
202 |
203 | int DllExport IsWindowOnCurrentVirtualDesktop(HWND window) {
204 | _RegisterService();
205 |
206 | BOOL b;
207 | if (SUCCEEDED(pDesktopManager->IsWindowOnCurrentVirtualDesktop(window, &b))) {
208 | return b;
209 | }
210 |
211 | return -1;
212 | }
213 |
214 | GUID DllExport GetDesktopIdByNumber(int number) {
215 | GUID id;
216 | IVirtualDesktop* pDesktop = _GetDesktopByNumber(number);
217 | if (pDesktop != nullptr) {
218 | pDesktop->GetID(&id);
219 | pDesktop->Release();
220 | }
221 | return id;
222 | }
223 |
224 |
225 | int DllExport IsWindowOnDesktopNumber(HWND window, int number) {
226 | _RegisterService();
227 | IApplicationView* app = nullptr;
228 | if (window == 0) {
229 | return -1;
230 | }
231 | viewCollection->GetViewForHwnd(window, &app);
232 | GUID desktopId = { 0 };
233 | app->GetVirtualDesktopId(&desktopId);
234 | GUID desktopCheckId = GetDesktopIdByNumber(number);
235 | app->Release();
236 | if (desktopCheckId == GUID_NULL || desktopId == GUID_NULL) {
237 | return -1;
238 | }
239 |
240 | if (GetDesktopIdByNumber(number) == desktopId) {
241 | return 1;
242 | }
243 | else {
244 | return 0;
245 | }
246 |
247 | return -1;
248 | }
249 |
250 | BOOL DllExport MoveWindowToDesktopNumber(HWND window, int number) {
251 | _RegisterService();
252 | IVirtualDesktop* pDesktop = _GetDesktopByNumber(number);
253 | if (pDesktopManager == nullptr) {
254 | std::wcout << L"ARRGH?";
255 | return false;
256 | }
257 | if (window == 0) {
258 | return false;
259 | }
260 | if (pDesktop != nullptr) {
261 | GUID id = { 0 };
262 | if (SUCCEEDED(pDesktop->GetID(&id))) {
263 | IApplicationView* app = nullptr;
264 | viewCollection->GetViewForHwnd(window, &app);
265 | if (app != nullptr) {
266 | pDesktopManagerInternal->MoveViewToDesktop(app, pDesktop);
267 | return true;
268 | }
269 | }
270 | }
271 | return false;
272 | }
273 |
274 | int DllExport GetDesktopNumber(IVirtualDesktop* pDesktop) {
275 | _RegisterService();
276 |
277 | if (pDesktop == nullptr) {
278 | return -1;
279 | }
280 |
281 | GUID guid;
282 |
283 | if (SUCCEEDED(pDesktop->GetID(&guid))) {
284 | return GetDesktopNumberById(guid);
285 | }
286 |
287 | return -1;
288 | }
289 | IVirtualDesktop* GetCurrentDesktop() {
290 | _RegisterService();
291 |
292 | if (pDesktopManagerInternal == nullptr) {
293 | return nullptr;
294 | }
295 | IVirtualDesktop* found = nullptr;
296 | pDesktopManagerInternal->GetCurrentDesktop(&found);
297 | return found;
298 | }
299 |
300 | int DllExport GetCurrentDesktopNumber() {
301 | IVirtualDesktop* virtualDesktop = GetCurrentDesktop();
302 | int number = GetDesktopNumber(virtualDesktop);
303 | virtualDesktop->Release();
304 | return number;
305 | }
306 |
307 | void DllExport GoToDesktopNumber(int number) {
308 | _RegisterService();
309 |
310 | if (pDesktopManagerInternal == nullptr) {
311 | return;
312 | }
313 |
314 | IVirtualDesktop* oldDesktop = GetCurrentDesktop();
315 | GUID oldId = { 0 };
316 | oldDesktop->GetID(&oldId);
317 | oldDesktop->Release();
318 |
319 | IObjectArray* pObjectArray = nullptr;
320 | HRESULT hr = pDesktopManagerInternal->GetDesktops(&pObjectArray);
321 | int found = -1;
322 |
323 | if (SUCCEEDED(hr))
324 | {
325 | UINT count;
326 | hr = pObjectArray->GetCount(&count);
327 |
328 | if (SUCCEEDED(hr))
329 | {
330 | for (UINT i = 0; i < count; i++)
331 | {
332 | IVirtualDesktop* pDesktop = nullptr;
333 |
334 | if (FAILED(pObjectArray->GetAt(i, __uuidof(IVirtualDesktop), (void**)&pDesktop)))
335 | continue;
336 |
337 | GUID id = { 0 };
338 | pDesktop->GetID(&id);
339 | if (i == number) {
340 | pDesktopManagerInternal->SwitchDesktop(pDesktop);
341 | }
342 |
343 | pDesktop->Release();
344 | }
345 | }
346 | pObjectArray->Release();
347 | }
348 | }
349 |
350 | struct ShowWindowOnDesktopAction {
351 | int desktopNumber;
352 | int cmdShow;
353 | };
354 |
355 | LPWSTR _GetApplicationIdForHwnd(HWND hwnd) {
356 | if (hwnd == 0)
357 | return nullptr;
358 | IApplicationView* app = _GetApplicationViewForHwnd(hwnd);
359 | if (app != nullptr) {
360 | LPWSTR appId = new TCHAR[1024];
361 | app->GetAppUserModelId(&appId);
362 | app->Release();
363 | return appId;
364 | }
365 | return nullptr;
366 | }
367 |
368 | int DllExport IsPinnedWindow(HWND hwnd) {
369 | if (hwnd == 0)
370 | return -1;
371 | _RegisterService();
372 | IApplicationView* pView = _GetApplicationViewForHwnd(hwnd);
373 | BOOL isPinned = false;
374 | if (pView != nullptr) {
375 | pinnedApps->IsViewPinned(pView, &isPinned);
376 | pView->Release();
377 | if (isPinned) {
378 | return 1;
379 | }
380 | else {
381 | return 0;
382 | }
383 | }
384 |
385 | return -1;
386 | }
387 |
388 | void DllExport PinWindow(HWND hwnd) {
389 | if (hwnd == 0)
390 | return;
391 | _RegisterService();
392 | IApplicationView* pView = _GetApplicationViewForHwnd(hwnd);
393 | if (pView != nullptr) {
394 | pinnedApps->PinView(pView);
395 | pView->Release();
396 | }
397 | }
398 |
399 | void DllExport UnPinWindow(HWND hwnd) {
400 | if (hwnd == 0)
401 | return;
402 | _RegisterService();
403 | IApplicationView* pView = _GetApplicationViewForHwnd(hwnd);
404 | if (pView != nullptr) {
405 | pinnedApps->UnpinView(pView);
406 | pView->Release();
407 | }
408 | }
409 |
410 | int DllExport IsPinnedApp(HWND hwnd) {
411 | if (hwnd == 0)
412 | return -1;
413 | _RegisterService();
414 | LPWSTR appId = _GetApplicationIdForHwnd(hwnd);
415 | if (appId != nullptr) {
416 | BOOL isPinned = false;
417 | pinnedApps->IsAppIdPinned(appId, &isPinned);
418 | if (isPinned) {
419 | return 1;
420 | }
421 | else {
422 | return 0;
423 | }
424 | }
425 | return -1;
426 | }
427 |
428 | void DllExport PinApp(HWND hwnd) {
429 | if (hwnd == 0)
430 | return;
431 | _RegisterService();
432 | LPWSTR appId = _GetApplicationIdForHwnd(hwnd);
433 | if (appId != nullptr) {
434 | pinnedApps->PinAppID(appId);
435 | }
436 | }
437 |
438 | void DllExport UnPinApp(HWND hwnd) {
439 | if (hwnd == 0)
440 | return;
441 | _RegisterService();
442 | LPWSTR appId = _GetApplicationIdForHwnd(hwnd);
443 | if (appId != nullptr) {
444 | pinnedApps->UnpinAppID(appId);
445 | }
446 | }
447 |
448 | class _Notifications : public IVirtualDesktopNotification {
449 | private:
450 | ULONG _referenceCount;
451 | public:
452 | // Inherited via IVirtualDesktopNotification
453 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override
454 | {
455 | // Always set out parameter to NULL, validating it first.
456 | if (!ppvObject)
457 | return E_INVALIDARG;
458 | *ppvObject = NULL;
459 |
460 | if (riid == IID_IUnknown || riid == IID_IVirtualDesktopNotification)
461 | {
462 | // Increment the reference count and return the pointer.
463 | *ppvObject = (LPVOID)this;
464 | AddRef();
465 | return S_OK;
466 | }
467 | return E_NOINTERFACE;
468 | }
469 |
470 | virtual ULONG STDMETHODCALLTYPE AddRef() override
471 | {
472 | return InterlockedIncrement(&_referenceCount);
473 | }
474 |
475 | virtual ULONG STDMETHODCALLTYPE Release() override
476 | {
477 | ULONG result = InterlockedDecrement(&_referenceCount);
478 | if (result == 0)
479 | {
480 | delete this;
481 | }
482 | return 0;
483 | }
484 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopCreated(IVirtualDesktop* pDesktop) override
485 | {
486 | _PostMessageToListeners(VDA_VirtualDesktopCreated, GetDesktopNumber(pDesktop), 0);
487 | return S_OK;
488 | }
489 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyBegin(IVirtualDesktop* pDesktopDestroyed,
490 | IVirtualDesktop* pDesktopFallback) override
491 | {
492 | _PostMessageToListeners(VDA_VirtualDesktopDestroyBegin,
493 | GetDesktopNumber(pDesktopDestroyed),
494 | GetDesktopNumber(pDesktopFallback));
495 | return S_OK;
496 | }
497 |
498 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyFailed(
499 | IVirtualDesktop* pDesktopDestroyed, IVirtualDesktop* pDesktopFallback) override
500 | {
501 | _PostMessageToListeners(VDA_VirtualDesktopDestroyFailed,
502 | GetDesktopNumber(pDesktopDestroyed),
503 | GetDesktopNumber(pDesktopFallback));
504 | return S_OK;
505 | }
506 |
507 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyed(
508 | IVirtualDesktop* pDesktopDestroyed, IVirtualDesktop* pDesktopFallback) override
509 | {
510 | _PostMessageToListeners(VDA_VirtualDesktopDestroyed,
511 | GetDesktopNumber(pDesktopDestroyed),
512 | GetDesktopNumber(pDesktopFallback));
513 | return S_OK;
514 | }
515 |
516 | virtual HRESULT STDMETHODCALLTYPE ViewVirtualDesktopChanged(IApplicationView* pView) override
517 | {
518 | _PostMessageToListeners(VDA_ViewVirtualDesktopChanged, 0, 0);
519 | return S_OK;
520 | }
521 |
522 | virtual HRESULT STDMETHODCALLTYPE CurrentVirtualDesktopChanged(
523 | IVirtualDesktop* pDesktopOld,
524 | IVirtualDesktop* pDesktopNew) override
525 | {
526 | // not sure how/why this happens but have crash dump where it did.
527 | if (pDesktopOld == nullptr && pDesktopNew == nullptr) {
528 | return S_OK;
529 | }
530 |
531 | viewCollection->RefreshCollection();
532 |
533 | ChangeDesktopAction act;
534 | if (pDesktopOld != nullptr) {
535 | pDesktopOld->GetID(&act.oldDesktopGuid);
536 | }
537 |
538 | if (pDesktopNew != nullptr) {
539 | pDesktopNew->GetID(&act.newDesktopGuid);
540 | }
541 |
542 | _PostMessageToListeners(VDA_CurrentVirtualDesktopChanged,
543 | GetDesktopNumberById(act.oldDesktopGuid),
544 | GetDesktopNumberById(act.newDesktopGuid));
545 | return S_OK;
546 | }
547 |
548 | virtual HRESULT __stdcall VirtualDesktopMoved(
549 | IVirtualDesktop* pDesktop, UINT64 oldIndex, UINT64 newIndex) override {
550 | return S_OK;
551 | }
552 |
553 | virtual HRESULT __stdcall VirtualDesktopNameChanged(IVirtualDesktop* pDesktop, HSTRING name) override {
554 | return S_OK;
555 | }
556 |
557 | virtual HRESULT __stdcall VirtualDesktopWallpaperChanged(IVirtualDesktop* pDesktop, HSTRING name) override {
558 | return S_OK;
559 | }
560 |
561 | virtual HRESULT __stdcall VirtualDesktopSwitched(IVirtualDesktop* pDesktopNew) override {
562 | return S_OK;
563 | }
564 |
565 | virtual HRESULT __stdcall RemoteVirtualDesktopConnected(IVirtualDesktop* remoteVirtualDesktop) override {
566 | return S_OK;
567 | }
568 | };
569 |
570 | void _RegisterDesktopNotifications() {
571 | _RegisterService();
572 | if (pDesktopNotificationService == nullptr) {
573 | return;
574 | }
575 | if (registeredForNotifications) {
576 | return;
577 | }
578 | _Notifications* nf = new _Notifications();
579 | HRESULT res = pDesktopNotificationService->Register(nf, &idNotificationService);
580 | if (SUCCEEDED(res)) {
581 | registeredForNotifications = TRUE;
582 | }
583 | }
584 |
585 | void DllExport RestartVirtualDesktopAccessor() {
586 | _RegisterService(TRUE);
587 | _RegisterDesktopNotifications();
588 | }
589 |
590 | void DllExport RegisterPostMessageHook(HWND listener, int messageOffset) {
591 | _RegisterService();
592 |
593 | listeners.insert(std::pair(listener, messageOffset));
594 | if (listeners.size() != 1) {
595 | return;
596 | }
597 | _RegisterDesktopNotifications();
598 | }
599 |
600 | void DllExport UnregisterPostMessageHook(HWND hwnd) {
601 | _RegisterService();
602 |
603 | listeners.erase(hwnd);
604 | if (listeners.size() != 0) {
605 | return;
606 | }
607 |
608 | if (pDesktopNotificationService == nullptr) {
609 | return;
610 | }
611 |
612 | if (idNotificationService > 0) {
613 | registeredForNotifications = TRUE;
614 | pDesktopNotificationService->Unregister(idNotificationService);
615 | }
616 | }
617 |
618 | VOID _OpenDllWindow(HINSTANCE injModule) {
619 | }
620 |
--------------------------------------------------------------------------------
/VirtualDesktopAccessor/stdafx.cpp:
--------------------------------------------------------------------------------
1 | // stdafx.cpp : source file that includes just the standard includes
2 | // VirtualDesktopAccessor.pch will be the pre-compiled header
3 | // stdafx.obj will contain the pre-compiled type information
4 |
5 | #include "stdafx.h"
6 |
7 | // TODO: reference any additional headers you need in STDAFX.H
8 | // and not in this file
9 |
--------------------------------------------------------------------------------
/VirtualDesktopAccessor/stdafx.h:
--------------------------------------------------------------------------------
1 | // stdafx.h : include file for standard system include files,
2 | // or project specific include files that are used frequently, but
3 | // are changed infrequently
4 | //
5 |
6 | #pragma once
7 |
8 | #include "targetver.h"
9 |
10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
11 | // Windows Header Files:
12 | #include
13 | #include
14 |
15 | #include
16 | #include
17 |
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include