├── .gitattributes ├── .gitignore ├── API ├── RainmeterAPI.h ├── Win32 │ └── Rainmeter.lib └── x64 │ └── Rainmeter.lib ├── HISTORY.txt ├── LICENSE.txt ├── README.md ├── RMSKIN.ini ├── Skins └── VirtualDesktopDemo │ └── VirtualDesktop │ └── VirtualDesktop.ini ├── Utils ├── MakeRmsSkin.ps1 └── Package.bat ├── VirtualDesktop.sln └── src ├── ComUtils.h ├── Default.props ├── VDNotification.cpp ├── VDNotification.h ├── VDUtils.cpp ├── VDUtils.h ├── VirtualDesktop.cpp ├── VirtualDesktop.rc ├── VirtualDesktop.vcxproj └── Win10Desktops.h /.gitattributes: -------------------------------------------------------------------------------- 1 | API/* linguist-vendored 2 | Utils/* linguist-vendored 3 | 4 | ############################################################################### 5 | # Set default behavior to automatically normalize line endings. 6 | ############################################################################### 7 | * text=auto 8 | 9 | ############################################################################### 10 | # Set default behavior for command prompt diff. 11 | # 12 | # This is need for earlier builds of msysgit that does not have it on by 13 | # default for csharp files. 14 | # Note: This is only used by command line 15 | ############################################################################### 16 | #*.cs diff=csharp 17 | 18 | ############################################################################### 19 | # Set the merge driver for project and solution files 20 | # 21 | # Merging from the command prompt will add diff markers to the files if there 22 | # are conflicts (Merging from VS is not affected by the settings below, in VS 23 | # the diff markers are never inserted). Diff markers may cause the following 24 | # file extensions to fail to load in VS. An alternative would be to treat 25 | # these files as binary and thus will always conflict and require user 26 | # intervention with every merge. To do so, just uncomment the entries below 27 | ############################################################################### 28 | #*.sln merge=binary 29 | #*.csproj merge=binary 30 | #*.vbproj merge=binary 31 | #*.vcxproj merge=binary 32 | #*.vcproj merge=binary 33 | #*.dbproj merge=binary 34 | #*.fsproj merge=binary 35 | #*.lsproj merge=binary 36 | #*.wixproj merge=binary 37 | #*.modelproj merge=binary 38 | #*.sqlproj merge=binary 39 | #*.wwaproj merge=binary 40 | 41 | ############################################################################### 42 | # behavior for image files 43 | # 44 | # image files are treated as binary by default. 45 | ############################################################################### 46 | #*.jpg binary 47 | #*.png binary 48 | #*.gif binary 49 | 50 | ############################################################################### 51 | # diff behavior for common document formats 52 | # 53 | # Convert binary document formats to text before diffing them. This feature 54 | # is only available from the command line. Turn it on by uncommenting the 55 | # entries below. 56 | ############################################################################### 57 | #*.doc diff=astextplain 58 | #*.DOC diff=astextplain 59 | #*.docx diff=astextplain 60 | #*.DOCX diff=astextplain 61 | #*.dot diff=astextplain 62 | #*.DOT diff=astextplain 63 | #*.pdf diff=astextplain 64 | #*.PDF diff=astextplain 65 | #*.rtf diff=astextplain 66 | #*.RTF diff=astextplain 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Local.* 2 | Plugins 3 | *.rmskin 4 | 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | ## 8 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 9 | 10 | # User-specific files 11 | *.rsuser 12 | *.suo 13 | *.user 14 | *.userosscache 15 | *.sln.docstates 16 | 17 | # User-specific files (MonoDevelop/Xamarin Studio) 18 | *.userprefs 19 | 20 | # Mono auto generated files 21 | mono_crash.* 22 | 23 | # Build results 24 | [Dd]ebug/ 25 | [Dd]ebugPublic/ 26 | [Rr]elease/ 27 | [Rr]eleases/ 28 | x64/ 29 | x86/ 30 | [Ww][Ii][Nn]32/ 31 | [Aa][Rr][Mm]/ 32 | [Aa][Rr][Mm]64/ 33 | bld/ 34 | [Bb]in/ 35 | [Oo]bj/ 36 | [Oo]ut/ 37 | [Ll]og/ 38 | [Ll]ogs/ 39 | [Ii]nt/ 40 | 41 | # Visual Studio 2015/2017 cache/options directory 42 | .vs/ 43 | # Uncomment if you have tasks that create the project's static files in wwwroot 44 | #wwwroot/ 45 | 46 | # Visual Studio 2017 auto generated files 47 | Generated\ Files/ 48 | 49 | # MSTest test Results 50 | [Tt]est[Rr]esult*/ 51 | [Bb]uild[Ll]og.* 52 | 53 | # NUnit 54 | *.VisualState.xml 55 | TestResult.xml 56 | nunit-*.xml 57 | 58 | # Build Results of an ATL Project 59 | [Dd]ebugPS/ 60 | [Rr]eleasePS/ 61 | dlldata.c 62 | 63 | # Benchmark Results 64 | BenchmarkDotNet.Artifacts/ 65 | 66 | # .NET Core 67 | project.lock.json 68 | project.fragment.lock.json 69 | artifacts/ 70 | 71 | # ASP.NET Scaffolding 72 | ScaffoldingReadMe.txt 73 | 74 | # StyleCop 75 | StyleCopReport.xml 76 | 77 | # Files built by Visual Studio 78 | *_i.c 79 | *_p.c 80 | *_h.h 81 | *.ilk 82 | *.meta 83 | *.obj 84 | *.iobj 85 | *.pch 86 | *.pdb 87 | *.ipdb 88 | *.pgc 89 | *.pgd 90 | *.rsp 91 | *.sbr 92 | *.tlb 93 | *.tli 94 | *.tlh 95 | *.tmp 96 | *.tmp_proj 97 | *_wpftmp.csproj 98 | *.log 99 | *.vspscc 100 | *.vssscc 101 | .builds 102 | *.pidb 103 | *.svclog 104 | *.scc 105 | 106 | # Chutzpah Test files 107 | _Chutzpah* 108 | 109 | # Visual C++ cache files 110 | ipch/ 111 | *.aps 112 | *.ncb 113 | *.opendb 114 | *.opensdf 115 | *.sdf 116 | *.cachefile 117 | *.VC.db 118 | *.VC.VC.opendb 119 | 120 | # Visual Studio profiler 121 | *.psess 122 | *.vsp 123 | *.vspx 124 | *.sap 125 | 126 | # Visual Studio Trace Files 127 | *.e2e 128 | 129 | # TFS 2012 Local Workspace 130 | $tf/ 131 | 132 | # Guidance Automation Toolkit 133 | *.gpState 134 | 135 | # ReSharper is a .NET coding add-in 136 | _ReSharper*/ 137 | *.[Rr]e[Ss]harper 138 | *.DotSettings.user 139 | 140 | # TeamCity is a build add-in 141 | _TeamCity* 142 | 143 | # DotCover is a Code Coverage Tool 144 | *.dotCover 145 | 146 | # AxoCover is a Code Coverage Tool 147 | .axoCover/* 148 | !.axoCover/settings.json 149 | 150 | # Coverlet is a free, cross platform Code Coverage Tool 151 | coverage*.json 152 | coverage*.xml 153 | coverage*.info 154 | 155 | # Visual Studio code coverage results 156 | *.coverage 157 | *.coveragexml 158 | 159 | # NCrunch 160 | _NCrunch_* 161 | .*crunch*.local.xml 162 | nCrunchTemp_* 163 | 164 | # MightyMoose 165 | *.mm.* 166 | AutoTest.Net/ 167 | 168 | # Web workbench (sass) 169 | .sass-cache/ 170 | 171 | # Installshield output folder 172 | [Ee]xpress/ 173 | 174 | # DocProject is a documentation generator add-in 175 | DocProject/buildhelp/ 176 | DocProject/Help/*.HxT 177 | DocProject/Help/*.HxC 178 | DocProject/Help/*.hhc 179 | DocProject/Help/*.hhk 180 | DocProject/Help/*.hhp 181 | DocProject/Help/Html2 182 | DocProject/Help/html 183 | 184 | # Click-Once directory 185 | publish/ 186 | 187 | # Publish Web Output 188 | *.[Pp]ublish.xml 189 | *.azurePubxml 190 | # Note: Comment the next line if you want to checkin your web deploy settings, 191 | # but database connection strings (with potential passwords) will be unencrypted 192 | *.pubxml 193 | *.publishproj 194 | 195 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 196 | # checkin your Azure Web App publish settings, but sensitive information contained 197 | # in these scripts will be unencrypted 198 | PublishScripts/ 199 | 200 | # NuGet Packages 201 | *.nupkg 202 | # NuGet Symbol Packages 203 | *.snupkg 204 | # The packages folder can be ignored because of Package Restore 205 | **/[Pp]ackages/* 206 | # except build/, which is used as an MSBuild target. 207 | !**/[Pp]ackages/build/ 208 | # Uncomment if necessary however generally it will be regenerated when needed 209 | #!**/[Pp]ackages/repositories.config 210 | # NuGet v3's project.json files produces more ignorable files 211 | *.nuget.props 212 | *.nuget.targets 213 | 214 | # Microsoft Azure Build Output 215 | csx/ 216 | *.build.csdef 217 | 218 | # Microsoft Azure Emulator 219 | ecf/ 220 | rcf/ 221 | 222 | # Windows Store app package directories and files 223 | AppPackages/ 224 | BundleArtifacts/ 225 | Package.StoreAssociation.xml 226 | _pkginfo.txt 227 | *.appx 228 | *.appxbundle 229 | *.appxupload 230 | 231 | # Visual Studio cache files 232 | # files ending in .cache can be ignored 233 | *.[Cc]ache 234 | # but keep track of directories ending in .cache 235 | !?*.[Cc]ache/ 236 | 237 | # Others 238 | ClientBin/ 239 | ~$* 240 | *~ 241 | *.dbmdl 242 | *.dbproj.schemaview 243 | *.jfm 244 | *.pfx 245 | *.publishsettings 246 | orleans.codegen.cs 247 | 248 | # Including strong name files can present a security risk 249 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 250 | #*.snk 251 | 252 | # Since there are multiple workflows, uncomment next line to ignore bower_components 253 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 254 | #bower_components/ 255 | 256 | # RIA/Silverlight projects 257 | Generated_Code/ 258 | 259 | # Backup & report files from converting an old project file 260 | # to a newer Visual Studio version. Backup files are not needed, 261 | # because we have git ;-) 262 | _UpgradeReport_Files/ 263 | Backup*/ 264 | UpgradeLog*.XML 265 | UpgradeLog*.htm 266 | ServiceFabricBackup/ 267 | *.rptproj.bak 268 | 269 | # SQL Server files 270 | *.mdf 271 | *.ldf 272 | *.ndf 273 | 274 | # Business Intelligence projects 275 | *.rdl.data 276 | *.bim.layout 277 | *.bim_*.settings 278 | *.rptproj.rsuser 279 | *- [Bb]ackup.rdl 280 | *- [Bb]ackup ([0-9]).rdl 281 | *- [Bb]ackup ([0-9][0-9]).rdl 282 | 283 | # Microsoft Fakes 284 | FakesAssemblies/ 285 | 286 | # GhostDoc plugin setting file 287 | *.GhostDoc.xml 288 | 289 | # Node.js Tools for Visual Studio 290 | .ntvs_analysis.dat 291 | node_modules/ 292 | 293 | # Visual Studio 6 build log 294 | *.plg 295 | 296 | # Visual Studio 6 workspace options file 297 | *.opt 298 | 299 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 300 | *.vbw 301 | 302 | # Visual Studio LightSwitch build output 303 | **/*.HTMLClient/GeneratedArtifacts 304 | **/*.DesktopClient/GeneratedArtifacts 305 | **/*.DesktopClient/ModelManifest.xml 306 | **/*.Server/GeneratedArtifacts 307 | **/*.Server/ModelManifest.xml 308 | _Pvt_Extensions 309 | 310 | # Paket dependency manager 311 | .paket/paket.exe 312 | paket-files/ 313 | 314 | # FAKE - F# Make 315 | .fake/ 316 | 317 | # CodeRush personal settings 318 | .cr/personal 319 | 320 | # Python Tools for Visual Studio (PTVS) 321 | __pycache__/ 322 | *.pyc 323 | 324 | # Cake - Uncomment if you are using it 325 | # tools/** 326 | # !tools/packages.config 327 | 328 | # Tabs Studio 329 | *.tss 330 | 331 | # Telerik's JustMock configuration file 332 | *.jmconfig 333 | 334 | # BizTalk build output 335 | *.btp.cs 336 | *.btm.cs 337 | *.odx.cs 338 | *.xsd.cs 339 | 340 | # OpenCover UI analysis results 341 | OpenCover/ 342 | 343 | # Azure Stream Analytics local run output 344 | ASALocalRun/ 345 | 346 | # MSBuild Binary and Structured Log 347 | *.binlog 348 | 349 | # NVidia Nsight GPU debugger configuration file 350 | *.nvuser 351 | 352 | # MFractors (Xamarin productivity tool) working folder 353 | .mfractor/ 354 | 355 | # Local History for Visual Studio 356 | .localhistory/ 357 | 358 | # BeatPulse healthcheck temp database 359 | healthchecksdb 360 | 361 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 362 | MigrationBackup/ 363 | 364 | # Ionide (cross platform F# VS Code tools) working folder 365 | .ionide/ 366 | 367 | # Fody - auto-generated XML schema 368 | FodyWeavers.xsd -------------------------------------------------------------------------------- /API/RainmeterAPI.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2011 Rainmeter Project Developers 2 | * 3 | * This Source Code Form is subject to the terms of the GNU General Public 4 | * License; either version 2 of the License, or (at your option) any later 5 | * version. If a copy of the GPL was not distributed with this file, You can 6 | * obtain one at . */ 7 | 8 | #ifndef __RAINMETERAPI_H__ 9 | #define __RAINMETERAPI_H__ 10 | 11 | #ifdef LIBRARY_EXPORTS 12 | #define LIBRARY_EXPORT EXTERN_C 13 | #else 14 | #define LIBRARY_EXPORT EXTERN_C __declspec(dllimport) 15 | #endif // LIBRARY_EXPORTS 16 | 17 | #define PLUGIN_EXPORT EXTERN_C __declspec(dllexport) 18 | 19 | // 20 | // Exported functions 21 | // 22 | 23 | /// 24 | /// Retrieves the option defined in the skin file 25 | /// 26 | /// Pointer to the plugin measure 27 | /// Option name to be read from skin 28 | /// Default value for the option if it is not found or invalid 29 | /// If true, replaces section variables in the returned string 30 | /// Returns the option value as a string (LPCWSTR) 31 | /// 32 | /// 33 | /// PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue) 34 | /// { 35 | /// LPCWSTR value = RmReadString(rm, L"Value", L"DefaultValue"); 36 | /// LPCWSTR action = RmReadString(rm, L"Action", L"", FALSE); // [MeasureNames] will be parsed/replaced when the action is executed with RmExecute 37 | /// } 38 | /// 39 | /// 40 | #ifdef __cplusplus 41 | LIBRARY_EXPORT LPCWSTR __stdcall RmReadString(void* rm, LPCWSTR option, LPCWSTR defValue, BOOL replaceMeasures = TRUE); 42 | #else 43 | LIBRARY_EXPORT LPCWSTR __stdcall RmReadString(void* rm, LPCWSTR option, LPCWSTR defValue, BOOL replaceMeasures); 44 | #endif // __cplusplus 45 | 46 | /// 47 | /// Parses any formulas in the option (use RmReadDouble/RmReadInt instead) 48 | /// 49 | /// Pointer to the plugin measure 50 | /// Option name to be read from skin 51 | /// Default value for the option if it is not found, invalid, or a formula could not be parsed 52 | /// Returns the option value as an double 53 | /// 54 | /// 55 | /// PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue) 56 | /// { 57 | /// double value = RmReadFormula(rm, L"Value", 20); 58 | /// } 59 | /// 60 | /// 61 | LIBRARY_EXPORT double __stdcall RmReadFormula(void* rm, LPCWSTR option, double defValue); 62 | 63 | /// 64 | /// Returns a string, replacing any variables (or section variables) within the inputted string 65 | /// 66 | /// Pointer to the plugin measure 67 | /// String with unresolved variables 68 | /// Returns a string replacing any variables in the 'str' 69 | /// 70 | /// 71 | /// PLUGIN_EXPORT double Update(void* data) 72 | /// { 73 | /// Measure* measure = (Measure*)data; 74 | /// LPCWSTR myVar = RmReplaceVariables(measure->rm, L"#MyVar#"); // 'measure->rm' stored previously in the Initialize function 75 | /// if (_wcsicmp(myVar, L"SOMETHING") == 0) { return 1.0; } 76 | /// return 0.0; 77 | /// } 78 | /// 79 | /// 80 | LIBRARY_EXPORT LPCWSTR __stdcall RmReplaceVariables(void* rm, LPCWSTR str); 81 | 82 | /// 83 | /// Converts a relative path to a absolute path (use RmReadPath where appropriate) 84 | /// 85 | /// Pointer to the plugin measure 86 | /// String of path to be converted 87 | /// Returns the absolute path of the relativePath value as a string (LPCWSTR) 88 | /// 89 | /// 90 | /// PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue) 91 | /// { 92 | /// std::wstring somePath = L"..\\SomeFolder"; 93 | /// LPCWSTR path = RmPathToAbsolute(rm, somePath.c_str()); 94 | /// } 95 | /// 96 | /// 97 | LIBRARY_EXPORT LPCWSTR __stdcall RmPathToAbsolute(void* rm, LPCWSTR relativePath); 98 | 99 | /// 100 | /// Executes a command 101 | /// 102 | /// Pointer to current skin (See RmGetSkin) 103 | /// Bang to execute 104 | /// No return type 105 | /// 106 | /// 107 | /// PLUGIN_EXPORT double Update(void* data) 108 | /// { 109 | /// Measure* measure = (Measure*)data; 110 | /// RmExecute(measure->skin, L"!SetVariable SomeVar 10"); // 'measure->skin' stored previously in the Initialize function 111 | /// return 0.0; 112 | /// } 113 | /// 114 | /// 115 | LIBRARY_EXPORT void __stdcall RmExecute(void* skin, LPCWSTR command); 116 | 117 | /// 118 | /// Retrieves data from the measure or skin (use the helper functions instead) 119 | /// 120 | /// Call RmGet() in the Initialize function and store the results for later use 121 | /// Pointer to the plugin measure 122 | /// Type of information to retrieve (see RmGetType) 123 | /// Returns a pointer to an object which is determined by the 'type' 124 | /// 125 | /// 126 | /// PLUGIN_EXPORT void Initialize(void** data, void* rm) 127 | /// { 128 | /// Measure* measure = new Measure; 129 | /// *data = measure; 130 | /// measure->hwnd = RmGet(rm, RMG_SKINWINDOWHANDLE); // 'measure->hwnd' defined as HWND in class scope 131 | /// } 132 | /// 133 | /// 134 | LIBRARY_EXPORT void* __stdcall RmGet(void* rm, int type); 135 | 136 | enum RmGetType 137 | { 138 | RMG_MEASURENAME = 0, 139 | RMG_SKIN = 1, 140 | RMG_SETTINGSFILE = 2, 141 | RMG_SKINNAME = 3, 142 | RMG_SKINWINDOWHANDLE = 4 143 | }; 144 | 145 | /// 146 | /// Sends a message to the Rainmeter log with source 147 | /// 148 | /// LOG_DEBUG messages are logged only when Rainmeter is in debug mode 149 | /// Pointer to the plugin measure 150 | /// Log type (LOG_ERROR, LOG_WARNING, LOG_NOTICE, or LOG_DEBUG) 151 | /// Message to be logged 152 | /// No return type 153 | /// 154 | /// 155 | /// RmLog(rm, LOG_NOTICE, L"I am a 'notice' log message with a source"); 156 | /// 157 | /// 158 | LIBRARY_EXPORT void __stdcall RmLog(void* rm, int level, LPCWSTR message); 159 | 160 | /// 161 | /// Sends a formatted message to the Rainmeter log 162 | /// 163 | /// LOG_DEBUG messages are logged only when Rainmeter is in debug mode 164 | /// Pointer to the plugin measure 165 | /// Log level (LOG_ERROR, LOG_WARNING, LOG_NOTICE, or LOG_DEBUG) 166 | /// Formatted message to be logged, follows printf syntax 167 | /// Comma separated list of args referenced in the formatted message 168 | /// No return type 169 | /// 170 | /// 171 | /// std::wstring notice = L"notice"; 172 | /// RmLogF(rm, LOG_NOTICE, L"I am a '%s' log message with a source", notice.c_str()); 173 | /// 174 | /// 175 | LIBRARY_EXPORT void __cdecl RmLogF(void* rm, int level, LPCWSTR format, ...); 176 | 177 | /// 178 | /// DEPRECATED: Use RmLog. Sends a message to the Rainmeter log. 179 | /// 180 | LIBRARY_EXPORT BOOL __cdecl LSLog(int level, LPCWSTR unused, LPCWSTR message); 181 | 182 | // 183 | // Wrapper functions 184 | // 185 | 186 | #ifndef LIBRARY_EXPORTS 187 | /// 188 | /// Retrieves the option defined in the skin file and converts a relative path to a absolute path 189 | /// 190 | /// Pointer to the plugin measure 191 | /// Option name to be read from skin 192 | /// Default value for the option if it is not found or invalid 193 | /// Returns the absolute path of the option value as a string (LPCWSTR) 194 | /// 195 | /// 196 | /// PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue) 197 | /// { 198 | /// LPCWSTR path = RmReadPath(rm, L"MyPath", L"C:\\"); 199 | /// } 200 | /// 201 | /// 202 | __inline LPCWSTR RmReadPath(void* rm, LPCWSTR option, LPCWSTR defValue) 203 | { 204 | LPCWSTR relativePath = RmReadString(rm, option, defValue, TRUE); 205 | return RmPathToAbsolute(rm, relativePath); 206 | } 207 | 208 | /// 209 | /// Retrieves the option defined in the skin file and converts it to an integer 210 | /// 211 | /// If the option is a formula, the returned value will be the result of the parsed formula 212 | /// Pointer to the plugin measure 213 | /// Option name to be read from skin 214 | /// Default value for the option if it is not found, invalid, or a formula could not be parsed 215 | /// Returns the option value as an integer 216 | /// 217 | /// 218 | /// PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue) 219 | /// { 220 | /// int value = RmReadInt(rm, L"Value", 20); 221 | /// } 222 | /// 223 | /// 224 | __inline int RmReadInt(void* rm, LPCWSTR option, int defValue) 225 | { 226 | return (int)RmReadFormula(rm, option, defValue); 227 | } 228 | 229 | /// 230 | /// Retrieves the option defined in the skin file and converts it to a double 231 | /// 232 | /// If the option is a formula, the returned value will be the result of the parsed formula 233 | /// Pointer to the plugin measure 234 | /// Option name to read from skin 235 | /// Default value for the option if it is not found, invalid, or a formula could not be parsed 236 | /// Returns the option value as a double 237 | /// 238 | /// 239 | /// PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue) 240 | /// { 241 | /// double value = RmReadDouble(rm, L"Value", 20.0); 242 | /// } 243 | /// 244 | /// 245 | __inline double RmReadDouble(void* rm, LPCWSTR option, double defValue) 246 | { 247 | return RmReadFormula(rm, option, defValue); 248 | } 249 | 250 | /// 251 | /// Retrieves the name of the measure 252 | /// 253 | /// Call RmGetMeasureName() in the Initialize function and store the results for later use 254 | /// Pointer to the plugin measure 255 | /// Returns the current measure name as a string (LPCWSTR) 256 | /// 257 | /// 258 | /// PLUGIN_EXPORT void Initialize(void** data, void* rm) 259 | /// { 260 | /// Measure* measure = new Measure; 261 | /// *data = measure; 262 | /// measure->myName = RmGetMeasureName(rm); // 'measure->myName' defined as a string (LPCWSTR) in class scope 263 | /// } 264 | /// 265 | /// 266 | __inline LPCWSTR RmGetMeasureName(void* rm) 267 | { 268 | return (LPCWSTR)RmGet(rm, RMG_MEASURENAME); 269 | } 270 | 271 | /// 272 | /// Retrieves a path to the Rainmeter data file (Rainmeter.data). 273 | /// 274 | /// Call GetSettingsFile() in the Initialize function and store the results for later use 275 | /// Returns the path and filename of the Rainmeter data file as a string (LPCWSTR) 276 | /// 277 | /// 278 | /// PLUGIN_EXPORT void Initialize(void** data, void* rm) 279 | /// { 280 | /// Measure* measure = new Measure; 281 | /// *data = measure; 282 | /// if (rmDataFile == nullptr) { rmDataFile = RmGetSettingsFile(); } // 'rmDataFile' defined as a string (LPCWSTR) in global scope 283 | /// } 284 | /// 285 | /// 286 | __inline LPCWSTR RmGetSettingsFile() 287 | { 288 | return (LPCWSTR)RmGet(NULL, RMG_SETTINGSFILE); 289 | } 290 | 291 | /// 292 | /// Retrieves an internal pointer to the current skin 293 | /// 294 | /// Call GetSkin() in the Initialize function and store the results for later use 295 | /// Pointer to the plugin measure 296 | /// Returns a pointer to the current skin 297 | /// 298 | /// 299 | /// PLUGIN_EXPORT void Initialize(void** data, void* rm) 300 | /// { 301 | /// Measure* measure = new Measure; 302 | /// *data = measure; 303 | /// measure->mySkin = RmGetSkin(rm); // 'measure->mySkin' defined as a 'void*' in class scope 304 | /// } 305 | /// 306 | /// 307 | __inline void* RmGetSkin(void* rm) 308 | { 309 | return (void*)RmGet(rm, RMG_SKIN); 310 | } 311 | 312 | /// 313 | /// Retrieves full path and name of the skin 314 | /// 315 | /// Call GetSkinName() in the Initialize function and store the results for later use 316 | /// Pointer to the plugin measure 317 | /// Returns the path and filename of the skin as a string (LPCWSTR) 318 | /// 319 | /// 320 | /// PLUGIN_EXPORT void Initialize(void** data, void* rm) 321 | /// { 322 | /// Measure* measure = new Measure; 323 | /// *data = measure; 324 | /// skinName = RmGetSkinName(rm); } // 'measure->skinName' defined as a string (LPCWSTR) in class scope 325 | /// } 326 | /// 327 | /// 328 | __inline LPCWSTR RmGetSkinName(void* rm) 329 | { 330 | return (LPCWSTR)RmGet(rm, RMG_SKINNAME); 331 | } 332 | 333 | /// 334 | /// Returns a pointer to the handle of the skin window (HWND) 335 | /// 336 | /// Call GetSkinWindow() in the Initialize function and store the results for later use 337 | /// Pointer to the plugin measure 338 | /// Returns a handle to the skin window as a HWND 339 | /// 340 | /// 341 | /// PLUGIN_EXPORT void Initialize(void** data, void* rm) 342 | /// { 343 | /// Measure* measure = new Measure; 344 | /// *data = measure; 345 | /// measure->skinWindow = RmGetSkinWindow(rm); } // 'measure->skinWindow' defined as HWND in class scope 346 | /// } 347 | /// 348 | /// 349 | __inline HWND RmGetSkinWindow(void* rm) 350 | { 351 | return (HWND)RmGet(rm, RMG_SKINWINDOWHANDLE); 352 | } 353 | 354 | /// 355 | /// DEPRECATED: Use RmLog(rm, type, message). Sends a message to the Rainmeter log. 356 | /// 357 | __inline void RmLog(int level, LPCWSTR message) 358 | { 359 | LSLog(level, NULL, message); 360 | } 361 | 362 | enum LOGLEVEL 363 | { 364 | LOG_ERROR = 1, 365 | LOG_WARNING = 2, 366 | LOG_NOTICE = 3, 367 | LOG_DEBUG = 4 368 | }; 369 | #endif // LIBRARY_EXPORTS 370 | 371 | #endif 372 | -------------------------------------------------------------------------------- /API/Win32/Rainmeter.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RadAd/RMVirtualDesktop/dd32ebec6028ba78b58339471d886388c4d1d4a1/API/Win32/Rainmeter.lib -------------------------------------------------------------------------------- /API/x64/Rainmeter.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RadAd/RMVirtualDesktop/dd32ebec6028ba78b58339471d886388c4d1d4a1/API/x64/Rainmeter.lib -------------------------------------------------------------------------------- /HISTORY.txt: -------------------------------------------------------------------------------- 1 | [Version 1.4] 2 | Get wallpaper: 3 | MeasureVirtualDesktop:Wallpaper 4 | New bangs: 5 | SetName [desktop_num] [new_name] 6 | SetWallpaper [desktop_num] [new_wallpaper] 7 | 8 | [Version 1.3] 9 | Create Window 11 version 10 | 11 | [Version 1.2] 12 | 13 | [Version 1.1] 14 | Change desktop number system to 1-based 15 | 16 | [Version 1.0] 17 | Initial version 18 | -------------------------------------------------------------------------------- /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.md: -------------------------------------------------------------------------------- 1 | # RMVirtualDesktop 2 | Virtual desktop functionality for [Rainmeter](https://www.rainmeter.net/) 3 | 4 | ![Windows](https://img.shields.io/badge/platform-Windows-blue.svg) 5 | [![Releases](https://img.shields.io/github/release/RadAd/RMVirtualDesktop.svg)](https://github.com/RadAd/RMVirtualDesktop/releases/latest) 6 | [![commits-since](https://img.shields.io/github/commits-since/RadAd/RMVirtualDesktop/latest.svg)](commits/master) 7 | [![Build](https://img.shields.io/appveyor/ci/RadAd/RMVirtualDesktop.svg)](https://ci.appveyor.com/project/RadAd/RMVirtualDesktop) 8 | -------------------------------------------------------------------------------- /RMSKIN.ini: -------------------------------------------------------------------------------- 1 | [rmskin] 2 | Name=Virtual Desktop Plugin Demo 3 | Author=Adam Gates 4 | Version=1.1 5 | MinimumRainmeter=4.5.9.3592 6 | MinimumWindows=10.0 7 | -------------------------------------------------------------------------------- /Skins/VirtualDesktopDemo/VirtualDesktop/VirtualDesktop.ini: -------------------------------------------------------------------------------- 1 | [Metadata] 2 | Name=Virtual Desktop Demo 3 | Author=Adam Gates 4 | Information=Demonstrates the VirtualDesktop plugin 5 | License=Creative Commons BY-NC-SA 4.0 6 | Version=1.1.0 7 | 8 | [Rainmeter] 9 | Update=10000 10 | DynamicWindowSize=1 11 | BackgroundMode=2 12 | SolidColor=0,0,0 13 | ContextTitle=Create Desktop 14 | ContextAction=[!CommandMeasure MeasureVirtualDesktop "Create"] 15 | ContextTitle2=Remove Desktop 16 | ContextAction2=[!CommandMeasure MeasureVirtualDesktop "Remove"] 17 | 18 | [Variables] 19 | TextColor=255,255,255,255 20 | ButtonTextColor=0,0,0,255 21 | NormalColor=255,255,255,255 22 | SelectedColor=9,134,9,255 23 | PressedColor=9,200,9,255 24 | OverColor=9,255,9,255 25 | 26 | [StyleText] 27 | X=R 28 | Y=r 29 | FontColor=#TextColor# 30 | FontSize=14 31 | AntiAlias=1 32 | 33 | [ButtonText] 34 | X=9r 35 | Y=10r 36 | StringAlign=CenterCenter 37 | FontColor=#ButtonTextColor# 38 | 39 | [StyleSolidButton] 40 | X=2R 41 | Y=r 42 | W=20 43 | H=20 44 | SolidColor=#NormalColor# 45 | MouseOverAction=[!SetOption #CURRENTSECTION# MeterStyle "StyleSolidButton | StyleSolidButtonOver"][!UpdateMeter #CURRENTSECTION#][!Redraw] 46 | MouseLeaveAction=[!SetOption #CURRENTSECTION# MeterStyle "StyleSolidButton"][!UpdateMeter #CURRENTSECTION#][!Redraw] 47 | LeftMouseDownAction=[!SetOption #CURRENTSECTION# MeterStyle "StyleSolidButton | StyleSolidButtonPressed"][!UpdateMeter #CURRENTSECTION#][!Redraw] 48 | LeftMouseUpAction=[!SetOption #CURRENTSECTION# MeterStyle "StyleSolidButton | StyleSolidButtonOver"][!UpdateMeter #CURRENTSECTION#][!Redraw] 49 | 50 | [StyleSolidButtonOver] 51 | SolidColor=#OverColor# 52 | BevelType=1 53 | 54 | [StyleSolidButtonPressed] 55 | SolidColor=#PressedColor# 56 | BevelType=2 57 | 58 | [MeasureVirtualDesktop] 59 | Measure=Plugin 60 | Plugin=VirtualDesktop 61 | UpdateDivider=-1 62 | OnUpdateAction=[!UpdateMeter MeasureName][!SetOptionGroup DesktopButton SolidColor ""][!SetOption "Desktop[MeasureVirtualDesktop:]" SolidColor #SelectedColor#][!UpdateMeterGroup DesktopButton][!Redraw] 63 | 64 | [MeasureVirtualDesktopCount] 65 | Measure=Plugin 66 | Plugin=VirtualDesktop 67 | Type=Count 68 | UpdateDivider=-1 69 | OnUpdateAction=[!UpdateMeterGroup DesktopButton][!Redraw] 70 | 71 | [ButtonPrev] 72 | Meter=Button 73 | MeterStyle=StyleSolidButton 74 | X=5R 75 | Y=5r 76 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Prev"] 77 | 78 | [TextPrev] 79 | Meter=String 80 | MeterStyle=StyleText | ButtonText 81 | Text="[\xD83E][\xDC80]" 82 | 83 | [ButtonNext] 84 | Meter=Button 85 | MeterStyle=StyleSolidButton 86 | X=-14R 87 | Y=-10r 88 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Next"] 89 | 90 | [TextNext] 91 | Meter=String 92 | MeterStyle=StyleText | ButtonText 93 | Text="[\xD83E][\xDC82]" 94 | 95 | [MeasureName] 96 | Meter=String 97 | MeasureName=MeasureVirtualDesktop 98 | X=-17R 99 | Y=-10r 100 | W=100 101 | MeterStyle=StyleText 102 | 103 | [Desktop1] 104 | Meter=Button 105 | MeterStyle=StyleSolidButton 106 | Group=DesktopButton 107 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Switch 1"] 108 | ToolTipText=[MeasureVirtualDesktop:Name(1)] 109 | Hidden=([MeasureVirtualDesktopCount]<1?) 110 | DynamicVariables=1 111 | 112 | [Desktop2] 113 | Meter=Button 114 | MeterStyle=StyleSolidButton 115 | Group=DesktopButton 116 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Switch 2"] 117 | ToolTipText=[MeasureVirtualDesktop:Name(2)] 118 | Hidden=([MeasureVirtualDesktopCount]<2?) 119 | DynamicVariables=1 120 | 121 | [Desktop3] 122 | Meter=Button 123 | MeterStyle=StyleSolidButton 124 | Group=DesktopButton 125 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Switch 3"] 126 | ToolTipText=[MeasureVirtualDesktop:Name(3)] 127 | Hidden=([MeasureVirtualDesktopCount]<3?) 128 | DynamicVariables=1 129 | 130 | [Desktop4] 131 | Meter=Button 132 | MeterStyle=StyleSolidButton 133 | Group=DesktopButton 134 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Switch 4"] 135 | ToolTipText=[MeasureVirtualDesktop:Name(4)] 136 | Hidden=([MeasureVirtualDesktopCount]<4?) 137 | DynamicVariables=1 138 | 139 | [Desktop5] 140 | Meter=Button 141 | MeterStyle=StyleSolidButton 142 | Group=DesktopButton 143 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Switch 5"] 144 | ToolTipText=[MeasureVirtualDesktop:Name(5)] 145 | Hidden=([MeasureVirtualDesktopCount]<5?) 146 | DynamicVariables=1 147 | 148 | [Desktop6] 149 | Meter=Button 150 | MeterStyle=StyleSolidButton 151 | Group=DesktopButton 152 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Switch 6"] 153 | ToolTipText=[MeasureVirtualDesktop:Name(6)] 154 | Hidden=([MeasureVirtualDesktopCount]<6?) 155 | DynamicVariables=1 156 | 157 | [Desktop7] 158 | Meter=Button 159 | MeterStyle=StyleSolidButton 160 | Group=DesktopButton 161 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Switch 7"] 162 | ToolTipText=[MeasureVirtualDesktop:Name(7)] 163 | Hidden=([MeasureVirtualDesktopCount]<7?) 164 | DynamicVariables=1 165 | 166 | [Desktop8] 167 | Meter=Button 168 | MeterStyle=StyleSolidButton 169 | Group=DesktopButton 170 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Switch 8"] 171 | ToolTipText=[MeasureVirtualDesktop:Name(8)] 172 | Hidden=([MeasureVirtualDesktopCount]<8?) 173 | DynamicVariables=1 174 | 175 | [Desktop9] 176 | Meter=Button 177 | MeterStyle=StyleSolidButton 178 | Group=DesktopButton 179 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Switch 9"] 180 | ToolTipText=[MeasureVirtualDesktop:Name(9)] 181 | Hidden=([MeasureVirtualDesktopCount]<9?) 182 | DynamicVariables=1 183 | 184 | [Desktop10] 185 | Meter=Button 186 | MeterStyle=StyleSolidButton 187 | Group=DesktopButton 188 | ButtonCommand=[!CommandMeasure MeasureVirtualDesktop "Switch 10"] 189 | ToolTipText=[MeasureVirtualDesktop:Name(10)] 190 | Hidden=([MeasureVirtualDesktopCount]<10?) 191 | DynamicVariables=1 192 | -------------------------------------------------------------------------------- /Utils/MakeRmsSkin.ps1: -------------------------------------------------------------------------------- 1 | $target = $args[0] 2 | 3 | Write-Output "Writing footer..." 4 | $size = [long](Get-Item $target).length 5 | $size_bytes = [System.BitConverter]::GetBytes($size) 6 | Add-Content -Path $target -Value $size_bytes -Encoding Byte 7 | 8 | $flags = [byte]0 9 | Add-Content -Path $target -Value $flags -Encoding Byte 10 | 11 | $rmskin = [string]"RMSKIN`0" 12 | Add-Content -Path $target -Value $rmskin -NoNewLine -Encoding ASCII 13 | 14 | Write-Output "Changing .zip to .rmskin" 15 | Rename-Item -Path $target -NewName ([io.path]::ChangeExtension($target, '.rmskin')) 16 | $target = $target.Replace(".zip", ".rmskin") 17 | -------------------------------------------------------------------------------- /Utils/Package.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | prompt $G$S 4 | set _=%1 5 | if defined _ set _=_%_: =_% 6 | set name=Virtual.Desktop.Plugin.Demo%_% 7 | 8 | rem echo on 9 | rem msbuild VirtualDesktop.sln /p:Configuration=Release /p:Platformt=x86 /t:Rebuild || exit /b 10 | rem msbuild VirtualDesktop.sln /p:Configuration=Release /p:Platformt=x64 /t:Rebuild || exit /b 11 | 12 | echo on 13 | @call :safemkdir Plugins 14 | @call :safemkdir Plugins\32Bit 15 | @call :safemkdir Plugins\64Bit 16 | copy Bin\Win32Release\VirtualDesktop.dll Plugins\32Bit || exit /b 17 | copy Bin\x64Release\VirtualDesktop.dll Plugins\64Bit || exit /b 18 | if exist %name%.zip del %name%.zip 19 | 7z a %name%.zip Plugins Skins RMSKIN.ini 20 | del %name%.rmskin 21 | powershell -File %~dp0MakeRmsSkin.ps1 %name%.zip 22 | @goto :eof 23 | 24 | :safemkdir %1 25 | if not exist %1 mkdir %1 26 | @goto :eof 27 | -------------------------------------------------------------------------------- /VirtualDesktop.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 17 3 | VisualStudioVersion = 17.1.32210.238 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VirtualDesktop", "src\VirtualDesktop.vcxproj", "{ECAE7A3B-B18E-481D-992E-7DD70DCA0478}" 6 | EndProject 7 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FD400E4C-0F51-4400-8AAF-2B5DD9125A1B}" 8 | ProjectSection(SolutionItems) = preProject 9 | HISTORY.txt = HISTORY.txt 10 | Skins\VirtualDesktopDemo\VirtualDesktop\VirtualDesktop.ini = Skins\VirtualDesktopDemo\VirtualDesktop\VirtualDesktop.ini 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|x86 = Debug|x86 16 | Debug|x64 = Debug|x64 17 | Release|x86 = Release|x86 18 | Release|x64 = Release|x64 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {ECAE7A3B-B18E-481D-992E-7DD70DCA0478}.Debug|x86.ActiveCfg = Debug|Win32 22 | {ECAE7A3B-B18E-481D-992E-7DD70DCA0478}.Debug|x86.Build.0 = Debug|Win32 23 | {ECAE7A3B-B18E-481D-992E-7DD70DCA0478}.Debug|x64.ActiveCfg = Debug|x64 24 | {ECAE7A3B-B18E-481D-992E-7DD70DCA0478}.Debug|x64.Build.0 = Debug|x64 25 | {ECAE7A3B-B18E-481D-992E-7DD70DCA0478}.Release|x86.ActiveCfg = Release|Win32 26 | {ECAE7A3B-B18E-481D-992E-7DD70DCA0478}.Release|x86.Build.0 = Release|Win32 27 | {ECAE7A3B-B18E-481D-992E-7DD70DCA0478}.Release|x64.ActiveCfg = Release|x64 28 | {ECAE7A3B-B18E-481D-992E-7DD70DCA0478}.Release|x64.Build.0 = Release|x64 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | GlobalSection(ExtensibilityGlobals) = postSolution 34 | SolutionGuid = {8D6EF489-A8F3-4AEC-B292-AF0804A38C57} 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /src/ComUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | struct ObjectArrayIndex 8 | { 9 | UINT i; 10 | IObjectArray* pObjectArray; 11 | 12 | ObjectArrayIndex& operator++() 13 | { 14 | ++i; 15 | return *this; 16 | } 17 | 18 | CComPtr operator*() 19 | { 20 | CComPtr p; 21 | if (FAILED(pObjectArray->GetAt(i, IID_PPV_ARGS(&p)))) 22 | return nullptr; 23 | return p; 24 | } 25 | }; 26 | 27 | template 28 | bool operator!=(const ObjectArrayIndex& l, const ObjectArrayIndex& r) 29 | { 30 | assert(l.pObjectArray == r.pObjectArray); 31 | return l.i != r.i; 32 | } 33 | 34 | template 35 | class ObjectArrayRange 36 | { 37 | private: 38 | IObjectArray* pObjectArray; 39 | 40 | public: 41 | ObjectArrayRange(IObjectArray* pObjectArray) 42 | : pObjectArray(pObjectArray) 43 | { 44 | } 45 | 46 | ObjectArrayIndex begin() const 47 | { 48 | return { 0, pObjectArray }; 49 | } 50 | 51 | ObjectArrayIndex end() const 52 | { 53 | UINT count; 54 | if (FAILED(pObjectArray->GetCount(&count))) 55 | count = 0; 56 | return { count, pObjectArray }; 57 | } 58 | }; 59 | 60 | template 61 | struct ObjectArrayIndexRev 62 | { 63 | UINT i; 64 | IObjectArray* pObjectArray; 65 | 66 | ObjectArrayIndexRev& operator++() 67 | { 68 | --i; 69 | return *this; 70 | } 71 | 72 | CComPtr operator*() 73 | { 74 | CComPtr p; 75 | if (FAILED(pObjectArray->GetAt(i - 1, IID_PPV_ARGS(&p)))) 76 | return nullptr; 77 | return p; 78 | } 79 | }; 80 | 81 | template 82 | bool operator!=(const ObjectArrayIndexRev& l, const ObjectArrayIndexRev& r) 83 | { 84 | assert(l.pObjectArray == r.pObjectArray); 85 | return l.i != r.i; 86 | } 87 | 88 | template 89 | class ObjectArrayRangeRev 90 | { 91 | private: 92 | IObjectArray* pObjectArray; 93 | 94 | public: 95 | ObjectArrayRangeRev(IObjectArray* pObjectArray) 96 | : pObjectArray(pObjectArray) 97 | { 98 | } 99 | 100 | ObjectArrayIndexRev begin() const 101 | { 102 | UINT count; 103 | if (FAILED(pObjectArray->GetCount(&count))) 104 | count = 0; 105 | return { count, pObjectArray }; 106 | } 107 | 108 | ObjectArrayIndexRev end() const 109 | { 110 | return { 0, pObjectArray }; 111 | } 112 | }; 113 | -------------------------------------------------------------------------------- /src/Default.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(SolutionDir)\Bin\$(Platform)$(Configuration)\ 5 | Int\$(Platform)$(Configuration)\ 6 | 7 | -------------------------------------------------------------------------------- /src/VDNotification.cpp: -------------------------------------------------------------------------------- 1 | #include "VDNotification.h" 2 | 3 | VirtualDesktopNotification::VirtualDesktopNotification(IVDNotification* notify) 4 | : _notify(notify), _referenceCount(0) 5 | { 6 | } 7 | 8 | STDMETHODIMP VirtualDesktopNotification::QueryInterface(REFIID riid, void** ppvObject) 9 | { 10 | // Always set out parameter to NULL, validating it first. 11 | if (!ppvObject) 12 | return E_INVALIDARG; 13 | *ppvObject = NULL; 14 | 15 | if (riid == IID_IUnknown || riid == Win10::IID_IVirtualDesktopNotification) 16 | { 17 | // Increment the reference count and return the pointer. 18 | *ppvObject = (LPVOID) static_cast(this); 19 | AddRef(); 20 | return S_OK; 21 | } 22 | else if (riid == Win11::IID_IVirtualDesktopNotification) 23 | { 24 | // Increment the reference count and return the pointer. 25 | *ppvObject = (LPVOID) static_cast(this); 26 | AddRef(); 27 | return S_OK; 28 | } 29 | return E_NOINTERFACE; 30 | } 31 | 32 | STDMETHODIMP_(DWORD) VirtualDesktopNotification::AddRef() 33 | { 34 | return InterlockedIncrement(&_referenceCount); 35 | } 36 | 37 | STDMETHODIMP_(DWORD) STDMETHODCALLTYPE VirtualDesktopNotification::Release() 38 | { 39 | ULONG result = InterlockedDecrement(&_referenceCount); 40 | if (result == 0) 41 | { 42 | delete this; 43 | } 44 | return 0; 45 | } 46 | 47 | // Win10::IVirtualDesktopNotification 48 | 49 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopCreated(Win10::IVirtualDesktop* pDesktop) 50 | { 51 | _notify->VirtualDesktopCreated(pDesktop); 52 | return S_OK; 53 | } 54 | 55 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopDestroyBegin(Win10::IVirtualDesktop* pDesktopDestroyed, Win10::IVirtualDesktop* pDesktopFallback) 56 | { 57 | return S_OK; 58 | } 59 | 60 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopDestroyFailed(Win10::IVirtualDesktop* pDesktopDestroyed, Win10::IVirtualDesktop* pDesktopFallback) 61 | { 62 | return S_OK; 63 | } 64 | 65 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopDestroyed(Win10::IVirtualDesktop* pDesktopDestroyed, Win10::IVirtualDesktop* pDesktopFallback) 66 | { 67 | _notify->VirtualDesktopDestroyed(pDesktopDestroyed, pDesktopFallback); 68 | return S_OK; 69 | } 70 | 71 | STDMETHODIMP VirtualDesktopNotification::ViewVirtualDesktopChanged(IApplicationView* pView) 72 | { 73 | return S_OK; 74 | } 75 | 76 | STDMETHODIMP VirtualDesktopNotification::CurrentVirtualDesktopChanged(Win10::IVirtualDesktop* pDesktopOld, Win10::IVirtualDesktop* pDesktopNew) 77 | { 78 | _notify->CurrentVirtualDesktopChanged(pDesktopOld, pDesktopNew); 79 | return S_OK; 80 | } 81 | 82 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopNameChanged(Win10::IVirtualDesktop* pDesktop, HSTRING name) 83 | { 84 | _notify->VirtualDesktopNameChanged(pDesktop, name); 85 | return S_OK; 86 | } 87 | 88 | // Win11::IVirtualDesktopNotification 89 | 90 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopCreated(Win11::IVirtualDesktop* pDesktop) 91 | { 92 | _notify->VirtualDesktopCreated(pDesktop); 93 | return S_OK; 94 | } 95 | 96 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopDestroyBegin(Win11::IVirtualDesktop* pDesktopDestroyed, Win11::IVirtualDesktop* pDesktopFallback) 97 | { 98 | return S_OK; 99 | } 100 | 101 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopDestroyFailed(Win11::IVirtualDesktop* pDesktopDestroyed, Win11::IVirtualDesktop* pDesktopFallback) 102 | { 103 | return S_OK; 104 | } 105 | 106 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopDestroyed(Win11::IVirtualDesktop* pDesktopDestroyed, Win11::IVirtualDesktop* pDesktopFallback) 107 | { 108 | _notify->VirtualDesktopDestroyed(pDesktopDestroyed, pDesktopFallback); 109 | return S_OK; 110 | } 111 | 112 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopMoved(Win11::IVirtualDesktop* pDesktop, int64_t oldIndex, int64_t newIndex) 113 | { 114 | _notify->VirtualDesktopMoved(pDesktop, oldIndex, newIndex); 115 | return S_OK; 116 | } 117 | 118 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopNameChanged11(Win11::IVirtualDesktop* pDesktop, HSTRING name) 119 | { 120 | _notify->VirtualDesktopNameChanged(pDesktop, name); 121 | return S_OK; 122 | } 123 | 124 | STDMETHODIMP VirtualDesktopNotification::ViewVirtualDesktopChanged11(IApplicationView* pView) 125 | { 126 | return S_OK; 127 | } 128 | 129 | STDMETHODIMP VirtualDesktopNotification::CurrentVirtualDesktopChanged(Win11::IVirtualDesktop* pDesktopOld, Win11::IVirtualDesktop* pDesktopNew) 130 | { 131 | _notify->CurrentVirtualDesktopChanged(pDesktopOld, pDesktopNew); 132 | return S_OK; 133 | } 134 | 135 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopWallpaperChanged(Win11::IVirtualDesktop* pDesktop, HSTRING name) 136 | { 137 | return S_OK; 138 | } 139 | 140 | STDMETHODIMP VirtualDesktopNotification::VirtualDesktopSwitched(Win11::IVirtualDesktop* pDesktop) 141 | { 142 | return S_OK; 143 | } 144 | 145 | STDMETHODIMP VirtualDesktopNotification::RemoteVirtualDesktopConnected(Win11::IVirtualDesktop* pDesktop) 146 | { 147 | return S_OK; 148 | } 149 | -------------------------------------------------------------------------------- /src/VDNotification.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Win10Desktops.h" 4 | 5 | class IVDNotification 6 | { 7 | public: 8 | // Win10::IVirtualDesktopNotification 9 | virtual void VirtualDesktopCreated(Win10::IVirtualDesktop* pDesktop) = 0; 10 | virtual void VirtualDesktopDestroyed(Win10::IVirtualDesktop* pDesktopDestroyed, Win10::IVirtualDesktop* pDesktopFallback) = 0; 11 | virtual void CurrentVirtualDesktopChanged(Win10::IVirtualDesktop* pDesktopOld, Win10::IVirtualDesktop* pDesktopNew) = 0; 12 | virtual void VirtualDesktopNameChanged(Win10::IVirtualDesktop* pDesktop, HSTRING name) = 0; 13 | 14 | // Win11::IVirtualDesktopNotification 15 | virtual void VirtualDesktopCreated(Win11::IVirtualDesktop* pDesktop) = 0; 16 | virtual void VirtualDesktopDestroyed(Win11::IVirtualDesktop* pDesktopDestroyed, Win11::IVirtualDesktop* pDesktopFallback) = 0; 17 | virtual void VirtualDesktopMoved(Win11::IVirtualDesktop* pDesktop, int64_t oldIndex, int64_t newIndex) = 0; 18 | virtual void VirtualDesktopNameChanged(Win11::IVirtualDesktop* pDesktop, HSTRING name) = 0; 19 | virtual void CurrentVirtualDesktopChanged(Win11::IVirtualDesktop* pDesktopOld, Win11::IVirtualDesktop* pDesktopNew) = 0; 20 | //virtual void VirtualDesktopWallpaperChanged(Win11::IVirtualDesktop* pDesktop, HSTRING name) = 0; 21 | //virtual void VirtualDesktopSwitched(Win11::IVirtualDesktop* pDesktop) = 0; 22 | //virtual void RemoteVirtualDesktopConnected(Win11::IVirtualDesktop* pDesktop) = 0; 23 | }; 24 | 25 | class VirtualDesktopNotification : public Win10::IVirtualDesktopNotification2, public Win11::IVirtualDesktopNotification 26 | { 27 | private: 28 | IVDNotification* _notify; 29 | ULONG _referenceCount; 30 | public: 31 | VirtualDesktopNotification(IVDNotification* notify); 32 | 33 | STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) override; 34 | STDMETHODIMP_(DWORD) AddRef() override; 35 | STDMETHODIMP_(DWORD) STDMETHODCALLTYPE Release() override; 36 | 37 | // Win10::IVirtualDesktopNotification 38 | STDMETHODIMP VirtualDesktopCreated(Win10::IVirtualDesktop* pDesktop) override; 39 | STDMETHODIMP VirtualDesktopDestroyBegin(Win10::IVirtualDesktop* pDesktopDestroyed, Win10::IVirtualDesktop* pDesktopFallback) override; 40 | STDMETHODIMP VirtualDesktopDestroyFailed(Win10::IVirtualDesktop* pDesktopDestroyed, Win10::IVirtualDesktop* pDesktopFallback) override; 41 | STDMETHODIMP VirtualDesktopDestroyed(Win10::IVirtualDesktop* pDesktopDestroyed, Win10::IVirtualDesktop* pDesktopFallback) override; 42 | STDMETHODIMP ViewVirtualDesktopChanged(IApplicationView* pView) override; 43 | STDMETHODIMP CurrentVirtualDesktopChanged(Win10::IVirtualDesktop* pDesktopOld, Win10::IVirtualDesktop* pDesktopNew) override; 44 | // Win10::IVirtualDesktopNotification2 45 | STDMETHODIMP VirtualDesktopNameChanged(Win10::IVirtualDesktop* pDesktop, HSTRING name) override; 46 | 47 | // Win10::IVirtualDesktopNotification 48 | STDMETHODIMP VirtualDesktopCreated(Win11::IVirtualDesktop* pDesktop) override; 49 | STDMETHODIMP VirtualDesktopDestroyBegin(Win11::IVirtualDesktop* pDesktopDestroyed, Win11::IVirtualDesktop* pDesktopFallback) override; 50 | STDMETHODIMP VirtualDesktopDestroyFailed(Win11::IVirtualDesktop* pDesktopDestroyed, Win11::IVirtualDesktop* pDesktopFallback) override; 51 | STDMETHODIMP VirtualDesktopDestroyed(Win11::IVirtualDesktop* pDesktopDestroyed, Win11::IVirtualDesktop* pDesktopFallback) override; 52 | STDMETHODIMP VirtualDesktopMoved(Win11::IVirtualDesktop* pDesktop, int64_t oldIndex, int64_t newIndex) override; 53 | STDMETHODIMP VirtualDesktopNameChanged11(Win11::IVirtualDesktop* pDesktop, HSTRING name) override; 54 | STDMETHODIMP ViewVirtualDesktopChanged11(IApplicationView* pView) override; 55 | STDMETHODIMP CurrentVirtualDesktopChanged(Win11::IVirtualDesktop* pDesktopOld, Win11::IVirtualDesktop* pDesktopNew) override; 56 | STDMETHODIMP VirtualDesktopWallpaperChanged(Win11::IVirtualDesktop* pDesktop, HSTRING name) override; 57 | STDMETHODIMP VirtualDesktopSwitched(Win11::IVirtualDesktop* pDesktop) override; 58 | STDMETHODIMP RemoteVirtualDesktopConnected(Win11::IVirtualDesktop* pDesktop) override; 59 | }; 60 | -------------------------------------------------------------------------------- /src/VDUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "VDUtils.h" 2 | 3 | #include "ComUtils.h" 4 | 5 | #include 6 | 7 | static const int LOG_ERROR = 1; 8 | 9 | static inline bool LogHR(LogF* pLog, void* logdata, HRESULT hr, LPCWSTR name) 10 | { 11 | if (FAILED(hr)) 12 | { 13 | if (pLog) 14 | pLog(logdata, LOG_ERROR, L"%s %#10.8x\n", name, hr); 15 | return false; 16 | } 17 | else 18 | return true; 19 | } 20 | 21 | static inline bool LogHR(LogF* pLog, void* logdata, HRESULT hr, HRESULT ignore, LPCWSTR name) 22 | { 23 | if (FAILED(hr) && hr != ignore) 24 | { 25 | if (pLog) 26 | pLog(logdata, LOG_ERROR, L"%s %#10.8x\n", name, hr); 27 | return false; 28 | } 29 | else 30 | return true; 31 | } 32 | 33 | static const CComPtr& GetImmersiveShell(LogF* pLog, void* logdata) 34 | { 35 | static CComPtr pServiceProvider; 36 | if (!pServiceProvider) 37 | LogHR(pLog, logdata, pServiceProvider.CoCreateInstance(CLSID_ImmersiveShell, NULL, CLSCTX_LOCAL_SERVER), L"creating CLSID_ImmersiveShell"); 38 | return pServiceProvider; 39 | } 40 | 41 | template 42 | static const CComPtr& GetVirtualNotificationService(LogF* pLog, void* logdata) 43 | { 44 | static CComPtr pDesktopNotificationService; 45 | if (!pDesktopNotificationService) 46 | { 47 | const CComPtr& pServiceProvider = GetImmersiveShell(pLog, logdata); 48 | LogHR(pLog, logdata, pServiceProvider->QueryService(CLSID_VirtualNotificationService, &pDesktopNotificationService), L"creating CLSID_IVirtualNotificationService"); 49 | } 50 | return pDesktopNotificationService; 51 | } 52 | 53 | template 54 | static const CComPtr& GetDesktopManagerInternal(LogF* pLog, void* logdata) 55 | { 56 | static CComPtr pDesktopManagerInternal; 57 | if (!pDesktopManagerInternal) 58 | { 59 | const CComPtr& pServiceProvider = GetImmersiveShell(pLog, logdata); 60 | //LogHR(pLog, logdata, pServiceProvider->QueryService(CLSID_VirtualDesktopManagerInternal, &pDesktopManagerInternal), L"creating CLSID_VirtualDesktopManagerInternal"); 61 | pServiceProvider->QueryService(CLSID_VirtualDesktopManagerInternal, &pDesktopManagerInternal); 62 | } 63 | return pDesktopManagerInternal; 64 | } 65 | 66 | DWORD Register(LogF* pLog, void* logdata, VirtualDesktopNotification* pNotify) 67 | { 68 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 69 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 70 | DWORD idVirtualDesktopNotification = 0; 71 | if (pDesktopManagerInternal10) 72 | { 73 | const CComPtr pVirtualNotificationService = GetVirtualNotificationService(pLog, logdata); 74 | if (pVirtualNotificationService) 75 | LogHR(pLog, logdata, pVirtualNotificationService->Register(pNotify, &idVirtualDesktopNotification), L"Register DesktopNotificationService"); 76 | } 77 | else if (pDesktopManagerInternal11) 78 | { 79 | const CComPtr pVirtualNotificationService = GetVirtualNotificationService(pLog, logdata); 80 | if (pVirtualNotificationService) 81 | LogHR(pLog, logdata, pVirtualNotificationService->Register(pNotify, &idVirtualDesktopNotification), L"Register DesktopNotificationService"); 82 | } 83 | else if (pLog) 84 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 85 | return idVirtualDesktopNotification; 86 | } 87 | 88 | void Unregister(LogF* pLog, void* logdata, DWORD idVirtualDesktopNotification) 89 | { 90 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 91 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 92 | if (pDesktopManagerInternal10) 93 | { 94 | const CComPtr pVirtualNotificationService = GetVirtualNotificationService(pLog, logdata); 95 | if (pVirtualNotificationService) 96 | LogHR(pLog, logdata, pVirtualNotificationService->Unregister(idVirtualDesktopNotification), L"Unregister DesktopNotificationService"); 97 | } 98 | else if (pDesktopManagerInternal11) 99 | { 100 | const CComPtr pVirtualNotificationService = GetVirtualNotificationService(pLog, logdata); 101 | if (pVirtualNotificationService) 102 | LogHR(pLog, logdata, pVirtualNotificationService->Unregister(idVirtualDesktopNotification), L"Unregister DesktopNotificationService"); 103 | } 104 | else if (pLog) 105 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 106 | } 107 | 108 | template 109 | CComPtr GetDesktop(LogF* pLog, void* logdata, VDMI* pDesktopManagerInternal, int d) 110 | { 111 | CComPtr pDesktopArray; 112 | if (d == -1) 113 | { 114 | CComPtr pCurrentDesktop; 115 | LogHR(pLog, logdata, pDesktopManagerInternal->GetCurrentDesktop(&pCurrentDesktop), L"GetCurrentDesktop"); 116 | return pCurrentDesktop; 117 | } 118 | else if (pDesktopManagerInternal && SUCCEEDED(pDesktopManagerInternal->GetDesktops(&pDesktopArray))) 119 | { 120 | CComPtr pDesktop; 121 | LogHR(pLog, logdata, pDesktopArray->GetAt(d - 1, IID_PPV_ARGS(&pDesktop)), E_INVALIDARG, L"IObjectArray GetAt"); 122 | return pDesktop; 123 | } 124 | else 125 | return {}; 126 | } 127 | 128 | template 129 | void SwitchDesktop(LogF* pLog, void* logdata, VDMI* pDesktopManagerInternal, int d) 130 | { 131 | CComPtr pDesktop = GetDesktop(pLog, logdata, pDesktopManagerInternal, d); 132 | if (pDesktop) 133 | LogHR(pLog, logdata, SwitchDesktop(pDesktopManagerInternal, static_cast(pDesktop), false), L"SwitchDesktop"); 134 | } 135 | 136 | void SwitchDesktop(LogF* pLog, void* logdata, int d) 137 | { 138 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 139 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 140 | if (pDesktopManagerInternal10) 141 | SwitchDesktop(pLog, logdata, static_cast(pDesktopManagerInternal10), d); 142 | else if (pDesktopManagerInternal11) 143 | SwitchDesktop(pLog, logdata, static_cast(pDesktopManagerInternal11), d); 144 | else if (pLog) 145 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 146 | } 147 | 148 | template 149 | void SwitchDesktop(LogF* pLog, void* logdata, VDMI* pDesktopManagerInternal, enum AdjacentDesktop direction) 150 | { 151 | CComPtr pCurrentDesktop; 152 | LogHR(pLog, logdata, pDesktopManagerInternal->GetCurrentDesktop(&pCurrentDesktop), L"GetCurrentDesktop"); 153 | CComPtr pDesktop; 154 | LogHR(pLog, logdata, pDesktopManagerInternal->GetAdjacentDesktop(pCurrentDesktop, direction, &pDesktop), TYPE_E_OUTOFBOUNDS, L"GetAdjacentDesktop"); 155 | if (pDesktop) 156 | LogHR(pLog, logdata, SwitchDesktop(pDesktopManagerInternal, static_cast(pDesktop), false), L"SwitchDesktop"); 157 | } 158 | 159 | void SwitchDesktop(LogF* pLog, void* logdata, enum AdjacentDesktop direction) 160 | { 161 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 162 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 163 | if (pDesktopManagerInternal10) 164 | SwitchDesktop(pLog, logdata, static_cast(pDesktopManagerInternal10), direction); 165 | else if (pDesktopManagerInternal11) 166 | SwitchDesktop(pLog, logdata, static_cast(pDesktopManagerInternal11), direction); 167 | else if (pLog) 168 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 169 | } 170 | 171 | template 172 | int GetDesktopCount(LogF* pLog, void* logdata, VDMI* pDesktopManagerInternal) 173 | { 174 | CComPtr pDesktopArray; 175 | if (SUCCEEDED(pDesktopManagerInternal->GetDesktops(&pDesktopArray))) 176 | { 177 | UINT count; 178 | if (!LogHR(pLog, logdata, pDesktopArray->GetCount(&count), L"GetDesktopCount")) 179 | count = 0; 180 | return count; 181 | } 182 | else 183 | return 0; 184 | } 185 | 186 | int GetDesktopCount(LogF* pLog, void* logdata) 187 | { 188 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 189 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 190 | if (pDesktopManagerInternal10) 191 | return GetDesktopCount(pLog, logdata, static_cast(pDesktopManagerInternal10)); 192 | else if (pDesktopManagerInternal11) 193 | return GetDesktopCount(pLog, logdata, static_cast(pDesktopManagerInternal11)); 194 | else 195 | { 196 | if (pLog) 197 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 198 | return 0; 199 | } 200 | } 201 | 202 | template 203 | int GetDesktopNumber(VDMI* pDesktopManagerInternal, VD* pFindDesktop) 204 | { 205 | int dn = 0; 206 | CComPtr pDesktopArray; 207 | if (pDesktopManagerInternal && SUCCEEDED(pDesktopManagerInternal->GetDesktops(&pDesktopArray))) 208 | { 209 | for (CComPtr pDesktop : ObjectArrayRange(pDesktopArray)) 210 | { 211 | ++dn; 212 | if (pDesktop.IsEqualObject(pFindDesktop)) 213 | { 214 | return dn; 215 | } 216 | } 217 | } 218 | return 0; 219 | } 220 | 221 | template 222 | int GetCurrentDesktopNumber(LogF* pLog, void* logdata, VDMI* pDesktopManagerInternal) 223 | { 224 | CComPtr pCurrentDesktop; 225 | LogHR(pLog, logdata, pDesktopManagerInternal->GetCurrentDesktop(&pCurrentDesktop), L"GetCurrentDesktop"); 226 | return GetDesktopNumber(pDesktopManagerInternal, static_cast(pCurrentDesktop)); 227 | } 228 | 229 | int GetCurrentDesktopNumber(LogF* pLog, void* logdata) 230 | { 231 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 232 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 233 | if (pDesktopManagerInternal10) 234 | return GetCurrentDesktopNumber(pLog, logdata, static_cast(pDesktopManagerInternal10)); 235 | else if (pDesktopManagerInternal11) 236 | return GetCurrentDesktopNumber(pLog, logdata, static_cast(pDesktopManagerInternal11)); 237 | else 238 | { 239 | if (pLog) 240 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 241 | return 0; 242 | } 243 | } 244 | 245 | int GetDesktopNumber(LogF* pLog, void* logdata, Win10::IVirtualDesktop* pFindDesktop) 246 | { 247 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 248 | return GetDesktopNumber(static_cast(pDesktopManagerInternal10), pFindDesktop); 249 | } 250 | 251 | int GetDesktopNumber(LogF* pLog, void* logdata, Win11::IVirtualDesktop* pFindDesktop) 252 | { 253 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 254 | return GetDesktopNumber(static_cast(pDesktopManagerInternal11), pFindDesktop); 255 | } 256 | 257 | template 258 | std::wstring GetDesktopName(LogF* pLog, void* logdata, VDMI* pDesktopManagerInternal, int d) 259 | { 260 | std::wstring ret; 261 | 262 | CComPtr pDesktop = GetDesktop(pLog, logdata, pDesktopManagerInternal, d); 263 | if (pDesktop) 264 | { 265 | CComQIPtr pDesktop2 = pDesktop; 266 | 267 | HSTRING s = NULL; 268 | LogHR(pLog, logdata, pDesktop2->GetName(&s), L"GetDesktopName"); 269 | 270 | if (s != NULL) 271 | { 272 | ret = WindowsGetStringRawBuffer(s, nullptr); 273 | 274 | WindowsDeleteString(s); 275 | } 276 | else 277 | { 278 | WCHAR buffer[128]; 279 | _snwprintf_s(buffer, _TRUNCATE, L"Desktop %d", GetDesktopNumber(pDesktopManagerInternal, static_cast(pDesktop))); 280 | ret = buffer; 281 | } 282 | } 283 | 284 | return ret; 285 | } 286 | 287 | std::wstring GetDesktopName(LogF* pLog, void* logdata, int d) 288 | { 289 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 290 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 291 | if (pDesktopManagerInternal10) 292 | return GetDesktopName(pLog, logdata, static_cast(pDesktopManagerInternal10), d); 293 | else if (pDesktopManagerInternal11) 294 | return GetDesktopName(pLog, logdata, static_cast(pDesktopManagerInternal11), d); 295 | else 296 | { 297 | if (pLog) 298 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 299 | 300 | return {}; 301 | } 302 | } 303 | 304 | template 305 | void SetDesktopName(LogF* pLog, void* logdata, VDMI* pDesktopManagerInternal, int d, LPCWSTR name) 306 | { 307 | CComPtr pDesktop = GetDesktop(pLog, logdata, pDesktopManagerInternal, d); 308 | if (pDesktop) 309 | { 310 | HSTRING s = NULL; 311 | LogHR(pLog, logdata, WindowsCreateString(name, static_cast(wcslen(name)), &s), L"WindowsCreateString"); 312 | LogHR(pLog, logdata, pDesktopManagerInternal->SetDesktopName(pDesktop , s), L"SetDesktopName"); 313 | WindowsDeleteString(s); 314 | } 315 | } 316 | 317 | void SetDesktopName(LogF* pLog, void* logdata, int d, LPCWSTR name) 318 | { 319 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 320 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 321 | if (pDesktopManagerInternal10) 322 | return SetDesktopName(pLog, logdata, static_cast(pDesktopManagerInternal10), d, name); 323 | else if (pDesktopManagerInternal11) 324 | return SetDesktopName(pLog, logdata, static_cast(pDesktopManagerInternal11), d, name); 325 | else 326 | { 327 | if (pLog) 328 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 329 | 330 | return; 331 | } 332 | } 333 | 334 | template 335 | std::wstring GetDesktopWallpaper(LogF* pLog, void* logdata, VDMI* pDesktopManagerInternal, int d) 336 | { 337 | std::wstring ret; 338 | 339 | CComPtr pDesktop = GetDesktop(pLog, logdata, pDesktopManagerInternal, d); 340 | if (pDesktop) 341 | { 342 | HSTRING s = NULL; 343 | LogHR(pLog, logdata, pDesktop->GetWallpaperPath(&s), L"GetDesktopName"); 344 | 345 | if (s != NULL) 346 | { 347 | ret = WindowsGetStringRawBuffer(s, nullptr); 348 | 349 | WindowsDeleteString(s); 350 | } 351 | else 352 | { 353 | WCHAR buffer[128]; 354 | _snwprintf_s(buffer, _TRUNCATE, L"Desktop %d", GetDesktopNumber(pDesktopManagerInternal, static_cast(pDesktop))); 355 | ret = buffer; 356 | } 357 | } 358 | 359 | return ret; 360 | } 361 | 362 | std::wstring GetDesktopWallpaper(LogF* pLog, void* logdata, int d) 363 | { 364 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 365 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 366 | if (pDesktopManagerInternal10) 367 | return {}; // GetDesktopWallpaper(pLog, logdata, static_cast(pDesktopManagerInternal10), d); 368 | else if (pDesktopManagerInternal11) 369 | return GetDesktopWallpaper(pLog, logdata, static_cast(pDesktopManagerInternal11), d); 370 | else 371 | { 372 | if (pLog) 373 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 374 | 375 | return {}; 376 | } 377 | } 378 | 379 | template 380 | void SetDesktopWallpaper(LogF* pLog, void* logdata, VDMI* pDesktopManagerInternal, int d, LPCWSTR wallpaper) 381 | { 382 | CComPtr pDesktop = GetDesktop(pLog, logdata, pDesktopManagerInternal, d); 383 | if (pDesktop) 384 | { 385 | HSTRING s = NULL; 386 | LogHR(pLog, logdata, WindowsCreateString(wallpaper, static_cast(wcslen(wallpaper)), &s), L"WindowsCreateString"); 387 | LogHR(pLog, logdata, pDesktopManagerInternal->SetDesktopWallpaper(pDesktop, s), L"SetDesktopWallpaper"); 388 | WindowsDeleteString(s); 389 | } 390 | } 391 | 392 | void SetDesktopWallpaper(LogF* pLog, void* logdata, int d, LPCWSTR wallpaper) 393 | { 394 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 395 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 396 | if (pDesktopManagerInternal10) 397 | return; // SetDesktopWallpaper(pLog, logdata, static_cast(pDesktopManagerInternal10), d, wallpaper); 398 | else if (pDesktopManagerInternal11) 399 | return SetDesktopWallpaper(pLog, logdata, static_cast(pDesktopManagerInternal11), d, wallpaper); 400 | else 401 | { 402 | if (pLog) 403 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 404 | 405 | return; 406 | } 407 | } 408 | 409 | template 410 | void CreateDesktop(LogF* pLog, void* logdata, VDMI* pDesktopManagerInternal) 411 | { 412 | CComPtr pDesktop; 413 | LogHR(pLog, logdata, pDesktopManagerInternal->CreateDesktop(&pDesktop), L"CreateDesktop"); 414 | if (pDesktop) 415 | LogHR(pLog, logdata, SwitchDesktop(pDesktopManagerInternal, static_cast(pDesktop), false), L"SwitchDesktop"); 416 | } 417 | 418 | void CreateDesktop(LogF* pLog, void* logdata) 419 | { 420 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 421 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 422 | if (pDesktopManagerInternal10) 423 | CreateDesktop(pLog, logdata, static_cast(pDesktopManagerInternal10)); 424 | else if (pDesktopManagerInternal11) 425 | CreateDesktop(pLog, logdata, static_cast(pDesktopManagerInternal11)); 426 | else if (pLog) 427 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 428 | } 429 | 430 | template 431 | void RemoveDesktop(LogF* pLog, void* logdata, VDMI* pDesktopManagerInternal, int d) 432 | { 433 | CComPtr pCurrentDesktop; 434 | LogHR(pLog, logdata, pDesktopManagerInternal->GetCurrentDesktop(&pCurrentDesktop), L"GetCurrentDesktop"); 435 | CComPtr pDesktop = d == -1 ? pCurrentDesktop : GetDesktop(pLog, logdata, pDesktopManagerInternal, d); 436 | CComPtr pFallbackDesktop = pCurrentDesktop; 437 | if (!pFallbackDesktop || pFallbackDesktop.IsEqualObject(pDesktop)) 438 | { 439 | pFallbackDesktop.Release(); 440 | LogHR(pLog, logdata, pDesktopManagerInternal->GetAdjacentDesktop(pCurrentDesktop, AdjacentDesktop::RightDirection, &pFallbackDesktop), TYPE_E_OUTOFBOUNDS, L"GetAdjacentDesktop"); 441 | if (!pFallbackDesktop) 442 | LogHR(pLog, logdata, pDesktopManagerInternal->GetAdjacentDesktop(pCurrentDesktop, AdjacentDesktop::LeftDirection, &pFallbackDesktop), TYPE_E_OUTOFBOUNDS, L"GetAdjacentDesktop"); 443 | } 444 | if (pFallbackDesktop) 445 | LogHR(pLog, logdata, pDesktopManagerInternal->RemoveDesktop(pDesktop, pFallbackDesktop), L"RemoveDesktop"); 446 | } 447 | 448 | void RemoveDesktop(LogF* pLog, void* logdata, int d) 449 | { 450 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 451 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 452 | if (pDesktopManagerInternal10) 453 | RemoveDesktop(pLog, logdata, static_cast(pDesktopManagerInternal10), d); 454 | else if (pDesktopManagerInternal11) 455 | RemoveDesktop(pLog, logdata, static_cast(pDesktopManagerInternal11), d); 456 | else if (pLog) 457 | pLog(logdata, LOG_ERROR, L"GetDesktopManagerInternal\n"); 458 | } 459 | 460 | bool IsCurrentDesktop(LogF* pLog, void* logdata, Win10::IVirtualDesktop* pDesktop) 461 | { 462 | const CComPtr& pDesktopManagerInternal10 = GetDesktopManagerInternal(pLog, logdata); 463 | CComPtr pCurrentDesktop; 464 | LogHR(pLog, logdata, pDesktopManagerInternal10->GetCurrentDesktop(&pCurrentDesktop), L"GetCurrentDesktop"); 465 | return pCurrentDesktop.IsEqualObject(pDesktop); 466 | } 467 | 468 | bool IsCurrentDesktop(LogF* pLog, void* logdata, Win11::IVirtualDesktop* pDesktop) 469 | { 470 | const CComPtr& pDesktopManagerInternal11 = GetDesktopManagerInternal(pLog, logdata); 471 | CComPtr pCurrentDesktop; 472 | LogHR(pLog, logdata, pDesktopManagerInternal11->GetCurrentDesktop(&pCurrentDesktop), L"GetCurrentDesktop"); 473 | return pCurrentDesktop.IsEqualObject(pDesktop); 474 | } 475 | -------------------------------------------------------------------------------- /src/VDUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Win10Desktops.h" 6 | #include "VDNotification.h" 7 | 8 | typedef void __cdecl LogF(void* logdata, int level, LPCWSTR format, ...); 9 | 10 | DWORD Register(LogF* pLog, void* logdata, VirtualDesktopNotification* pNotify); 11 | void Unregister(LogF* pLog, void* logdata, DWORD idVirtualDesktopNotification); 12 | 13 | int GetDesktopCount(LogF* pLog, void* logdata); 14 | int GetCurrentDesktopNumber(LogF* pLog, void* logdata); 15 | int GetDesktopNumber(LogF* pLog, void* logdata, Win10::IVirtualDesktop* pFindDesktop); 16 | int GetDesktopNumber(LogF* pLog, void* logdata, Win11::IVirtualDesktop* pFindDesktop); 17 | std::wstring GetDesktopName(LogF* pLog, void* logdata, int d); 18 | void SetDesktopName(LogF* pLog, void* logdata, int d, LPCWSTR name); 19 | std::wstring GetDesktopWallpaper(LogF* pLog, void* logdata, int d); 20 | void SetDesktopWallpaper(LogF* pLog, void* logdata, int d, LPCWSTR wallpaper); 21 | void SwitchDesktop(LogF* pLog, void* logdata, int d); 22 | void SwitchDesktop(LogF* pLog, void* logdata, enum AdjacentDesktop direction); 23 | 24 | void CreateDesktop(LogF* pLog, void* logdata); 25 | void RemoveDesktop(LogF* pLog, void* logdata, int d); 26 | 27 | bool IsCurrentDesktop(LogF* pLog, void* logdata, Win10::IVirtualDesktop* pDesktop); 28 | bool IsCurrentDesktop(LogF* pLog, void* logdata, Win11::IVirtualDesktop* pDesktop); 29 | -------------------------------------------------------------------------------- /src/VirtualDesktop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "VDUtils.h" 8 | #include "VDNotification.h" 9 | 10 | // For more information, see the SDK docs: https://docs.rainmeter.net/developers/plugin/cpp/ 11 | 12 | enum class MeasureType 13 | { 14 | CURRENT, 15 | COUNT, 16 | }; 17 | 18 | class Measure : private IVDNotification 19 | { 20 | public: 21 | Measure(void* rm) 22 | : rm(rm) 23 | , skin(RmGetSkin(rm)) 24 | { 25 | RegisterForNotifications(); 26 | } 27 | 28 | ~Measure() 29 | { 30 | UnregisterForNotifications(); 31 | } 32 | 33 | void Reload(void* rm, double* maxValue) 34 | { 35 | assert(this->rm == rm); 36 | this->rm = rm; 37 | 38 | LPCWSTR value = RmReadString(rm, L"Type", L"Current"); 39 | if (_wcsicmp(value, L"Current") == 0) 40 | { 41 | type = MeasureType::CURRENT; 42 | } 43 | else if (_wcsicmp(value, L"Count") == 0) 44 | { 45 | type = MeasureType::COUNT; 46 | } 47 | else 48 | { 49 | RmLogF(rm, LOG_ERROR, L"Invalid \"Type\" %s", value); 50 | } 51 | 52 | Update(); 53 | 54 | //*maxValue = GetMax(); 55 | } 56 | 57 | double Update() const 58 | { 59 | return value; 60 | } 61 | 62 | LPCWSTR GetString() const 63 | { 64 | if (string.empty()) 65 | return nullptr; 66 | else 67 | return string.c_str(); 68 | } 69 | 70 | void ExecuteBang(const int argc, const LPWSTR* argv) const 71 | { 72 | if (argc > 0) 73 | { 74 | if (_wcsicmp(argv[0], L"Next") == 0) 75 | { 76 | RmLogF(rm, LOG_DEBUG, L"Next"); 77 | SwitchDesktop(RmLogF, rm, RightDirection); 78 | } 79 | else if (_wcsicmp(argv[0], L"Prev") == 0) 80 | { 81 | RmLogF(rm, LOG_DEBUG, L"Prev"); 82 | SwitchDesktop(RmLogF, rm, LeftDirection); 83 | } 84 | else if (_wcsicmp(argv[0], L"Create") == 0) 85 | { 86 | RmLogF(rm, LOG_DEBUG, L"Create"); 87 | CreateDesktop(RmLogF, rm); 88 | } 89 | else if (_wcsicmp(argv[0], L"Remove") == 0) 90 | { 91 | if (argc > 1) 92 | { 93 | int d = _wtoi(argv[1]); 94 | RmLogF(rm, LOG_DEBUG, L"Remove %d", d); 95 | RemoveDesktop(RmLogF, rm, d); 96 | } 97 | else 98 | RemoveDesktop(RmLogF, rm, -1); 99 | } 100 | else if (_wcsicmp(argv[0], L"Switch") == 0) 101 | { 102 | if (argc > 1) 103 | { 104 | int d = _wtoi(argv[1]); 105 | RmLogF(rm, LOG_DEBUG, L"Switch %d", d); 106 | SwitchDesktop(RmLogF, rm, d); 107 | } 108 | else 109 | RmLogF(rm, LOG_ERROR, L"Arg expected \"%s\"", argv[0]); 110 | } 111 | else if (_wcsicmp(argv[0], L"SetName") == 0) 112 | { 113 | if (argc > 2) 114 | { 115 | int d = _wtoi(argv[1]); 116 | LPCWSTR name = argv[2]; 117 | RmLogF(rm, LOG_DEBUG, L"SetName %d \"%s\"", d, name); 118 | SetDesktopName(RmLogF, rm, d, name); 119 | } 120 | else 121 | RmLogF(rm, LOG_ERROR, L"Args expected \"%s\"", argv[0]); 122 | } 123 | else if (_wcsicmp(argv[0], L"SetWallpaper") == 0) 124 | { 125 | if (argc > 2) 126 | { 127 | int d = _wtoi(argv[1]); 128 | LPCWSTR wallpaper = argv[2]; 129 | RmLogF(rm, LOG_DEBUG, L"SetWallpaper %d \"%s\"", d, wallpaper); 130 | SetDesktopWallpaper(RmLogF, rm, d, wallpaper); 131 | } 132 | else 133 | RmLogF(rm, LOG_ERROR, L"Args expected \"%s\"", argv[0]); 134 | } 135 | else 136 | RmLogF(rm, LOG_ERROR, L"Invalid Bang \"%s\"", argv[0]); 137 | } 138 | } 139 | 140 | LPCWSTR Name(const int argc, const LPWSTR* argv) const 141 | { 142 | if (argc == 0) 143 | { 144 | buffer.clear(); 145 | buffer = GetDesktopName(RmLogF, rm, -1); 146 | RmLogF(rm, LOG_DEBUG, L"Name \"%s\"", buffer.c_str()); 147 | //return buffer.empty() ? nullptr : buffer.c_str(); 148 | return buffer.c_str(); 149 | } 150 | else if (argc == 1) 151 | { 152 | buffer.clear(); 153 | int d = _wtoi(argv[0]); 154 | buffer = GetDesktopName(RmLogF, rm, d); 155 | RmLogF(rm, LOG_DEBUG, L"Name %d ret \"%s\"", d, buffer.c_str()); 156 | //return buffer.empty() ? nullptr : buffer.c_str(); 157 | return buffer.c_str(); 158 | } 159 | else 160 | return nullptr; 161 | } 162 | 163 | LPCWSTR Wallpaper(const int argc, const LPWSTR* argv) const 164 | { 165 | if (argc == 0) 166 | { 167 | buffer.clear(); 168 | buffer = GetDesktopWallpaper(RmLogF, rm, -1); 169 | RmLogF(rm, LOG_DEBUG, L"Wallpaper ret \"%s\"", buffer.c_str()); 170 | //return buffer.empty() ? nullptr : buffer.c_str(); 171 | return buffer.c_str(); 172 | } 173 | else if (argc == 1) 174 | { 175 | buffer.clear(); 176 | int d = _wtoi(argv[0]); 177 | buffer = GetDesktopWallpaper(RmLogF, rm, d); 178 | RmLogF(rm, LOG_DEBUG, L"Wallpaper %d ret \"%s\"", d, buffer.c_str()); 179 | //return buffer.empty() ? nullptr : buffer.c_str(); 180 | return buffer.c_str(); 181 | } 182 | else 183 | return nullptr; 184 | } 185 | 186 | private: 187 | void* rm; 188 | void* skin; 189 | MeasureType type = MeasureType::CURRENT; 190 | int value = 0; 191 | std::wstring string; 192 | mutable std::wstring buffer; 193 | 194 | DWORD idVirtualDesktopNotification = 0; 195 | CComPtr pNotify; 196 | 197 | private: 198 | virtual void VirtualDesktopCreated(Win10::IVirtualDesktop* pDesktop) override 199 | { 200 | if (type == MeasureType::COUNT) 201 | { 202 | Update(); 203 | UpdateMeasure(); 204 | } 205 | } 206 | 207 | virtual void VirtualDesktopDestroyed(Win10::IVirtualDesktop* pDesktopDestroyed, Win10::IVirtualDesktop* pDesktopFallback) override 208 | { 209 | if (type == MeasureType::COUNT) 210 | { 211 | Update(); 212 | UpdateMeasure(); 213 | } 214 | } 215 | 216 | virtual void CurrentVirtualDesktopChanged(Win10::IVirtualDesktop* pDesktopOld, Win10::IVirtualDesktop* pDesktopNew) override 217 | { 218 | if (type == MeasureType::CURRENT) 219 | { 220 | assert(IsCurrentDesktop(RmLogF, rm, pDesktopNew)); 221 | UpdateCurrent(pDesktopNew); 222 | UpdateMeasure(); 223 | } 224 | } 225 | 226 | virtual void VirtualDesktopNameChanged(Win10::IVirtualDesktop* pDesktop, HSTRING name) override 227 | { 228 | if (type == MeasureType::CURRENT && IsCurrentDesktop(RmLogF, rm, pDesktop)) 229 | { 230 | UpdateCurrent(pDesktop); 231 | UpdateMeasure(); 232 | } 233 | } 234 | 235 | virtual void VirtualDesktopCreated(Win11::IVirtualDesktop* pDesktop) override 236 | { 237 | if (type == MeasureType::COUNT) 238 | { 239 | Update(); 240 | UpdateMeasure(); 241 | } 242 | } 243 | 244 | virtual void VirtualDesktopDestroyed(Win11::IVirtualDesktop* pDesktopDestroyed, Win11::IVirtualDesktop* pDesktopFallback) override 245 | { 246 | if (type == MeasureType::COUNT) 247 | { 248 | Update(); 249 | UpdateMeasure(); 250 | } 251 | } 252 | 253 | virtual void VirtualDesktopMoved(Win11::IVirtualDesktop* pDesktop, int64_t oldIndex, int64_t newIndex) override 254 | { 255 | // TODO 256 | } 257 | 258 | virtual void VirtualDesktopNameChanged(Win11::IVirtualDesktop* pDesktop, HSTRING name) override 259 | { 260 | if (type == MeasureType::CURRENT && IsCurrentDesktop(RmLogF, rm, pDesktop)) 261 | { 262 | UpdateCurrent(pDesktop); 263 | UpdateMeasure(); 264 | } 265 | } 266 | 267 | virtual void CurrentVirtualDesktopChanged(Win11::IVirtualDesktop* pDesktopOld, Win11::IVirtualDesktop* pDesktopNew) override 268 | { 269 | if (type == MeasureType::CURRENT) 270 | { 271 | assert(IsCurrentDesktop(RmLogF, rm, pDesktopNew)); 272 | UpdateCurrent(pDesktopNew); 273 | UpdateMeasure(); 274 | } 275 | } 276 | 277 | private: 278 | void RegisterForNotifications() 279 | { 280 | if (idVirtualDesktopNotification == 0) 281 | { 282 | pNotify = new VirtualDesktopNotification(this); 283 | idVirtualDesktopNotification = Register(RmLogF, rm, pNotify); 284 | } 285 | } 286 | 287 | void UnregisterForNotifications() 288 | { 289 | if (idVirtualDesktopNotification != 0) 290 | { 291 | Unregister(RmLogF, rm, idVirtualDesktopNotification); 292 | idVirtualDesktopNotification = 0; 293 | } 294 | } 295 | 296 | void Update() 297 | { 298 | switch (type) 299 | { 300 | case MeasureType::COUNT: 301 | value = GetDesktopCount(RmLogF, rm); 302 | string.clear(); 303 | break; 304 | case MeasureType::CURRENT: 305 | //UpdateCurrent(GetCurrentDesktop10(RmLogF, rm)); 306 | value = GetCurrentDesktopNumber(RmLogF, rm); 307 | string = GetDesktopName(RmLogF, rm, value); 308 | break; 309 | } 310 | } 311 | 312 | void UpdateCurrent(const CComPtr& pDesktop) 313 | { 314 | assert(type == MeasureType::CURRENT); 315 | value = GetDesktopNumber(RmLogF, rm, pDesktop); 316 | string = GetDesktopName(RmLogF, rm, value); 317 | } 318 | 319 | void UpdateCurrent(const CComPtr& pDesktop) 320 | { 321 | assert(type == MeasureType::CURRENT); 322 | value = GetDesktopNumber(RmLogF, rm, pDesktop); 323 | string = GetDesktopName(RmLogF, rm, value); 324 | } 325 | 326 | void UpdateMeasure() const 327 | { 328 | WCHAR buffer[128]; 329 | _snwprintf_s(buffer, _TRUNCATE, L"!UpdateMeasure \"%s\"", RmGetMeasureName(rm)); 330 | RmExecute(skin, buffer); 331 | RmLog(rm, LOG_DEBUG, buffer); 332 | } 333 | }; 334 | 335 | PLUGIN_EXPORT void Initialize(void** data, void* rm) 336 | { 337 | 338 | Measure* measure = new Measure(rm); 339 | *data = measure; 340 | } 341 | 342 | PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue) 343 | { 344 | Measure* measure = (Measure*)data; 345 | measure->Reload(rm, maxValue); 346 | } 347 | 348 | PLUGIN_EXPORT double Update(void* data) 349 | { 350 | const Measure* measure = (Measure*) data; 351 | return measure->Update(); 352 | } 353 | 354 | PLUGIN_EXPORT LPCWSTR GetString(void* data) 355 | { 356 | const Measure* measure = (Measure*)data; 357 | return measure->GetString(); 358 | } 359 | 360 | PLUGIN_EXPORT void ExecuteBang(void* data, LPCWSTR args) 361 | { 362 | const Measure* measure = (Measure*) data; 363 | int argc = 0; 364 | LPWSTR* argv = CommandLineToArgvW(args, &argc); 365 | measure->ExecuteBang(argc, argv); 366 | LocalFree(argv); 367 | } 368 | 369 | PLUGIN_EXPORT LPCWSTR Name(void* data, const int argc, const LPWSTR argv[]) 370 | { 371 | const Measure* measure = (Measure*) data; 372 | return measure->Name(argc, argv); 373 | } 374 | 375 | PLUGIN_EXPORT LPCWSTR Wallpaper(void* data, const int argc, const LPWSTR argv[]) 376 | { 377 | const Measure* measure = (Measure*) data; 378 | return measure->Wallpaper(argc, argv); 379 | } 380 | 381 | PLUGIN_EXPORT void Finalize(void* data) 382 | { 383 | const Measure* measure = (Measure*)data; 384 | delete measure; 385 | measure = nullptr; 386 | } 387 | -------------------------------------------------------------------------------- /src/VirtualDesktop.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RadAd/RMVirtualDesktop/dd32ebec6028ba78b58339471d886388c4d1d4a1/src/VirtualDesktop.rc -------------------------------------------------------------------------------- /src/VirtualDesktop.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {ECAE7A3B-B18E-481D-992E-7DD70DCA0478} 37 | Win32Proj 38 | VirtualDesktop 39 | 10.0 40 | 41 | 42 | 43 | DynamicLibrary 44 | true 45 | Unicode 46 | v143 47 | 48 | 49 | DynamicLibrary 50 | true 51 | Unicode 52 | v143 53 | 54 | 55 | DynamicLibrary 56 | false 57 | true 58 | Unicode 59 | v143 60 | 61 | 62 | DynamicLibrary 63 | false 64 | true 65 | Unicode 66 | v143 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | true 94 | 95 | 96 | true 97 | 98 | 99 | false 100 | 101 | 102 | false 103 | 104 | 105 | 106 | 107 | 108 | Level3 109 | Disabled 110 | WIN32;_DEBUG;_WINDOWS;_USRDLL;VIRTUALDESKTOP_EXPORTS;%(PreprocessorDefinitions) 111 | MultiThreadedDebug 112 | $(SolutionDir)\API;%(AdditionalIncludeDirectories) 113 | 114 | 115 | true 116 | Rainmeter.lib;WindowsApp.lib;%(AdditionalDependencies) 117 | Windows 118 | $(SolutionDir)\API\$(Platform);%(AdditionalIncludeDirectories) 119 | 120 | 121 | 122 | 123 | 124 | 125 | Level3 126 | Disabled 127 | WIN32;_DEBUG;_WINDOWS;_USRDLL;VIRTUALDESKTOP_EXPORTS;%(PreprocessorDefinitions) 128 | MultiThreadedDebug 129 | $(SolutionDir)\API;%(AdditionalIncludeDirectories) 130 | 131 | 132 | true 133 | Rainmeter.lib;WindowsApp.lib;%(AdditionalDependencies) 134 | Windows 135 | $(SolutionDir)\API\$(Platform);%(AdditionalIncludeDirectories) 136 | 137 | 138 | _WIN64;%(PreprocessorDefinitions) 139 | 140 | 141 | 142 | 143 | Level3 144 | 145 | 146 | MaxSpeed 147 | true 148 | true 149 | WIN32;NDEBUG;_WINDOWS;_USRDLL;VIRTUALDESKTOP_EXPORTS;%(PreprocessorDefinitions) 150 | MultiThreaded 151 | $(SolutionDir)\API;%(AdditionalIncludeDirectories) 152 | 153 | 154 | false 155 | true 156 | .rdata=.text 157 | true 158 | Rainmeter.lib;WindowsApp.lib;%(AdditionalDependencies) 159 | Windows 160 | $(SolutionDir)\API\$(Platform);%(AdditionalIncludeDirectories) 161 | 162 | 163 | 164 | 165 | Level3 166 | 167 | 168 | MaxSpeed 169 | true 170 | true 171 | WIN32;NDEBUG;_WINDOWS;_USRDLL;VIRTUALDESKTOP_EXPORTS;%(PreprocessorDefinitions) 172 | MultiThreaded 173 | $(SolutionDir)\API;%(AdditionalIncludeDirectories) 174 | 175 | 176 | false 177 | true 178 | .rdata=.text 179 | true 180 | Rainmeter.lib;WindowsApp.lib;%(AdditionalDependencies) 181 | Windows 182 | $(SolutionDir)\API\$(Platform);%(AdditionalIncludeDirectories) 183 | 184 | 185 | _WIN64;%(PreprocessorDefinitions) 186 | 187 | 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /src/Win10Desktops.h: -------------------------------------------------------------------------------- 1 | // https://github.com/Ciantic/VirtualDesktopAccessor 2 | 3 | // See for more up-to-date 4 | // https://github.com/skottmckay/VirtualDesktopAccessor 5 | 6 | // See https://github.com/y2nd66/WindowsVirtualDesktop/blob/main/11.22631.2115/11.22631.2115.txt 7 | 8 | #pragma once 9 | 10 | //#include "framework.h" 11 | #include 12 | #include 13 | #include 14 | 15 | class DECLSPEC_UUID("C2F03A33-21F5-47FA-B4BB-156362A2F239") ImmersiveShell; 16 | const CLSID CLSID_ImmersiveShell = __uuidof(ImmersiveShell); 17 | 18 | class DECLSPEC_UUID("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B") VirtualDesktopManagerInternal; 19 | const CLSID CLSID_VirtualDesktopManagerInternal = __uuidof(VirtualDesktopManagerInternal); 20 | 21 | class DECLSPEC_UUID("A501FDEC-4A09-464C-AE4E-1B9C21B84918") VirtualNotificationService; 22 | const CLSID CLSID_VirtualNotificationService = __uuidof(VirtualNotificationService); 23 | 24 | class DECLSPEC_UUID("B5A399E7-1C87-46B8-88E9-FC5747B171BD") VirtualDesktopPinnedApps; 25 | const CLSID CLSID_VirtualDesktopPinnedApps = __uuidof(VirtualDesktopPinnedApps); 26 | 27 | // Ignore following API's: 28 | interface IAsyncCallback; 29 | interface IImmersiveMonitor; 30 | interface APPLICATION_VIEW_COMPATIBILITY_POLICY; 31 | interface IShellPositionerPriority; 32 | interface IApplicationViewOperation; 33 | interface APPLICATION_VIEW_CLOAK_TYPE; 34 | interface IApplicationViewPosition; 35 | interface IImmersiveApplication; 36 | interface IApplicationViewChangeListener; 37 | 38 | 39 | DECLARE_INTERFACE_IID_(IApplicationView, IInspectable, "372E1D3B-38D3-42E4-A15B-8AB2B178F513") 40 | { 41 | STDMETHOD(SetFocus)(THIS) PURE; // Proc6 42 | STDMETHOD(SwitchTo)(THIS) PURE; // Proc7 43 | STDMETHOD(TryInvokeBack)(THIS_ IAsyncCallback*) PURE; // Proc8 44 | STDMETHOD(GetThumbnailWindow)(THIS_ HWND*) PURE; // Proc9 45 | STDMETHOD(GetMonitor)(THIS_ IImmersiveMonitor**) PURE; // Proc10 46 | STDMETHOD(GetVisibility)(THIS_ int*) PURE; // Proc11 47 | STDMETHOD(SetCloak)(THIS_ APPLICATION_VIEW_CLOAK_TYPE, int) PURE; // Proc12 48 | STDMETHOD(GetPosition)(THIS_ REFIID, void**) PURE; // Proc13 49 | STDMETHOD(SetPosition)(THIS_ IApplicationViewPosition*) PURE; // Proc14 50 | STDMETHOD(InsertAfterWindow)(THIS_ HWND) PURE; // Proc15 51 | STDMETHOD(GetExtendedFramePosition)(THIS_ RECT*) PURE; // Proc16 52 | STDMETHOD(GetAppUserModelId)(THIS_ PWSTR*) PURE; // Proc17 53 | STDMETHOD(SetAppUserModelId)(THIS_ PCWSTR) PURE; // Proc18 54 | STDMETHOD(IsEqualByAppUserModelId)(THIS_ PCWSTR, int*) PURE; // Proc19 55 | STDMETHOD(GetViewState)(THIS_ UINT*) PURE; // Proc20 56 | STDMETHOD(SetViewState)(THIS_ UINT) PURE; // Proc21 57 | STDMETHOD(GetNeediness)(THIS_ int*) PURE; // Proc22 58 | STDMETHOD(GetLastActivationTimestamp)(THIS_ ULONGLONG*) PURE; // Proc23 59 | STDMETHOD(SetLastActivationTimestamp)(THIS_ ULONGLONG) PURE; // Proc24 60 | STDMETHOD(GetVirtualDesktopId)(THIS_ GUID*) PURE; // Proc25 61 | STDMETHOD(SetVirtualDesktopId)(THIS_ REFGUID) PURE; // Proc26 62 | STDMETHOD(GetShowInSwitchers)(THIS_ int*) PURE; // Proc27 63 | STDMETHOD(SetShowInSwitchers)(THIS_ int) PURE; // Proc28 64 | STDMETHOD(GetScaleFactor)(THIS_ int*) PURE; // Proc29 65 | STDMETHOD(CanReceiveInput)(THIS_ BOOL*) PURE; // Proc30 66 | STDMETHOD(GetCompatibilityPolicyType)(THIS_ APPLICATION_VIEW_COMPATIBILITY_POLICY*) PURE; // Proc31 67 | STDMETHOD(SetCompatibilityPolicyType)(THIS_ APPLICATION_VIEW_COMPATIBILITY_POLICY) PURE; // Proc32 68 | //STDMETHOD(GetPositionPriority)(THIS_ IShellPositionerPriority**) PURE; // removed in 1803 // Proc33 69 | //STDMETHOD(SetPositionPriority)(THIS_ IShellPositionerPriority*) PURE; // removed in 1803 // Proc34 70 | STDMETHOD(GetSizeConstraints)(THIS_ IImmersiveMonitor*, SIZE*, SIZE*) PURE; // Proc35 71 | STDMETHOD(GetSizeConstraintsForDpi)(THIS_ UINT, SIZE*, SIZE*) PURE; // Proc36 72 | STDMETHOD(SetSizeConstraintsForDpi)(THIS_ const UINT*, const SIZE*, const SIZE*) PURE; // Proc37 73 | //STDMETHOD(QuerySizeConstraintsFromApp)(THIS) PURE; // removed in 1803 // Proc38 74 | STDMETHOD(OnMinSizePreferencesUpdated)(THIS_ HWND) PURE; // Proc39 75 | STDMETHOD(ApplyOperation)(THIS_ IApplicationViewOperation*) PURE; // Proc40 76 | STDMETHOD(IsTray)(THIS_ BOOL*) PURE; // Proc41 77 | STDMETHOD(IsInHighZOrderBand)(THIS_ BOOL*) PURE; // Proc42 78 | STDMETHOD(IsSplashScreenPresented)(THIS_ BOOL*) PURE; // Proc43 79 | STDMETHOD(Flash)(THIS) PURE; // Proc44 80 | STDMETHOD(GetRootSwitchableOwner)(THIS_ IApplicationView**) PURE; // proc45 81 | STDMETHOD(EnumerateOwnershipTree)(THIS_ IObjectArray**) PURE; // proc46 82 | STDMETHOD(GetEnterpriseId)(THIS_ PWSTR*) PURE; // proc47 83 | STDMETHOD(IsMirrored)(THIS_ BOOL*) PURE; // Proc48 84 | STDMETHOD(Proc49)(THIS_ int*) PURE; 85 | STDMETHOD(Proc50)(THIS_ /* ENUM32 */ int32_t*) PURE; 86 | STDMETHOD(Proc51)(THIS_ int*) PURE; 87 | STDMETHOD(Proc52)(THIS_ int) PURE; 88 | STDMETHOD(Proc53)(THIS_ int*) PURE; 89 | STDMETHOD(Proc54)(THIS_ int) PURE; 90 | STDMETHOD(Proc55)(THIS) PURE; 91 | STDMETHOD(Proc56)(THIS_ int*) PURE; 92 | STDMETHOD(Proc57)(THIS_ int) PURE; 93 | STDMETHOD(Proc58)(THIS_ /* ENUM32 */ uint32_t, /* ENUM32 */ uint32_t) PURE; 94 | STDMETHOD(Proc59)(THIS_ int) PURE; 95 | STDMETHOD(Proc60)(THIS_ SIZE*) PURE; 96 | STDMETHOD(Proc61)(THIS_ PWSTR*) PURE; 97 | }; 98 | 99 | const __declspec(selectany) IID& IID_IApplicationView = __uuidof(IApplicationView); 100 | 101 | DECLARE_INTERFACE_IID_(IApplicationViewCollection, IUnknown, "1841C6D7-4F9D-42C0-AF41-8747538F10E5") 102 | { 103 | STDMETHOD(GetViews)(THIS_ IObjectArray**) PURE; 104 | STDMETHOD(GetViewsByZOrder)(THIS_ IObjectArray**) PURE; 105 | STDMETHOD(GetViewsByAppUserModelId)(THIS_ PCWSTR, IObjectArray**) PURE; 106 | STDMETHOD(GetViewForHwnd)(THIS_ HWND, IApplicationView**) PURE; 107 | STDMETHOD(GetViewForApplication)(THIS_ IImmersiveApplication*, IApplicationView**) PURE; 108 | STDMETHOD(GetViewForAppUserModelId)(THIS_ PCWSTR, IApplicationView**) PURE; 109 | STDMETHOD(GetViewInFocus)(THIS_ IApplicationView**) PURE; 110 | STDMETHOD(TryGetLastActiveVisibleView)(THIS_ IApplicationView**) PURE; 111 | STDMETHOD(RefreshCollection)(THIS) PURE; 112 | STDMETHOD(RegisterForApplicationViewChanges)(THIS_ IApplicationViewChangeListener*, DWORD*) PURE; 113 | STDMETHOD(UnregisterForApplicationViewChanges)(THIS_ DWORD) PURE; 114 | }; 115 | 116 | const __declspec(selectany) IID& IID_IApplicationViewCollection = __uuidof(IApplicationViewCollection); 117 | 118 | DECLARE_INTERFACE_IID_(IVirtualDesktopPinnedApps, IUnknown, "4CE81583-1E4C-4632-A621-07A53543148F") 119 | { 120 | STDMETHOD(IsAppIdPinned)(THIS_ PCWSTR appId, BOOL*) PURE; 121 | STDMETHOD(PinAppID)(THIS_ PCWSTR appId) PURE; 122 | STDMETHOD(UnpinAppID)(THIS_ PCWSTR appId) PURE; 123 | STDMETHOD(IsViewPinned)(THIS_ IApplicationView*, BOOL*) PURE; 124 | STDMETHOD(PinView)(THIS_ IApplicationView*) PURE; 125 | STDMETHOD(UnpinView)(THIS_ IApplicationView*) PURE; 126 | }; 127 | 128 | namespace Win10 { 129 | 130 | MIDL_INTERFACE("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4") 131 | IVirtualDesktop : public IUnknown 132 | { 133 | public: 134 | virtual HRESULT STDMETHODCALLTYPE IsViewVisible( 135 | _In_ IApplicationView* pView, 136 | _Out_ BOOL* pfVisible) = 0; 137 | 138 | virtual HRESULT STDMETHODCALLTYPE GetID( 139 | _Out_ GUID* pGuid) = 0; 140 | }; 141 | 142 | MIDL_INTERFACE("31EBDE3F-6EC3-4CBD-B9FB-0EF6D09B41F4") 143 | IVirtualDesktop2: public IVirtualDesktop 144 | { 145 | public: 146 | virtual HRESULT STDMETHODCALLTYPE GetName( 147 | _Out_ HSTRING* pStr) = 0; 148 | }; 149 | 150 | } 151 | 152 | namespace Win11 { 153 | 154 | MIDL_INTERFACE("3F07F4BE-B107-441A-AF0F-39D82529072C") 155 | IVirtualDesktop : public IUnknown 156 | { 157 | public: 158 | virtual HRESULT STDMETHODCALLTYPE IsViewVisible( 159 | _In_ IApplicationView* pView, 160 | _Out_ BOOL* pfVisible) = 0; 161 | 162 | virtual HRESULT STDMETHODCALLTYPE GetID( 163 | _Out_ GUID* pGuid) = 0; 164 | 165 | virtual HRESULT STDMETHODCALLTYPE GetName( 166 | _Out_ HSTRING* p0) = 0; 167 | 168 | virtual HRESULT STDMETHODCALLTYPE GetWallpaperPath( 169 | _Out_ HSTRING* p0) = 0; 170 | 171 | virtual HRESULT STDMETHODCALLTYPE IsRemote( 172 | _Out_ BOOL* pBool) = 0; 173 | }; 174 | 175 | } 176 | 177 | enum AdjacentDesktop 178 | { 179 | LeftDirection = 3, 180 | RightDirection = 4 181 | }; 182 | 183 | namespace Win10 { 184 | 185 | MIDL_INTERFACE("F31574D6-B682-4CDC-BD56-1827860ABEC6") 186 | IVirtualDesktopManagerInternal : public IUnknown 187 | { 188 | public: 189 | virtual HRESULT STDMETHODCALLTYPE GetCount( 190 | _Out_ UINT* pCount) = 0; 191 | 192 | virtual HRESULT STDMETHODCALLTYPE MoveViewToDesktop( 193 | _In_ IApplicationView* pView, 194 | _In_ IVirtualDesktop* pDesktop) = 0; 195 | 196 | // Since build 10240 197 | virtual HRESULT STDMETHODCALLTYPE CanViewMoveDesktops( 198 | _In_ IApplicationView* pView, 199 | _Out_ BOOL* pfCanViewMoveDesktops) = 0; 200 | 201 | virtual HRESULT STDMETHODCALLTYPE GetCurrentDesktop( 202 | _Out_ IVirtualDesktop** desktop) = 0; 203 | 204 | virtual HRESULT STDMETHODCALLTYPE GetDesktops( 205 | _Out_ IObjectArray** ppDesktops) = 0; 206 | 207 | virtual HRESULT STDMETHODCALLTYPE GetAdjacentDesktop( 208 | _In_ IVirtualDesktop* pDesktopReference, 209 | _In_ AdjacentDesktop uDirection, 210 | _Out_ IVirtualDesktop** ppAdjacentDesktop) = 0; 211 | 212 | virtual HRESULT STDMETHODCALLTYPE SwitchDesktop( 213 | _In_ IVirtualDesktop* pDesktop) = 0; 214 | 215 | virtual HRESULT STDMETHODCALLTYPE CreateDesktopW( 216 | _Out_ IVirtualDesktop** ppNewDesktop) = 0; 217 | 218 | virtual HRESULT STDMETHODCALLTYPE RemoveDesktop( 219 | _In_ IVirtualDesktop* pRemove, 220 | _In_ IVirtualDesktop* pFallbackDesktop) = 0; 221 | 222 | // Since build 10240 223 | virtual HRESULT STDMETHODCALLTYPE FindDesktop( 224 | _In_ GUID* desktopId, 225 | _Out_ IVirtualDesktop** ppDesktop) = 0; 226 | 227 | // Since build ?? 228 | virtual HRESULT STDMETHODCALLTYPE Proc13( 229 | _In_ IVirtualDesktop* pDesktop, 230 | _Out_ IObjectArray** ppDesktops1, 231 | _Out_ IObjectArray** ppDesktops2) = 0; 232 | }; 233 | 234 | MIDL_INTERFACE("0F3A72B0-4566-487E-9A33-4ED302F6D6CE") 235 | IVirtualDesktopManagerInternal2 : public IVirtualDesktopManagerInternal 236 | { 237 | public: 238 | virtual HRESULT STDMETHODCALLTYPE SetDesktopName( 239 | _In_ IVirtualDesktop* p0, 240 | _In_ HSTRING name) = 0; 241 | }; 242 | 243 | MIDL_INTERFACE("FE538FF5-D53B-4F5A-9DAD-8E72873CB360") 244 | IVirtualDesktopManagerInternal3 : public IVirtualDesktopManagerInternal2 245 | { 246 | public: 247 | virtual HRESULT STDMETHODCALLTYPE Proc15( 248 | _In_ IApplicationView* p0, 249 | _In_ IApplicationView* p1) = 0; 250 | }; 251 | 252 | } 253 | 254 | namespace Win11 { 255 | 256 | MIDL_INTERFACE("A3175F2D-239C-4BD2-8AA0-EEBA8B0B138E") 257 | IVirtualDesktopManagerInternal : public IUnknown 258 | { 259 | public: 260 | virtual HRESULT STDMETHODCALLTYPE GetCount( 261 | _Out_ UINT* pCount) = 0; 262 | 263 | virtual HRESULT STDMETHODCALLTYPE MoveViewToDesktop( 264 | _In_ IApplicationView* pView, 265 | _In_ IVirtualDesktop* pDesktop) = 0; 266 | 267 | virtual HRESULT STDMETHODCALLTYPE CanViewMoveDesktops( 268 | _In_ IApplicationView* pView, 269 | _Out_ BOOL* pfCanViewMoveDesktops) = 0; 270 | 271 | virtual HRESULT STDMETHODCALLTYPE GetCurrentDesktop( 272 | _Out_ IVirtualDesktop** desktop) = 0; 273 | 274 | virtual HRESULT STDMETHODCALLTYPE GetDesktops( 275 | _Out_ IObjectArray** ppDesktops) = 0; 276 | 277 | virtual HRESULT STDMETHODCALLTYPE GetAdjacentDesktop( 278 | _In_ IVirtualDesktop* pDesktopReference, 279 | _In_ AdjacentDesktop uDirection, 280 | _Out_ IVirtualDesktop** ppAdjacentDesktop) = 0; 281 | 282 | virtual HRESULT STDMETHODCALLTYPE SwitchDesktop( 283 | _In_ IVirtualDesktop* pDesktop) = 0; 284 | 285 | virtual HRESULT STDMETHODCALLTYPE CreateDesktopW( 286 | _Out_ IVirtualDesktop** ppNewDesktop) = 0; 287 | 288 | virtual HRESULT STDMETHODCALLTYPE MoveDesktop( 289 | _In_ IVirtualDesktop* desktop, 290 | _In_ INT32 index) = 0; 291 | 292 | virtual HRESULT STDMETHODCALLTYPE RemoveDesktop( 293 | _In_ IVirtualDesktop* pRemove, 294 | _In_ IVirtualDesktop* pFallbackDesktop) = 0; 295 | 296 | virtual HRESULT STDMETHODCALLTYPE FindDesktop( 297 | _In_ GUID* desktopId, 298 | _Out_ IVirtualDesktop** ppDesktop) = 0; 299 | 300 | virtual HRESULT STDMETHODCALLTYPE GetDesktopSwitchIncludeExcludeViews( 301 | _In_ IVirtualDesktop* pDesktop, 302 | _Out_ IObjectArray** ppDesktops1, 303 | _Out_ IObjectArray** ppDesktops2) = 0; 304 | 305 | virtual HRESULT STDMETHODCALLTYPE SetDesktopName( 306 | _In_ IVirtualDesktop* p0, 307 | _In_ HSTRING name) = 0; 308 | 309 | virtual HRESULT STDMETHODCALLTYPE SetDesktopWallpaper( 310 | _In_ IVirtualDesktop* p0, 311 | _In_ HSTRING name) = 0; 312 | 313 | virtual HRESULT STDMETHODCALLTYPE UpdateWallpaperPathForAllDesktops( 314 | _In_ HSTRING name) = 0; 315 | 316 | virtual HRESULT STDMETHODCALLTYPE CopyDesktopState( 317 | _In_ IApplicationView* p0, 318 | _In_ IApplicationView* p1) = 0; 319 | 320 | virtual HRESULT STDMETHODCALLTYPE CreateRemoteDesktop( 321 | _In_ HSTRING name, 322 | _Out_ IVirtualDesktop** desktop) = 0; 323 | 324 | virtual HRESULT STDMETHODCALLTYPE SwitchRemoteDesktop( 325 | _In_ IVirtualDesktop* pDesktop) = 0; 326 | 327 | virtual HRESULT STDMETHODCALLTYPE SwitchDesktopWithAnimation( 328 | _In_ IVirtualDesktop* pDesktop) = 0; 329 | 330 | virtual HRESULT STDMETHODCALLTYPE GetLastActiveDesktop( 331 | _Out_ IVirtualDesktop** desktop) = 0; 332 | 333 | virtual HRESULT STDMETHODCALLTYPE WaitForAnimationToComplete() = 0; 334 | }; 335 | } 336 | 337 | namespace Win10 { 338 | 339 | MIDL_INTERFACE("C179334C-4295-40D3-BEA1-C654D965605A") 340 | IVirtualDesktopNotification : public IUnknown 341 | { 342 | public: 343 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopCreated( 344 | _In_ IVirtualDesktop* pDesktop) = 0; 345 | 346 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyBegin( 347 | _In_ IVirtualDesktop* pDesktopDestroyed, 348 | _In_ IVirtualDesktop* pDesktopFallback) = 0; 349 | 350 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyFailed( 351 | _In_ IVirtualDesktop* pDesktopDestroyed, 352 | _In_ IVirtualDesktop* pDesktopFallback) = 0; 353 | 354 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyed( 355 | _In_ IVirtualDesktop* pDesktopDestroyed, 356 | _In_ IVirtualDesktop* pDesktopFallback) = 0; 357 | 358 | virtual HRESULT STDMETHODCALLTYPE ViewVirtualDesktopChanged( 359 | _In_ IApplicationView* pView) = 0; 360 | 361 | virtual HRESULT STDMETHODCALLTYPE CurrentVirtualDesktopChanged( 362 | _In_ IVirtualDesktop* pDesktopOld, 363 | _In_ IVirtualDesktop* pDesktopNew) = 0; 364 | }; 365 | 366 | const __declspec(selectany) IID& IID_IVirtualDesktopNotification = __uuidof(IVirtualDesktopNotification); 367 | 368 | MIDL_INTERFACE("1BA7CF30-3591-43FA-ABFA-4AAF7ABEEDB7") 369 | IVirtualDesktopNotification2 : public IVirtualDesktopNotification 370 | { 371 | public: 372 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopNameChanged( 373 | _In_ IVirtualDesktop* pDesktop, 374 | _In_ HSTRING p1) = 0; 375 | }; 376 | 377 | MIDL_INTERFACE("0CD45E71-D927-4F15-8B0A-8FEF525337BF") 378 | IVirtualDesktopNotificationService : public IUnknown 379 | { 380 | public: 381 | virtual HRESULT STDMETHODCALLTYPE Register( 382 | _In_ IVirtualDesktopNotification * pNotification, 383 | _Out_ DWORD * pdwCookie) = 0; 384 | 385 | virtual HRESULT STDMETHODCALLTYPE Unregister( 386 | _In_ DWORD dwCookie) = 0; 387 | }; 388 | 389 | } 390 | 391 | namespace Win11 { 392 | 393 | MIDL_INTERFACE("B287FA1C-7771-471A-A2DF-9B6B21F0D675") 394 | IVirtualDesktopNotification : public IUnknown 395 | { 396 | public: 397 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopCreated( 398 | _In_ IVirtualDesktop* pDesktop) = 0; 399 | 400 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyBegin( 401 | _In_ IVirtualDesktop* pDesktopDestroyed, 402 | _In_ IVirtualDesktop* pDesktopFallback) = 0; 403 | 404 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyFailed( 405 | _In_ IVirtualDesktop* pDesktopDestroyed, 406 | _In_ IVirtualDesktop* pDesktopFallback) = 0; 407 | 408 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopDestroyed( 409 | _In_ IVirtualDesktop* pDesktopDestroyed, 410 | _In_ IVirtualDesktop* pDesktopFallback) = 0; 411 | 412 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopMoved( 413 | _In_ IVirtualDesktop* pDesktop, 414 | _In_ int64_t oldIndex, 415 | _In_ int64_t newIndex) = 0; 416 | 417 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopNameChanged11( 418 | _In_ IVirtualDesktop* pDesktop, 419 | _In_ HSTRING name) = 0; 420 | 421 | virtual HRESULT STDMETHODCALLTYPE ViewVirtualDesktopChanged11( 422 | _In_ IApplicationView* pView) = 0; 423 | 424 | virtual HRESULT STDMETHODCALLTYPE CurrentVirtualDesktopChanged( 425 | _In_ IVirtualDesktop* pDesktopOld, 426 | _In_ IVirtualDesktop* pDesktopNew) = 0; 427 | 428 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopWallpaperChanged( 429 | _In_ IVirtualDesktop* pDesktop, 430 | _In_ HSTRING name) = 0; 431 | 432 | virtual HRESULT STDMETHODCALLTYPE VirtualDesktopSwitched( 433 | _In_ IVirtualDesktop* pDesktop) = 0; 434 | 435 | virtual HRESULT STDMETHODCALLTYPE RemoteVirtualDesktopConnected( 436 | _In_ IVirtualDesktop* pDesktop) = 0; 437 | }; 438 | 439 | const __declspec(selectany) IID& IID_IVirtualDesktopNotification = __uuidof(IVirtualDesktopNotification); 440 | 441 | MIDL_INTERFACE("0CD45E71-D927-4F15-8B0A-8FEF525337BF") 442 | IVirtualDesktopNotificationService : public IUnknown 443 | { 444 | public: 445 | virtual HRESULT STDMETHODCALLTYPE Register( 446 | _In_ IVirtualDesktopNotification * pNotification, 447 | _Out_ DWORD * pdwCookie) = 0; 448 | 449 | virtual HRESULT STDMETHODCALLTYPE Unregister( 450 | _In_ DWORD dwCookie) = 0; 451 | }; 452 | 453 | } 454 | 455 | inline HRESULT SwitchDesktop(Win10::IVirtualDesktopManagerInternal* pDesktopManagerInternal, Win10::IVirtualDesktop* pDesktop, bool /*bWithAnimation*/) 456 | { 457 | return pDesktopManagerInternal->SwitchDesktop(pDesktop); 458 | } 459 | 460 | inline HRESULT SwitchDesktop(Win11::IVirtualDesktopManagerInternal* pDesktopManagerInternal, Win11::IVirtualDesktop* pDesktop, bool bWithAnimation) 461 | { 462 | if (bWithAnimation) 463 | return pDesktopManagerInternal->SwitchDesktopWithAnimation(pDesktop); 464 | else 465 | return pDesktopManagerInternal->SwitchDesktop(pDesktop); 466 | } 467 | --------------------------------------------------------------------------------