├── .gitignore ├── LICENSE ├── README.md ├── screenshots ├── ContextMenu.png └── PropertyHandler.png └── src ├── RevitLaucher.Package ├── Images │ ├── LockScreenLogo.scale-200.png │ ├── SplashScreen.scale-200.png │ ├── Square150x150Logo.scale-200.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── StoreLogo.png │ └── Wide310x150Logo.scale-200.png ├── Package.appxmanifest └── RevitLaucher.Package.wapproj ├── RevitLauncher.Addin ├── App.cs ├── FileOpenExternalEvent.cs ├── PackageContents.xml ├── Properties │ └── launchSettings.json ├── RevitLauncher.Addin.csproj └── RevitLauncher.addin ├── RevitLauncher.Core ├── RevitFileInfo.cs ├── RevitLauncher.Core.csproj └── Utils │ ├── AddInArchitecture.cs │ ├── LanguageType.cs │ ├── ProcessUtils.cs │ ├── ProductType.cs │ ├── RevitProduct.cs │ ├── RevitProductUtility.cs │ ├── RevitVersion.cs │ └── Win32API.cs ├── RevitLauncher.InstallAction ├── Program.cs ├── RevitLauncher.InstallAction.csproj └── RevitLauncher.propdesc ├── RevitLauncher.Setup └── RevitLauncher.Setup.vdproj ├── RevitLauncher.ShellExtension ├── ContextMenu │ ├── CommandBase │ │ ├── BaseExplorerCommand.cs │ │ ├── EnumExplorerCommand.cs │ │ └── ShellExtensionHelper.cs │ ├── ExistProcessCommand.cs │ ├── LockingProcessCommand.cs │ ├── NewProcessCommand.cs │ ├── RevitLauncherCommand.cs │ └── StringInfoCommand.cs ├── Interop │ ├── HRESULT.cs │ ├── PropSys │ │ ├── IInitializeWithFile.cs │ │ ├── IInitializeWithStream.cs │ │ ├── IPropertyStore.cs │ │ ├── IPropertyStoreCapabilities.cs │ │ ├── PROPERTYKEY.cs │ │ ├── PROPVARIANT.cs │ │ └── STGM.cs │ └── Shell32 │ │ ├── EXPCMDFLAGS.cs │ │ ├── EXPCMDSTATE.cs │ │ ├── IEnumExplorerCommand.cs │ │ ├── IExplorerCommand.cs │ │ ├── IShellItem.cs │ │ ├── IShellItemArray.cs │ │ └── SIGDN.cs ├── PropertyHandler │ ├── IStreamExtensions.cs │ └── RevitPropertyStore.cs ├── RevitLauncher.ShellExtension.csproj └── launchericon.ico ├── RevitLauncher.sln └── RevitLauncher ├── Program.cs ├── RevitLauncher.csproj ├── app.manifest ├── launchericon.ico └── launchericon.png /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RevitLauncher 2 | 3 | A Revit launcher integrated in the windows context menu. 4 | 5 | Automatically detect the Revit file version, support opening the file in the new process, or open in the current existing Revit process. 6 | 7 | Supports ".rvt", ".rte", ".rft", ".rfa" 4 file extensions. 8 | 9 | ## Screenshots 10 | 11 | ### ConetxtMenu 12 | 13 | - Locking Process 14 | 15 | Click to switch to process who locking the file. 16 | 17 | - Exist Process (Match/Mismatch version) 18 | 19 | List all running revit processes. Click to opening the file in specified process. 20 | 21 | - New Process 22 | 23 | List all the revit versions installed on your computer. Click to starting a new Revit process and opening the file. 24 | 25 | ![ConetxtMenu](./screenshots/ContextMenu.png) 26 | 27 | ### PropertyHandler 28 | 29 | Show `RevitVersion` info with a windows explorer column. 30 | 31 | ![PropertyHandler](./screenshots/PropertyHandler.png) 32 | 33 | ## Third Party 34 | 35 | - [OpenMcdf](https://github.com/ironfede/openmcdf) 36 | 37 | ## Installation 38 | 39 | Get the latest installer from the [Releases](https://github.com/Zhuangkh/RevitLauncher/releases) page. 40 | 41 | This project uses [Microsoft Visual Studio Installer Projects](https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2017InstallerProjects) to generate the MSI package. 42 | 43 | At the same time, with the help of [srm.exe](https://www.nuget.org/packages/ServerRegistrationManager) to complete the registration of shell extensions. 44 | 45 | You may need to restart the *Explorer* process after completing the MSI installation to see the effect. 46 | 47 | ## License 48 | 49 | [Apache 2.0 License](./LICENSE). 50 | -------------------------------------------------------------------------------- /screenshots/ContextMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/screenshots/ContextMenu.png -------------------------------------------------------------------------------- /screenshots/PropertyHandler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/screenshots/PropertyHandler.png -------------------------------------------------------------------------------- /src/RevitLaucher.Package/Images/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/src/RevitLaucher.Package/Images/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /src/RevitLaucher.Package/Images/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/src/RevitLaucher.Package/Images/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /src/RevitLaucher.Package/Images/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/src/RevitLaucher.Package/Images/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /src/RevitLaucher.Package/Images/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/src/RevitLaucher.Package/Images/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /src/RevitLaucher.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/src/RevitLaucher.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /src/RevitLaucher.Package/Images/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/src/RevitLaucher.Package/Images/StoreLogo.png -------------------------------------------------------------------------------- /src/RevitLaucher.Package/Images/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/src/RevitLaucher.Package/Images/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /src/RevitLaucher.Package/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 14 | 15 | 19 | 20 | 21 | RevitLauncher 22 | Zhuangkh 23 | Images\StoreLogo.png 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | .rvt 52 | .rfa 53 | .rte 54 | .rft 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 82 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/RevitLaucher.Package/RevitLaucher.Package.wapproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15.0 5 | 6 | 7 | 8 | Debug 9 | x86 10 | 11 | 12 | Release 13 | x86 14 | 15 | 16 | Debug 17 | x64 18 | 19 | 20 | Release 21 | x64 22 | 23 | 24 | 25 | $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\ 26 | 27 | 28 | 29 | 48feddb8-eb63-41b2-9833-9abcf5ba434c 30 | 10.0.22000.0 31 | 10.0.18362.0 32 | zh-CN 33 | True 34 | SHA256 35 | False 36 | x64 37 | $(NoWarn);NU1702 38 | ..\RevitLauncher\RevitLauncher.csproj 39 | False 40 | True 41 | 0 42 | EA4ABEB1364F7760130754D831A6C797DCBE26F7 43 | 44 | 45 | Auto 46 | 47 | 48 | Auto 49 | 50 | 51 | Auto 52 | 53 | 54 | Auto 55 | 56 | 57 | 58 | Designer 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/RevitLauncher.Addin/App.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.IO.Pipes; 5 | using System.Threading.Tasks; 6 | using Autodesk.Revit.UI; 7 | 8 | namespace RevitLauncher.Addin 9 | { 10 | public class App : IExternalApplication 11 | { 12 | private NamedPipeServerStream _server; 13 | private string _pipeName; 14 | private ExternalEvent _externalEvent; 15 | public static string Path { get; set; } = string.Empty; 16 | 17 | public App() 18 | { 19 | _pipeName = Process.GetCurrentProcess().Id.ToString(); 20 | _server = new NamedPipeServerStream(_pipeName, PipeDirection.In, 3, PipeTransmissionMode.Message); 21 | } 22 | 23 | public Result OnStartup(UIControlledApplication application) 24 | { 25 | _externalEvent = ExternalEvent.Create(new FileOpenExternalEvent()); 26 | Task.Run(new Action(() => 27 | { 28 | while (true) 29 | { 30 | _server.WaitForConnection(); 31 | Trace.WriteLine("Conneted"); 32 | 33 | StreamReader streamReader = new StreamReader(_server); 34 | string line = string.Empty; 35 | while ((line = streamReader.ReadLine()) != null) 36 | { 37 | App.Path = line; 38 | _externalEvent.Raise(); 39 | } 40 | 41 | Trace.WriteLine("Disconnetion"); 42 | _server.Disconnect(); 43 | 44 | Task.Delay(100); 45 | } 46 | 47 | })); 48 | return Result.Succeeded; 49 | } 50 | 51 | public Result OnShutdown(UIControlledApplication application) 52 | { 53 | _server?.Dispose(); 54 | 55 | return Result.Succeeded; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/RevitLauncher.Addin/FileOpenExternalEvent.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Autodesk.Revit; 3 | using Autodesk.Revit.DB.ExternalService; 4 | using Autodesk.Revit.UI; 5 | 6 | namespace RevitLauncher.Addin 7 | { 8 | public class FileOpenExternalEvent : IExternalEventHandler 9 | { 10 | public FileOpenExternalEvent() 11 | { 12 | ExternalEvent.Create(this); 13 | } 14 | public void Execute(UIApplication app) 15 | { 16 | if (!string.IsNullOrEmpty(App.Path) && File.Exists(App.Path)) 17 | { 18 | app.OpenAndActivateDocument(App.Path); 19 | } 20 | 21 | App.Path = string.Empty; 22 | } 23 | 24 | public string GetName() 25 | { 26 | return "FileOpen Server"; 27 | } 28 | 29 | 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/RevitLauncher.Addin/PackageContents.xml: -------------------------------------------------------------------------------- 1 |  2 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/RevitLauncher.Addin/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "RevitLauncher.Addin": { 4 | "commandName": "Project" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /src/RevitLauncher.Addin/RevitLauncher.Addin.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net452 5 | AnyCPU;x64 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Always 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/RevitLauncher.Addin/RevitLauncher.addin: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | RevitLauncher 5 | RevitLauncher.Addin.dll 6 | 1A71F325-30E9-4D18-BB70-10FB4CFE4157 7 | RevitLauncher.Addin.App 8 | RevitLauncher 9 | Zhuangkh 10 | Zhuangkh, zhuangkh.com 11 | 12 | -------------------------------------------------------------------------------- /src/RevitLauncher.Core/RevitFileInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Pipes; 4 | using System.Text; 5 | using OpenMcdf; 6 | 7 | namespace RevitLauncher.Core 8 | { 9 | public class RevitFileInfo 10 | { 11 | private const string _infoStream = "BasicFileInfo"; 12 | public string Username { get; private set; } = string.Empty; 13 | public string CentralPath { get; private set; } = string.Empty; 14 | public string LanguageWhenSaved { get; private set; } = string.Empty; 15 | public Guid LatestCentralEpisodeGUID { get; private set; } = Guid.Empty; 16 | public int LatestCentralVersion { get; private set; } = 0; 17 | public string SavedInVersion { get; private set; } = string.Empty; 18 | public bool AllLocalChangesSavedToCentral { get; private set; } = false; 19 | public bool IsCentral { get; private set; } = false; 20 | public bool IsLocal { get; private set; } = false; 21 | public bool IsWorkshared { get; private set; } = false; 22 | 23 | public RevitFileInfo(string filePath) 24 | { 25 | FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 26 | Init(fileStream); 27 | } 28 | 29 | public RevitFileInfo(Stream stream) 30 | { 31 | Init(stream); 32 | } 33 | 34 | private void Init(Stream stream) 35 | { 36 | CompoundFile compoundFile = new CompoundFile(stream, CFSUpdateMode.ReadOnly, CFSConfiguration.Default); 37 | CFStream cfStream = compoundFile.RootStorage.GetStream(_infoStream); 38 | string rawString = Encoding.UTF8.GetString(cfStream.GetData()); 39 | compoundFile.Close(); 40 | 41 | var fileInfoDatas = rawString.Replace("\0", "").Split(new string[] { "\r\n", "\t" }, StringSplitOptions.RemoveEmptyEntries); 42 | foreach (var info in fileInfoDatas) 43 | { 44 | if (info.Contains("Worksharing:")) 45 | { 46 | string workshare = Behind(info, "Worksharing:"); 47 | if (workshare.Contains("Local")) 48 | { 49 | IsLocal = true; 50 | } 51 | else if (workshare.Contains("Central")) 52 | { 53 | IsCentral = true; 54 | } 55 | } 56 | else if (info.Contains("Username:")) 57 | { 58 | Username = Behind(info, "Username:"); 59 | } 60 | else if (info.Contains("Central File Path:")) 61 | { 62 | CentralPath = Behind(info, "Central File Path:"); 63 | } 64 | else if (info.Contains("Central Model Path:")) 65 | { 66 | CentralPath = Behind(info, "Central Model Path:"); 67 | } 68 | else if (info.Contains("Revit Build: ")) 69 | { 70 | string version = Behind(info, "Revit Build: "); 71 | if (version.Contains("Autodesk Revit ")) 72 | { 73 | SavedInVersion = Behind(version, "Autodesk Revit ").Substring(0, 4); 74 | } 75 | else 76 | { 77 | SavedInVersion = "2009"; 78 | break; 79 | } 80 | } 81 | else if (info.Contains("Format: ")) 82 | { 83 | string version = Behind(info, "Format: "); 84 | SavedInVersion = version; 85 | break; 86 | } 87 | else if (info.Contains("Locale when saved: ")) 88 | { 89 | LanguageWhenSaved = Behind(info, "Locale when saved: "); 90 | } 91 | else if (info.Contains("All Local Changes Saved To Central:")) 92 | { 93 | AllLocalChangesSavedToCentral = int.Parse(Behind(info, "All Local Changes Saved To Central:")) == 1; 94 | } 95 | else if (info.Contains("Central model's version number corresponding to the last reload latest:")) 96 | { 97 | LatestCentralVersion = int.Parse(Behind(info, "Central model's version number corresponding to the last reload latest:")); 98 | } 99 | else if (info.Contains("Central model's episode GUID corresponding to the last reload latest:")) 100 | { 101 | LatestCentralEpisodeGUID = Guid.Parse(Behind(info, "Central model's episode GUID corresponding to the last reload latest:")); 102 | } 103 | 104 | } 105 | } 106 | 107 | private static string Behind(string source, string key) 108 | { 109 | return source.Substring(source.LastIndexOf(key)).Remove(0, key.Length).Trim(); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/RevitLauncher.Core/RevitLauncher.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0-windows10.0.17763 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/RevitLauncher.Core/Utils/AddInArchitecture.cs: -------------------------------------------------------------------------------- 1 | namespace RevitLauncher.Core.Utils 2 | { 3 | /// Defines the operating system architectures recognized by the Add-In utility. 4 | public enum AddInArchitecture 5 | { 6 | /// 32-bit operating system. 7 | OS32bit = 1, 8 | /// 64-bit operating system. 9 | OS64bit 10 | } 11 | } -------------------------------------------------------------------------------- /src/RevitLauncher.Core/Utils/LanguageType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace RevitLauncher.Core.Utils 8 | { 9 | /// Defines the language type of Revit Add-In. 10 | public enum LanguageType 11 | { 12 | /// Unknown. 13 | Unknown = -1, 14 | /// English USA. 15 | English_USA, 16 | /// German. 17 | German, 18 | /// Spanish. 19 | Spanish, 20 | /// French. 21 | French, 22 | /// Italian. 23 | Italian, 24 | /// Dutch. 25 | Dutch, 26 | /// Chinese Simplified. 27 | Chinese_Simplified, 28 | /// Chinese Traditional. 29 | Chinese_Traditional, 30 | /// Japanese. 31 | Japanese, 32 | /// Korean. 33 | Korean, 34 | /// Russian. 35 | Russian, 36 | /// Czech. 37 | Czech, 38 | /// Polish. 39 | Polish, 40 | /// Hungarian. 41 | Hungarian, 42 | /// Brazilian Portuguese. 43 | Brazilian_Portuguese, 44 | /// English GB. 45 | English_GB 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/RevitLauncher.Core/Utils/ProcessUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | 5 | namespace RevitLauncher.Core.Utils 6 | { 7 | public class ProcessUtils 8 | { 9 | ///   10 | /// Start external process  11 | ///   12 | /// application location  13 | /// 命令行参数  14 | public static bool StartProcess(string application, string args) 15 | { 16 | try 17 | { 18 | Process myprocess = new Process(); 19 | ProcessStartInfo startInfo = new ProcessStartInfo(application, $"\"{args}\""); 20 | myprocess.StartInfo = startInfo; 21 | myprocess.StartInfo.UseShellExecute = false; 22 | myprocess.Start(); 23 | return true; 24 | } 25 | catch (Exception) 26 | { 27 | //ignore 28 | } 29 | return false; 30 | } 31 | 32 | /// 33 | /// Find out what process(es) have a lock on the specified file. 34 | /// 35 | /// Path of the file. 36 | /// Processes locking the file 37 | /// See also: 38 | /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx 39 | /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing) 40 | /// 41 | /// 42 | public static List GetLockingProcesses(string path) 43 | { 44 | uint handle; 45 | string key = Guid.NewGuid().ToString(); 46 | List processes = new List(); 47 | 48 | int res = Win32API.RmStartSession(out handle, 0, key); 49 | if (res != 0) throw new Exception("Could not begin restart session. Unable to determine file locker."); 50 | 51 | try 52 | { 53 | const int ERROR_MORE_DATA = 234; 54 | uint pnProcInfoNeeded = 0, 55 | pnProcInfo = 0, 56 | lpdwRebootReasons = Win32API.RmRebootReasonNone; 57 | 58 | string[] resources = new string[] { path }; // Just checking on one resource. 59 | 60 | res = Win32API.RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null); 61 | 62 | if (res != 0) throw new Exception("Could not register resource."); 63 | 64 | //Note: there's a race condition here -- the first call to RmGetList() returns 65 | // the total number of process. However, when we call RmGetList() again to get 66 | // the actual processes this number may have increased. 67 | res = Win32API.RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons); 68 | 69 | if (res == ERROR_MORE_DATA) 70 | { 71 | // Create an array to store the process results 72 | Win32API.RM_PROCESS_INFO[] processInfo = new Win32API.RM_PROCESS_INFO[pnProcInfoNeeded]; 73 | pnProcInfo = pnProcInfoNeeded; 74 | 75 | // Get the list 76 | res = Win32API.RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons); 77 | if (res == 0) 78 | { 79 | processes = new List((int)pnProcInfo); 80 | 81 | // Enumerate all of the results and add them to the 82 | // list to be returned 83 | for (int i = 0; i < pnProcInfo; i++) 84 | { 85 | try 86 | { 87 | processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId)); 88 | } 89 | // catch the error -- in case the process is no longer running 90 | catch (ArgumentException) { } 91 | } 92 | } 93 | else throw new Exception("Could not list processes locking resource."); 94 | } 95 | else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result."); 96 | } 97 | finally 98 | { 99 | Win32API.RmEndSession(handle); 100 | } 101 | 102 | return processes; 103 | } 104 | 105 | public static void SwitchToProcess(Process process) 106 | { 107 | Win32API.ShowWindow(process.MainWindowHandle, 5); 108 | Win32API.SetForegroundWindow(process.MainWindowHandle); 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /src/RevitLauncher.Core/Utils/ProductType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace RevitLauncher.Core.Utils 8 | { 9 | /// An enumerated type containing the possible Revit product types. 10 | /// 11 | /// 2012 12 | /// 13 | public enum ProductType 14 | { 15 | /// Architecture. 16 | Architecture, 17 | /// Structure. 18 | Structure, 19 | /// MEP. 20 | MEP, 21 | /// Revit. 22 | Revit, 23 | /// Unknown. 24 | Unknown 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/RevitLauncher.Core/Utils/RevitProduct.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.Win32; 7 | using RevitLauncher.Core.Utils; 8 | 9 | namespace RevitLauncher.Core.Utils 10 | { 11 | /// Represents an installed instance of Revit on the local machine. 12 | public class RevitProduct 13 | { 14 | /// The folder path in which .addin files associated to all users will be located for this product. 15 | public string AllUsersAddInFolder { get; private set; } 16 | 17 | /// The folder path in which .addin files associated to the current user will be located for this product. 18 | public string CurrentUserAddInFolder { get; private set; } 19 | 20 | /// The folder path where this Revit product is installed. 21 | public string InstallLocation { get; private set; } 22 | 23 | /// User-visible name for this Revit product. such as : 'Autodesk Revit Architecture 2010'. 24 | public string Name { get; private set; } 25 | 26 | /// The system architecture of this Revit product installation. 27 | public AddInArchitecture Architecture { get; } = AddInArchitecture.OS64bit; 28 | 29 | /// The id used to locate and identify the Revit product from the registry. 30 | public Guid ProductCode { get; private set; } 31 | 32 | /// The version for this Revit product. Such as: '2010'. 33 | public RevitVersion Version { get; } 34 | 35 | /// The release subversion. 36 | /// 37 | /// 2012 38 | /// 39 | //[CLSCompliant(false)] 40 | public uint Subversion { get; private set; } 41 | 42 | /// The product type. 43 | /// 44 | /// 2012 45 | /// 46 | public ProductType Product { get; private set; } = ProductType.Unknown; 47 | 48 | /// The string for the release sub versions. 49 | /// SubVersion releases may have additional APIs and functionality not available in the standard customer releases. Add-ins written to support standard Revit releases should be compatible with Subversion releases, but add-ins written specifically targeting new features in Subversion releases would not be compatible with the standard releases. 50 | /// 51 | /// 2018 52 | /// 53 | public string ReleaseSubVersion { get; private set; } 54 | 55 | /// Gets the installed language types. 56 | /// 57 | /// The installed language types. 58 | /// 59 | /// 60 | /// 2014 61 | /// 62 | private ICollection GetInstalledLanguages() 63 | { 64 | List list = new List(); 65 | byte[] array = this.ProductCode.ToByteArray(); 66 | byte[] array2 = array; 67 | int num = 6; 68 | array2[num] |= 1; 69 | foreach (LanguageType languageType in RevitProduct.sm_languageMap.Keys) 70 | { 71 | array[8] = RevitProduct.sm_languageMap[languageType][0]; 72 | array[9] = RevitProduct.sm_languageMap[languageType][1]; 73 | if (this.isGuidExistingInUninstallKeys(new Guid(array))) 74 | { 75 | list.Add(languageType); 76 | } 77 | } 78 | return list; 79 | } 80 | 81 | /// Default constructor 82 | internal RevitProduct() 83 | { 84 | } 85 | 86 | /// Constructor, set basic info for an Revit product. 87 | /// Use to uniquely identify each product, it's a GUID. 88 | /// Use to identify product type. 89 | /// Architecture information, such as 32bit or 64bit. 90 | /// Define the version number, such as 2010, 2011. 91 | internal RevitProduct(Guid productCode, ProductType product, AddInArchitecture architecture, RevitVersion version) 92 | { 93 | this.ProductCode = productCode; 94 | this.Product = product; 95 | this.Architecture = architecture; 96 | this.Version = version; 97 | } 98 | 99 | /// Gets the SubscriptionUpdate value from the registry. 100 | internal bool getSubscriptionValue() 101 | { 102 | bool result = false; 103 | string arg = RevitProductUtility.ConvertProductTypetoCode(this.Product); 104 | ICollection installedLanguages = this.GetInstalledLanguages(); 105 | foreach (LanguageType languageType in installedLanguages) 106 | { 107 | string arg2 = RevitProductUtility.ConvertLanguageTypeToCode(languageType); 108 | string name = string.Format("SOFTWARE\\Autodesk\\Revit\\{0}\\REVIT-{1}:{2}", this.Version.ToString().Replace("Revit", ""), arg, arg2); 109 | RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(name); 110 | if (registryKey != null) 111 | { 112 | int num = 0; 113 | int num2 = (int)registryKey.GetValue("SubscriptionUpdate", num); 114 | if (num2 == 1) 115 | { 116 | result = true; 117 | } 118 | registryKey.Close(); 119 | } 120 | } 121 | return result; 122 | } 123 | 124 | internal void SetProductCode(string productCode) 125 | { 126 | this.ProductCode = new Guid(productCode); 127 | } 128 | 129 | internal void SetInstallLocation(string value) 130 | { 131 | this.InstallLocation = value; 132 | } 133 | 134 | internal void SetName(string value) 135 | { 136 | this.Name = value; 137 | } 138 | 139 | internal void SetAllUsersAddInFolder(string value) 140 | { 141 | this.AllUsersAddInFolder = value; 142 | } 143 | 144 | internal void SetCurrentUserAddInFolder(string value) 145 | { 146 | this.CurrentUserAddInFolder = value; 147 | } 148 | 149 | internal void setSubversion(uint subversion) 150 | { 151 | this.Subversion = subversion; 152 | } 153 | 154 | internal void setReleaseSubVersion(string value) 155 | { 156 | this.ReleaseSubVersion = value; 157 | } 158 | 159 | internal void setLanguage(LanguageType languageType) 160 | { 161 | this.m_Language = languageType; 162 | } 163 | 164 | internal void setProduct(ProductType product) 165 | { 166 | this.Product = product; 167 | } 168 | 169 | private bool isGuidExistingInUninstallKeys(Guid value) 170 | { 171 | RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall").OpenSubKey(value.ToString("B")); 172 | return registryKey != null; 173 | } 174 | 175 | static RevitProduct() 176 | { 177 | RevitProduct.sm_languageMap.Add(LanguageType.Chinese_Simplified, new byte[] 178 | { 179 | 8, 180 | 4 181 | }); 182 | RevitProduct.sm_languageMap.Add(LanguageType.Chinese_Traditional, new byte[] 183 | { 184 | 4, 185 | 4 186 | }); 187 | RevitProduct.sm_languageMap.Add(LanguageType.Czech, new byte[] 188 | { 189 | 4, 190 | 5 191 | }); 192 | RevitProduct.sm_languageMap.Add(LanguageType.German, new byte[] 193 | { 194 | 4, 195 | 7 196 | }); 197 | RevitProduct.sm_languageMap.Add(LanguageType.English_USA, new byte[] 198 | { 199 | 4, 200 | 9 201 | }); 202 | RevitProduct.sm_languageMap.Add(LanguageType.Spanish, new byte[] 203 | { 204 | 4, 205 | 10 206 | }); 207 | RevitProduct.sm_languageMap.Add(LanguageType.French, new byte[] 208 | { 209 | 4, 210 | 12 211 | }); 212 | RevitProduct.sm_languageMap.Add(LanguageType.Hungarian, new byte[] 213 | { 214 | 4, 215 | 14 216 | }); 217 | RevitProduct.sm_languageMap.Add(LanguageType.Italian, new byte[] 218 | { 219 | 4, 220 | 16 221 | }); 222 | RevitProduct.sm_languageMap.Add(LanguageType.Japanese, new byte[] 223 | { 224 | 4, 225 | 17 226 | }); 227 | RevitProduct.sm_languageMap.Add(LanguageType.Korean, new byte[] 228 | { 229 | 4, 230 | 18 231 | }); 232 | RevitProduct.sm_languageMap.Add(LanguageType.Polish, new byte[] 233 | { 234 | 4, 235 | 21 236 | }); 237 | RevitProduct.sm_languageMap.Add(LanguageType.Brazilian_Portuguese, new byte[] 238 | { 239 | 4, 240 | 22 241 | }); 242 | RevitProduct.sm_languageMap.Add(LanguageType.Russian, new byte[] 243 | { 244 | 4, 245 | 25 246 | }); 247 | RevitProduct.sm_languageMap.Add(LanguageType.English_GB, new byte[] 248 | { 249 | 8, 250 | 9 251 | }); 252 | } 253 | 254 | private LanguageType m_Language = LanguageType.Unknown; 255 | 256 | private static IDictionary sm_languageMap = new Dictionary(); 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /src/RevitLauncher.Core/Utils/RevitProductUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Runtime.InteropServices; 7 | using System.Text; 8 | using System.Text.RegularExpressions; 9 | using System.Threading.Tasks; 10 | using Microsoft.Win32; 11 | using RevitLauncher.Core.Utils; 12 | 13 | namespace RevitLauncher.Core.Utils 14 | { 15 | /// Provides access to installed versions of Revit on the local machine. 16 | public sealed class RevitProductUtility 17 | { 18 | /// Gets a list of Revit products installed on this machine. 19 | /// This operation parses the registry for necessary information about the installation(s). 20 | /// An incomplete or incorrect installation of Revit may not be returned correctly by this utility. 21 | public static List GetAllInstalledRevitProducts() 22 | { 23 | List list = new List(); 24 | RevitProductUtility.InitializeProductsDictionary(); 25 | try 26 | { 27 | List installedRevitProductCodes = RevitProductUtility.GetInstalledRevitProductCodes(); 28 | foreach (string productCode in installedRevitProductCodes) 29 | { 30 | RevitProduct revitProduct = RevitProductUtility.GetRevitProduct(productCode); 31 | if (revitProduct != null) 32 | { 33 | list.Add(revitProduct); 34 | } 35 | } 36 | } 37 | catch (Exception) 38 | { 39 | } 40 | 41 | return list; 42 | } 43 | 44 | internal static LanguageType ConvertLanguageCodeToType(int code) 45 | { 46 | switch (code) 47 | { 48 | case 1028: 49 | return LanguageType.Chinese_Traditional; 50 | case 1029: 51 | return LanguageType.Czech; 52 | case 1030: 53 | case 1032: 54 | case 1035: 55 | case 1037: 56 | case 1039: 57 | case 1043: 58 | case 1044: 59 | case 1047: 60 | case 1048: 61 | break; 62 | case 1031: 63 | return LanguageType.German; 64 | case 1033: 65 | return LanguageType.English_USA; 66 | case 1034: 67 | return LanguageType.Spanish; 68 | case 1036: 69 | return LanguageType.French; 70 | case 1038: 71 | return LanguageType.Hungarian; 72 | case 1040: 73 | return LanguageType.Italian; 74 | case 1041: 75 | return LanguageType.Japanese; 76 | case 1042: 77 | return LanguageType.Korean; 78 | case 1045: 79 | return LanguageType.Polish; 80 | case 1046: 81 | return LanguageType.Brazilian_Portuguese; 82 | case 1049: 83 | return LanguageType.Russian; 84 | default: 85 | if (code == 2052) 86 | { 87 | return LanguageType.Chinese_Simplified; 88 | } 89 | 90 | if (code == 2057) 91 | { 92 | return LanguageType.English_GB; 93 | } 94 | 95 | break; 96 | } 97 | 98 | return LanguageType.Unknown; 99 | } 100 | 101 | internal static string ConvertLanguageTypeToCode(LanguageType languageType) 102 | { 103 | switch (languageType) 104 | { 105 | case LanguageType.English_USA: 106 | return "0409"; 107 | case LanguageType.German: 108 | return "0407"; 109 | case LanguageType.Spanish: 110 | return "040A"; 111 | case LanguageType.French: 112 | return "040C"; 113 | case LanguageType.Italian: 114 | return "0410"; 115 | case LanguageType.Chinese_Simplified: 116 | return "0804"; 117 | case LanguageType.Chinese_Traditional: 118 | return "0404"; 119 | case LanguageType.Japanese: 120 | return "0411"; 121 | case LanguageType.Korean: 122 | return "0412"; 123 | case LanguageType.Russian: 124 | return "0419"; 125 | case LanguageType.Czech: 126 | return "0405"; 127 | case LanguageType.Polish: 128 | return "0415"; 129 | case LanguageType.Hungarian: 130 | return "040E"; 131 | case LanguageType.Brazilian_Portuguese: 132 | return "0416"; 133 | case LanguageType.English_GB: 134 | return "0809"; 135 | } 136 | 137 | return "0409"; 138 | } 139 | 140 | internal static RevitVersion ConverVersionCodeToVersion(int code) 141 | { 142 | switch (code) 143 | { 144 | case 11: 145 | return RevitVersion.Revit2011; 146 | case 12: 147 | return RevitVersion.Revit2012; 148 | case 13: 149 | return RevitVersion.Revit2013; 150 | case 14: 151 | return RevitVersion.Revit2014; 152 | case 15: 153 | return RevitVersion.Revit2015; 154 | case 16: 155 | return RevitVersion.Revit2016; 156 | case 17: 157 | return RevitVersion.Revit2017; 158 | case 18: 159 | return RevitVersion.Revit2018; 160 | case 19: 161 | return RevitVersion.Revit2019; 162 | case 20: 163 | return RevitVersion.Revit2020; 164 | case 21: 165 | return RevitVersion.Revit2021; 166 | case 22: 167 | return RevitVersion.Revit2022; 168 | case 23: 169 | return RevitVersion.Revit2023; 170 | default: 171 | return RevitVersion.Unknown; 172 | } 173 | } 174 | 175 | internal static ProductType ConvertDisciplineCodeToProductType(int code) 176 | { 177 | switch (code) 178 | { 179 | case 1: 180 | return ProductType.Architecture; 181 | case 2: 182 | return ProductType.Structure; 183 | case 3: 184 | return ProductType.MEP; 185 | case 5: 186 | return ProductType.Revit; 187 | } 188 | 189 | return ProductType.Unknown; 190 | } 191 | 192 | internal static string ConvertProductTypetoCode(ProductType product) 193 | { 194 | switch (product) 195 | { 196 | case ProductType.Architecture: 197 | return "01"; 198 | case ProductType.Structure: 199 | return "02"; 200 | case ProductType.MEP: 201 | return "03"; 202 | case ProductType.Revit: 203 | return "05"; 204 | default: 205 | return "01"; 206 | } 207 | } 208 | 209 | /// 210 | /// Initialize a dictionary to store all the RevitProducts which 211 | /// can be supported by this RevitAddInUtility 212 | /// 213 | /// NOTE: This method only initializes the product codes for Revit 2011 and RVT 2013. 214 | /// Since 2012 we analysis the Revit product code (not include the dynamo) of RevitDB.dll component with a fixed pattern, 215 | /// please see RevitProductUtility::getRevitProduct method for more details. 216 | /// 217 | private static void InitializeProductsDictionary() 218 | { 219 | if (RevitProductUtility._mProductsHashtable == null) 220 | { 221 | RevitProductUtility._mProductsHashtable = new Hashtable(); 222 | } 223 | else 224 | { 225 | RevitProductUtility._mProductsHashtable.Clear(); 226 | } 227 | 228 | RevitProductUtility._mProductsHashtable.Add("{4AF99FCA-1D0C-4D5A-9BFE-0D4376A52B23}", 229 | new RevitProduct(new Guid("{4AF99FCA-1D0C-4D5A-9BFE-0D4376A52B23}"), ProductType.Architecture, 230 | AddInArchitecture.OS32bit, RevitVersion.Revit2011)); 231 | RevitProductUtility._mProductsHashtable.Add("{0EE1FCA9-7474-4143-8F22-E7AD998FACBF}", 232 | new RevitProduct(new Guid("{0EE1FCA9-7474-4143-8F22-E7AD998FACBF}"), ProductType.Structure, 233 | AddInArchitecture.OS32bit, RevitVersion.Revit2011)); 234 | RevitProductUtility._mProductsHashtable.Add("{CCCB80C8-5CC5-4EB7-89D0-F18E405F18F9}", 235 | new RevitProduct(new Guid("{CCCB80C8-5CC5-4EB7-89D0-F18E405F18F9}"), ProductType.MEP, 236 | AddInArchitecture.OS32bit, RevitVersion.Revit2011)); 237 | RevitProductUtility._mProductsHashtable.Add("{7A177659-6ADE-439F-9B68-AAB03739A5CF}", 238 | new RevitProduct(new Guid("{7A177659-6ADE-439F-9B68-AAB03739A5CF}"), ProductType.Revit, 239 | AddInArchitecture.OS32bit, RevitVersion.Revit2013)); 240 | RevitProductUtility._mProductsHashtable.Add("{94D463D0-2B13-4181-9512-B27004B1151A}", 241 | new RevitProduct(new Guid("{94D463D0-2B13-4181-9512-B27004B1151A}"), ProductType.Architecture, 242 | AddInArchitecture.OS64bit, RevitVersion.Revit2011)); 243 | RevitProductUtility._mProductsHashtable.Add("{23853368-22DD-4817-904B-DB04ADE9B0C8}", 244 | new RevitProduct(new Guid("{23853368-22DD-4817-904B-DB04ADE9B0C8}"), ProductType.Structure, 245 | AddInArchitecture.OS64bit, RevitVersion.Revit2011)); 246 | RevitProductUtility._mProductsHashtable.Add("{C31F3560-0007-4955-9F65-75CB47F82DB5}", 247 | new RevitProduct(new Guid("{C31F3560-0007-4955-9F65-75CB47F82DB5}"), ProductType.MEP, 248 | AddInArchitecture.OS64bit, RevitVersion.Revit2011)); 249 | RevitProductUtility._mProductsHashtable.Add("{2F816EFF-FACE-4000-AC88-C9AAA4A05E5D}", 250 | new RevitProduct(new Guid("{2F816EFF-FACE-4000-AC88-C9AAA4A05E5D}"), ProductType.Revit, 251 | AddInArchitecture.OS64bit, RevitVersion.Revit2013)); 252 | } 253 | 254 | /// Gets information of installed Revit from registry. 255 | private static RevitProduct GetInstalledProductInfo(string productRegGuid) 256 | { 257 | if (RevitProductUtility._mProductsHashtable.ContainsKey(productRegGuid)) 258 | { 259 | RevitProduct revitProduct = (RevitProduct)RevitProductUtility._mProductsHashtable[productRegGuid]; 260 | RegistryKey registryKey = Registry.LocalMachine 261 | .OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall").OpenSubKey(productRegGuid); 262 | if (registryKey == null) 263 | { 264 | string subKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + productRegGuid; 265 | UIntPtr hKey; 266 | if (Win32API.RegOpenKeyEx(RevitProductUtility._hkeyLocalMachine, subKey, 0, 131609, 267 | out hKey) != 0 && Win32API.RegOpenKeyEx(RevitProductUtility._hkeyLocalMachine, 268 | subKey, 0, 131353, out hKey) != 0) 269 | { 270 | return null; 271 | } 272 | 273 | uint num = 1024u; 274 | uint code = 0u; 275 | StringBuilder stringBuilder = new StringBuilder(1024); 276 | uint num2; 277 | Win32API.RegQueryValueEx(hKey, "InstallLocation", 0, out num2, stringBuilder, out num); 278 | revitProduct.SetInstallLocation(stringBuilder.ToString()); 279 | num = 1024u; 280 | Win32API.RegQueryValueEx(hKey, "DisplayName", 0, out num2, stringBuilder, out num); 281 | revitProduct.SetName(stringBuilder.ToString()); 282 | Win32API.RegQueryValueEx(hKey, "Language", 0, out num2, out code, out num); 283 | revitProduct.setLanguage(RevitProductUtility.ConvertLanguageCodeToType((int)code)); 284 | revitProduct.SetAllUsersAddInFolder( 285 | Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + 286 | "\\Autodesk\\Revit\\AddIns\\" + revitProduct.Version.ToString().Replace("Revit", "")); 287 | revitProduct.SetCurrentUserAddInFolder( 288 | Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + 289 | "\\Autodesk\\Revit\\AddIns\\" + revitProduct.Version.ToString().Replace("Revit", "")); 290 | Win32API.RegCloseKey(hKey); 291 | } 292 | else 293 | { 294 | revitProduct.SetInstallLocation((string)registryKey.GetValue("InstallLocation")); 295 | revitProduct.SetName((string)registryKey.GetValue("DisplayName")); 296 | revitProduct.setLanguage( 297 | RevitProductUtility.ConvertLanguageCodeToType((int)registryKey.GetValue("Language"))); 298 | revitProduct.SetAllUsersAddInFolder( 299 | Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + 300 | "\\Autodesk\\Revit\\AddIns\\" + revitProduct.Version.ToString().Replace("Revit", "")); 301 | revitProduct.SetCurrentUserAddInFolder( 302 | Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + 303 | "\\Autodesk\\Revit\\AddIns\\" + revitProduct.Version.ToString().Replace("Revit", "")); 304 | registryKey.Close(); 305 | } 306 | 307 | return revitProduct; 308 | } 309 | 310 | return null; 311 | } 312 | 313 | /// Gets product codes of the installed Revits. 314 | public static List GetInstalledRevitProductCodes() 315 | { 316 | List list = new List(); 317 | string text = new string('0', GuidStringSize); 318 | uint num = 0u; 319 | while (Win32API.MsiEnumClients(RevitDBComponentID, num++, text) == 0u) 320 | { 321 | string item = string.Copy(text); 322 | list.Add(item); 323 | } 324 | 325 | return list; 326 | } 327 | 328 | /// Gets product information with the product code. 329 | private static RevitProduct GetRevitProduct(string productCode) 330 | { 331 | Regex regex = 332 | new Regex( 333 | "^(\\{{0,1}(7346B4A[0-9a-fA-F])-(?([0-9a-fA-F]){2})(?([0-9a-fA-F]){2})-(?([0-9a-fA-F]){2})(?([0-9a-fA-F]){1})[0-9a-fA-F]-(?([0-9a-fA-F]){4})-705C0D862004\\}{0,1})$"); 334 | Match match = regex.Match(productCode); 335 | if (match.Success) 336 | { 337 | int code = int.Parse(match.Result("${Majorversion}")); 338 | AddInArchitecture architecture = (match.Result("${Platform}").CompareTo("0") == 0) 339 | ? AddInArchitecture.OS32bit 340 | : AddInArchitecture.OS64bit; 341 | RevitVersion version = RevitProductUtility.ConverVersionCodeToVersion(code); 342 | int code2 = int.Parse(match.Result("${Discipline}"), NumberStyles.AllowHexSpecifier); 343 | ProductType product = RevitProductUtility.ConvertDisciplineCodeToProductType(code2); 344 | RevitProduct revitProduct = new RevitProduct(new Guid(productCode), product, architecture, version); 345 | int code3 = int.Parse(match.Result("${Language}"), NumberStyles.AllowHexSpecifier); 346 | revitProduct.setLanguage(RevitProductUtility.ConvertLanguageCodeToType(code3)); 347 | revitProduct.setReleaseSubVersion("2021.0"); 348 | string text = new string(' ', 260); 349 | string text2 = new string(' ', 260); 350 | int length = 260; 351 | int length2 = 260; 352 | Win32API.MsiGetProductInfo(productCode, "ProductName", text, out length); 353 | Win32API.MsiGetProductInfo(productCode, "InstallLocation", text2, out length2); 354 | text = text.Substring(0, length); 355 | text2 = text2.Substring(0, length2); 356 | revitProduct.SetName(text); 357 | revitProduct.SetInstallLocation(text2); 358 | uint subversion = (uint)int.Parse(match.Result("${Subversion}"), NumberStyles.AllowHexSpecifier); 359 | revitProduct.setSubversion(subversion); 360 | revitProduct.SetAllUsersAddInFolder( 361 | Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + 362 | "\\Autodesk\\Revit\\AddIns\\" + revitProduct.Version.ToString().Replace("Revit", "")); 363 | revitProduct.SetCurrentUserAddInFolder( 364 | Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + 365 | "\\Autodesk\\Revit\\AddIns\\" + revitProduct.Version.ToString().Replace("Revit", "")); 366 | return revitProduct; 367 | } 368 | 369 | return RevitProductUtility.GetInstalledProductInfo(productCode); 370 | } 371 | 372 | /// Is used to store all the RevitProduct which can be supported by this RevitAddInUtility. 373 | private static Hashtable _mProductsHashtable = null; 374 | 375 | private static UIntPtr _hkeyLocalMachine = new UIntPtr(2147483650u); 376 | 377 | private const int KeyRead = 131097; 378 | 379 | private const int KeyWow6464Key = 256; 380 | 381 | private const int KeyWow6432Key = 512; 382 | 383 | private const int GuidStringSize = 38; 384 | 385 | private const string RevitDBComponentID = "{DF7D485F-B8BA-448E-A444-E6FB1C258912}"; 386 | 387 | private const int MaxSize = 260; 388 | 389 | private const string ReleaseSubVersion = "2021.0"; 390 | } 391 | } 392 | -------------------------------------------------------------------------------- /src/RevitLauncher.Core/Utils/RevitVersion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace RevitLauncher.Core.Utils 8 | { 9 | /// Defines the versions of Revit supported by the Add-In utility. 10 | public enum RevitVersion 11 | { 12 | /// Unknown. 13 | Unknown = -1, 14 | /// Revit 2011. 15 | Revit2011 = 1, 16 | /// Revit 2012. 17 | Revit2012, 18 | /// Revit 2013. 19 | Revit2013, 20 | /// Revit 2014. 21 | Revit2014, 22 | /// Revit 2015. 23 | Revit2015, 24 | /// Revit 2016. 25 | Revit2016, 26 | /// Revit 2017. 27 | Revit2017, 28 | /// Revit 2018. 29 | Revit2018, 30 | /// Revit 2019. 31 | Revit2019, 32 | /// Revit 2020. 33 | Revit2020, 34 | /// Revit 2021. 35 | Revit2021, 36 | /// Revit 2022. 37 | Revit2022, 38 | /// Revit 2023. 39 | Revit2023 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/RevitLauncher.Core/Utils/Win32API.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.InteropServices; 4 | using System.Text; 5 | 6 | namespace RevitLauncher.Core.Utils 7 | { 8 | public class Win32API 9 | { 10 | internal delegate bool WNDENUMPROC(IntPtr hWnd, int lParam); 11 | 12 | [DllImport("user32.dll")] 13 | 14 | internal static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, int lParam); 15 | 16 | [DllImport("user32.dll")] 17 | internal static extern int GetWindowTextW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpString, int nMaxCount); 18 | 19 | [DllImport("user32.dll")] 20 | internal static extern int GetClassNameW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpString, int nMaxCount); 21 | 22 | [DllImport("user32.dll", SetLastError = true)] 23 | internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out IntPtr processId); 24 | 25 | [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] 26 | internal static extern IntPtr SetFocus(HandleRef hWnd); 27 | 28 | [DllImport("user32.dll")] 29 | [return: MarshalAs(UnmanagedType.Bool)] 30 | internal static extern bool SetForegroundWindow(IntPtr hWnd); 31 | 32 | [DllImport("user32.dll")] 33 | internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 34 | 35 | [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] 36 | internal static extern int RmRegisterResources(uint pSessionHandle, 37 | UInt32 nFiles, 38 | string[] rgsFilenames, 39 | UInt32 nApplications, 40 | [In] RM_UNIQUE_PROCESS[] rgApplications, 41 | UInt32 nServices, 42 | string[] rgsServiceNames); 43 | 44 | [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)] 45 | internal static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey); 46 | 47 | [DllImport("rstrtmgr.dll")] 48 | internal static extern int RmEndSession(uint pSessionHandle); 49 | 50 | [DllImport("rstrtmgr.dll")] 51 | internal static extern int RmGetList(uint dwSessionHandle, 52 | out uint pnProcInfoNeeded, 53 | ref uint pnProcInfo, 54 | [In, Out] RM_PROCESS_INFO[] rgAffectedApps, 55 | ref uint lpdwRebootReasons); 56 | [DllImport("user32.dll")] 57 | internal static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab); 58 | 59 | [DllImport("advapi32.dll", CharSet = CharSet.Auto)] 60 | internal static extern int RegOpenKeyEx(UIntPtr hKey, string subKey, int ulOptions, int samDesired, 61 | out UIntPtr hkResult); 62 | 63 | [DllImport("advapi32.dll", CharSet = CharSet.Auto)] 64 | internal static extern int RegQueryValueEx(UIntPtr hKey, string lpValueName, int lpReserved, out uint lpType, 65 | StringBuilder lpData, out uint lpcbData); 66 | 67 | [DllImport("advapi32.dll", CharSet = CharSet.Auto)] 68 | internal static extern int RegQueryValueEx(UIntPtr hKey, string lpValueName, int lpReserved, out uint lpType, 69 | out uint lpData, out uint lpcbData); 70 | 71 | [DllImport("advapi32.dll", SetLastError = true)] 72 | internal static extern int RegCloseKey(UIntPtr hKey); 73 | 74 | [DllImport("msi.dll", CharSet = CharSet.Unicode)] 75 | internal static extern uint MsiEnumClients(string szComponent, uint iProductIndex, string lpProductBuf); 76 | 77 | [DllImport("msi.dll", CharSet = CharSet.Unicode)] 78 | internal static extern int MsiGetComponentPath(string szProduct, string szComponent, string lpPathBuf, 79 | out uint pcchBuf); 80 | 81 | [DllImport("msi.dll", CharSet = CharSet.Unicode)] 82 | internal static extern int MsiGetProductInfo(string product, string property, string valueBuf, out int len); 83 | 84 | public struct WindowInfo 85 | { 86 | public IntPtr HWnd; 87 | public IntPtr Pid; 88 | public string WindowName; 89 | public string ClassName; 90 | } 91 | 92 | public static WindowInfo[] GetAllDesktopWindows() 93 | { 94 | List wndList = new List(); 95 | 96 | EnumWindows(delegate (IntPtr hWnd, int lParam) 97 | { 98 | WindowInfo wnd = new WindowInfo(); 99 | StringBuilder sb = new StringBuilder(256); 100 | 101 | wnd.HWnd = hWnd; 102 | GetWindowTextW(hWnd, sb, sb.Capacity); 103 | wnd.WindowName = sb.ToString(); 104 | GetClassNameW(hWnd, sb, sb.Capacity); 105 | wnd.ClassName = sb.ToString(); 106 | GetWindowThreadProcessId(hWnd, out wnd.Pid); 107 | 108 | wndList.Add(wnd); 109 | return true; 110 | }, 0); 111 | 112 | return wndList.ToArray(); 113 | } 114 | 115 | [StructLayout(LayoutKind.Sequential)] 116 | internal struct RM_UNIQUE_PROCESS 117 | { 118 | public int dwProcessId; 119 | public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime; 120 | } 121 | 122 | internal const int RmRebootReasonNone = 0; 123 | internal const int CCH_RM_MAX_APP_NAME = 255; 124 | internal const int CCH_RM_MAX_SVC_NAME = 63; 125 | 126 | internal enum RM_APP_TYPE 127 | { 128 | RmUnknownApp = 0, 129 | RmMainWindow = 1, 130 | RmOtherWindow = 2, 131 | RmService = 3, 132 | RmExplorer = 4, 133 | RmConsole = 5, 134 | RmCritical = 1000 135 | } 136 | 137 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 138 | internal struct RM_PROCESS_INFO 139 | { 140 | public RM_UNIQUE_PROCESS Process; 141 | 142 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] 143 | public string strAppName; 144 | 145 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] 146 | public string strServiceShortName; 147 | 148 | public RM_APP_TYPE ApplicationType; 149 | public uint AppStatus; 150 | public uint TSSessionId; 151 | [MarshalAs(UnmanagedType.Bool)] 152 | public bool bRestartable; 153 | } 154 | 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/RevitLauncher.InstallAction/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System; 3 | using System.IO; 4 | using System.Reflection; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace RevitLauncher.InstallAction 8 | { 9 | internal class Program 10 | { 11 | [DllImport("propsys.dll", SetLastError = false, ExactSpelling = true)] 12 | private static extern uint PSRegisterPropertySchema([MarshalAs(UnmanagedType.LPWStr)] string pszPath); 13 | 14 | [DllImport("propsys.dll", SetLastError = false, ExactSpelling = true)] 15 | private static extern uint PSUnregisterPropertySchema([MarshalAs(UnmanagedType.LPWStr)] string pszPath); 16 | 17 | [DllImport("propsys.dll", SetLastError = false, ExactSpelling = true)] 18 | private static extern uint PSRefreshPropertySchema(); 19 | 20 | private const string Propdesc = "RevitLauncher.propdesc"; 21 | static void Main(string[] args) 22 | { 23 | if (args.Length == 1) 24 | { 25 | string path = Directory.GetParent(Assembly.GetExecutingAssembly().Location) + $"\\{Propdesc}"; 26 | switch (args[0]) 27 | { 28 | case "-i": 29 | Console.WriteLine(PSRegisterPropertySchema(path).ToString()); 30 | Console.WriteLine(PSRefreshPropertySchema().ToString()); 31 | Register(); 32 | break; 33 | case "-u": 34 | Unregister(); 35 | Console.WriteLine(PSUnregisterPropertySchema(path)); 36 | Console.WriteLine(PSRefreshPropertySchema().ToString()); 37 | break; 38 | } 39 | } 40 | 41 | 42 | } 43 | 44 | static void Register() 45 | { 46 | var key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PropertySystem\\PropertyHandlers\\", true); 47 | key.CreateSubKey(".rte", RegistryKeyPermissionCheck.ReadWriteSubTree); 48 | key.CreateSubKey(".rvt", RegistryKeyPermissionCheck.ReadWriteSubTree); 49 | key.CreateSubKey(".rft", RegistryKeyPermissionCheck.ReadWriteSubTree); 50 | key.CreateSubKey(".rfa", RegistryKeyPermissionCheck.ReadWriteSubTree); 51 | key.OpenSubKey(".rte", true).SetValue("", "{6542121F-1D79-4A27-9471-F80277DA8535}"); 52 | key.OpenSubKey(".rvt", true).SetValue("", "{6542121F-1D79-4A27-9471-F80277DA8535}"); 53 | key.OpenSubKey(".rft", true).SetValue("", "{6542121F-1D79-4A27-9471-F80277DA8535}"); 54 | key.OpenSubKey(".rfa", true).SetValue("", "{6542121F-1D79-4A27-9471-F80277DA8535}"); 55 | key = Registry.ClassesRoot.CreateSubKey("CLSID\\{6542121F-1D79-4A27-9471-F80277DA8535}", RegistryKeyPermissionCheck.ReadWriteSubTree); 56 | key = Registry.ClassesRoot.OpenSubKey("CLSID\\{6542121F-1D79-4A27-9471-F80277DA8535}", true); 57 | key.SetValue("", "Revit Property Handler"); 58 | key.SetValue("ManualSafeSave ", 1); 59 | key.CreateSubKey("InProcServer32", RegistryKeyPermissionCheck.ReadWriteSubTree); 60 | key.OpenSubKey("InProcServer32", true).SetValue("", new FileInfo(Directory.GetParent(Assembly.GetExecutingAssembly().Location) + @"..\RevitLauncher.ShellExtension\RevitLauncher.ShellExtension.comhost.dll").FullName); 61 | key.OpenSubKey("InProcServer32", true).SetValue("ThreadingModel", "Apartment"); 62 | } 63 | 64 | static void Unregister() 65 | { 66 | var key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PropertySystem\\PropertyHandlers\\", true); 67 | key.DeleteSubKey(".rte", false); 68 | key.DeleteSubKey(".rvt", false); 69 | key.DeleteSubKey(".rft", false); 70 | key.DeleteSubKey(".rfa", false); 71 | Registry.ClassesRoot.DeleteSubKey("CLSID\\{6542121F-1D79-4A27-9471-F80277DA8535}", false); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /src/RevitLauncher.InstallAction/RevitLauncher.InstallAction.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net5.0-windows10.0.17763 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/RevitLauncher.InstallAction/RevitLauncher.propdesc: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Revit File Version 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/RevitLauncher.Setup/RevitLauncher.Setup.vdproj: -------------------------------------------------------------------------------- 1 | "DeployProject" 2 | { 3 | "VSVersion" = "3:800" 4 | "ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}" 5 | "IsWebType" = "8:FALSE" 6 | "ProjectName" = "8:RevitLauncher.Setup" 7 | "LanguageId" = "3:2052" 8 | "CodePage" = "3:936" 9 | "UILanguageId" = "3:2052" 10 | "SccProjectName" = "8:" 11 | "SccLocalPath" = "8:" 12 | "SccAuxPath" = "8:" 13 | "SccProvider" = "8:" 14 | "Hierarchy" 15 | { 16 | "Entry" 17 | { 18 | "MsmKey" = "8:_83195ED8ABF9451B8AF02D9B6287968F" 19 | "OwnerKey" = "8:_UNDEFINED" 20 | "MsmSig" = "8:_UNDEFINED" 21 | } 22 | } 23 | "Configurations" 24 | { 25 | "Debug" 26 | { 27 | "DisplayName" = "8:Debug" 28 | "IsDebugOnly" = "11:TRUE" 29 | "IsReleaseOnly" = "11:FALSE" 30 | "OutputFilename" = "8:Debug\\RevitLauncher.Setup.msi" 31 | "PackageFilesAs" = "3:2" 32 | "PackageFileSize" = "3:-2147483648" 33 | "CabType" = "3:1" 34 | "Compression" = "3:2" 35 | "SignOutput" = "11:FALSE" 36 | "CertificateFile" = "8:" 37 | "PrivateKeyFile" = "8:" 38 | "TimeStampServer" = "8:" 39 | "InstallerBootstrapper" = "3:2" 40 | "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" 41 | { 42 | "Enabled" = "11:TRUE" 43 | "PromptEnabled" = "11:TRUE" 44 | "PrerequisitesLocation" = "2:1" 45 | "Url" = "8:" 46 | "ComponentsUrl" = "8:" 47 | "Items" 48 | { 49 | "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" 50 | { 51 | "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" 52 | "ProductCode" = "8:.NETFramework,Version=v4.7.2" 53 | } 54 | } 55 | } 56 | } 57 | "Release" 58 | { 59 | "DisplayName" = "8:Release" 60 | "IsDebugOnly" = "11:FALSE" 61 | "IsReleaseOnly" = "11:TRUE" 62 | "OutputFilename" = "8:Release\\RevitLauncher.Setup.msi" 63 | "PackageFilesAs" = "3:2" 64 | "PackageFileSize" = "3:-2147483648" 65 | "CabType" = "3:1" 66 | "Compression" = "3:2" 67 | "SignOutput" = "11:FALSE" 68 | "CertificateFile" = "8:" 69 | "PrivateKeyFile" = "8:" 70 | "TimeStampServer" = "8:" 71 | "InstallerBootstrapper" = "3:2" 72 | "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" 73 | { 74 | "Enabled" = "11:TRUE" 75 | "PromptEnabled" = "11:TRUE" 76 | "PrerequisitesLocation" = "2:1" 77 | "Url" = "8:" 78 | "ComponentsUrl" = "8:" 79 | "Items" 80 | { 81 | "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" 82 | { 83 | "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" 84 | "ProductCode" = "8:.NETFramework,Version=v4.7.2" 85 | } 86 | } 87 | } 88 | } 89 | } 90 | "Deployable" 91 | { 92 | "CustomAction" 93 | { 94 | } 95 | "DefaultFeature" 96 | { 97 | "Name" = "8:DefaultFeature" 98 | "Title" = "8:" 99 | "Description" = "8:" 100 | } 101 | "ExternalPersistence" 102 | { 103 | "LaunchCondition" 104 | { 105 | "{A06ECF26-33A3-4562-8140-9B0E340D4F24}:_10366E5C8A9648B593BAA488A4DCCB9A" 106 | { 107 | "Name" = "8:.NET Framework" 108 | "Message" = "8:[VSDNETMSG]" 109 | "FrameworkVersion" = "8:.NETFramework,Version=v4.7.2" 110 | "AllowLaterVersions" = "11:FALSE" 111 | "InstallUrl" = "8:http://go.microsoft.com/fwlink/?LinkId=863262" 112 | } 113 | } 114 | } 115 | "File" 116 | { 117 | } 118 | "FileType" 119 | { 120 | } 121 | "Folder" 122 | { 123 | "{1525181F-901A-416C-8A58-119130FE478E}:_27EDFD1DFEC4458C9E2E16BB7247A819" 124 | { 125 | "Name" = "8:#1919" 126 | "AlwaysCreate" = "11:FALSE" 127 | "Condition" = "8:" 128 | "Transitive" = "11:FALSE" 129 | "Property" = "8:ProgramMenuFolder" 130 | "Folders" 131 | { 132 | } 133 | } 134 | "{1525181F-901A-416C-8A58-119130FE478E}:_7480798103A14750B6FFDA4948873562" 135 | { 136 | "Name" = "8:#1916" 137 | "AlwaysCreate" = "11:FALSE" 138 | "Condition" = "8:" 139 | "Transitive" = "11:FALSE" 140 | "Property" = "8:DesktopFolder" 141 | "Folders" 142 | { 143 | } 144 | } 145 | "{3C67513D-01DD-4637-8A68-80971EB9504F}:_85F4CCCF41AE4FADA9CEED3457093320" 146 | { 147 | "DefaultLocation" = "8:[CommonAppDataFolder]\\Autodesk\\ApplicationPlugins" 148 | "Name" = "8:#1925" 149 | "AlwaysCreate" = "11:FALSE" 150 | "Condition" = "8:" 151 | "Transitive" = "11:FALSE" 152 | "Property" = "8:TARGETDIR" 153 | "Folders" 154 | { 155 | "{9EF0B969-E518-4E46-987F-47570745A589}:_A1D96C96ACD244A0A8455E22079E7D71" 156 | { 157 | "Name" = "8:RevitLauncher.bundle" 158 | "AlwaysCreate" = "11:FALSE" 159 | "Condition" = "8:" 160 | "Transitive" = "11:FALSE" 161 | "Property" = "8:_72CB6F9F9F9B4578802BED6681DE97A0" 162 | "Folders" 163 | { 164 | "{9EF0B969-E518-4E46-987F-47570745A589}:_40E08F09D0BB482DA019B991DB411509" 165 | { 166 | "Name" = "8:Contents" 167 | "AlwaysCreate" = "11:FALSE" 168 | "Condition" = "8:" 169 | "Transitive" = "11:FALSE" 170 | "Property" = "8:_157311E0D2BD454F9C854F3CC1A0BF83" 171 | "Folders" 172 | { 173 | } 174 | } 175 | "{9EF0B969-E518-4E46-987F-47570745A589}:_47E567E7B7D9408C9ACA4C64C3D82C25" 176 | { 177 | "Name" = "8:RevitLauncher" 178 | "AlwaysCreate" = "11:FALSE" 179 | "Condition" = "8:" 180 | "Transitive" = "11:FALSE" 181 | "Property" = "8:_40E8691F9BD64999B0E358678E55BBDC" 182 | "Folders" 183 | { 184 | } 185 | } 186 | } 187 | } 188 | } 189 | } 190 | } 191 | "LaunchCondition" 192 | { 193 | } 194 | "Locator" 195 | { 196 | } 197 | "MsiBootstrapper" 198 | { 199 | "LangId" = "3:2052" 200 | "RequiresElevation" = "11:FALSE" 201 | } 202 | "Product" 203 | { 204 | "Name" = "8:Microsoft Visual Studio" 205 | "ProductName" = "8:RevitLauncher.Setup" 206 | "ProductCode" = "8:{1A71F325-30E9-4D18-BB70-10FB4CFE4157}" 207 | "PackageCode" = "8:{6084C443-0087-40AD-8B93-05BAC723261D}" 208 | "UpgradeCode" = "8:{F06E08D0-7BC5-488C-9D6D-60FB9FCF517E}" 209 | "AspNetVersion" = "8:4.0.30319.0" 210 | "RestartWWWService" = "11:FALSE" 211 | "RemovePreviousVersions" = "11:FALSE" 212 | "DetectNewerInstalledVersion" = "11:TRUE" 213 | "InstallAllUsers" = "11:FALSE" 214 | "ProductVersion" = "8:1.0.0" 215 | "Manufacturer" = "8:Default Company Name" 216 | "ARPHELPTELEPHONE" = "8:" 217 | "ARPHELPLINK" = "8:" 218 | "Title" = "8:RevitLauncher.Setup" 219 | "Subject" = "8:" 220 | "ARPCONTACT" = "8:Default Company Name" 221 | "Keywords" = "8:" 222 | "ARPCOMMENTS" = "8:" 223 | "ARPURLINFOABOUT" = "8:" 224 | "ARPPRODUCTICON" = "8:" 225 | "ARPIconIndex" = "3:0" 226 | "SearchPath" = "8:" 227 | "UseSystemSearchPath" = "11:TRUE" 228 | "TargetPlatform" = "3:1" 229 | "PreBuildEvent" = "8:" 230 | "PostBuildEvent" = "8:" 231 | "RunPostBuildEvent" = "3:0" 232 | } 233 | "Registry" 234 | { 235 | "HKLM" 236 | { 237 | "Keys" 238 | { 239 | "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_D3FDE7D65CF84834BE8C87E2D22048FD" 240 | { 241 | "Name" = "8:Software" 242 | "Condition" = "8:" 243 | "AlwaysCreate" = "11:FALSE" 244 | "DeleteAtUninstall" = "11:FALSE" 245 | "Transitive" = "11:FALSE" 246 | "Keys" 247 | { 248 | "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_D804E802930742F88044F4D5ECA98004" 249 | { 250 | "Name" = "8:[Manufacturer]" 251 | "Condition" = "8:" 252 | "AlwaysCreate" = "11:FALSE" 253 | "DeleteAtUninstall" = "11:FALSE" 254 | "Transitive" = "11:FALSE" 255 | "Keys" 256 | { 257 | } 258 | "Values" 259 | { 260 | } 261 | } 262 | } 263 | "Values" 264 | { 265 | } 266 | } 267 | } 268 | } 269 | "HKCU" 270 | { 271 | "Keys" 272 | { 273 | "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_36227E57BDEE4A429E9A6A236A542B5D" 274 | { 275 | "Name" = "8:Software" 276 | "Condition" = "8:" 277 | "AlwaysCreate" = "11:FALSE" 278 | "DeleteAtUninstall" = "11:FALSE" 279 | "Transitive" = "11:FALSE" 280 | "Keys" 281 | { 282 | "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_C12B94C5046F45A49FB85FEBEAD6D3E6" 283 | { 284 | "Name" = "8:[Manufacturer]" 285 | "Condition" = "8:" 286 | "AlwaysCreate" = "11:FALSE" 287 | "DeleteAtUninstall" = "11:FALSE" 288 | "Transitive" = "11:FALSE" 289 | "Keys" 290 | { 291 | } 292 | "Values" 293 | { 294 | } 295 | } 296 | } 297 | "Values" 298 | { 299 | } 300 | } 301 | } 302 | } 303 | "HKCR" 304 | { 305 | "Keys" 306 | { 307 | } 308 | } 309 | "HKU" 310 | { 311 | "Keys" 312 | { 313 | } 314 | } 315 | "HKPU" 316 | { 317 | "Keys" 318 | { 319 | } 320 | } 321 | } 322 | "Sequences" 323 | { 324 | } 325 | "Shortcut" 326 | { 327 | } 328 | "UserInterface" 329 | { 330 | "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_1D1C110C618241E68F262E9C29269913" 331 | { 332 | "Name" = "8:#1901" 333 | "Sequence" = "3:2" 334 | "Attributes" = "3:2" 335 | "Dialogs" 336 | { 337 | "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_2EB13C9F097D47D1BDA33E68A0161AF9" 338 | { 339 | "Sequence" = "3:100" 340 | "DisplayName" = "8:进度" 341 | "UseDynamicProperties" = "11:TRUE" 342 | "IsDependency" = "11:FALSE" 343 | "SourcePath" = "8:\\VsdAdminProgressDlg.wid" 344 | "Properties" 345 | { 346 | "BannerBitmap" 347 | { 348 | "Name" = "8:BannerBitmap" 349 | "DisplayName" = "8:#1001" 350 | "Description" = "8:#1101" 351 | "Type" = "3:8" 352 | "ContextData" = "8:Bitmap" 353 | "Attributes" = "3:4" 354 | "Setting" = "3:1" 355 | "UsePlugInResources" = "11:TRUE" 356 | } 357 | "ShowProgress" 358 | { 359 | "Name" = "8:ShowProgress" 360 | "DisplayName" = "8:#1009" 361 | "Description" = "8:#1109" 362 | "Type" = "3:5" 363 | "ContextData" = "8:1;True=1;False=0" 364 | "Attributes" = "3:0" 365 | "Setting" = "3:0" 366 | "Value" = "3:1" 367 | "DefaultValue" = "3:1" 368 | "UsePlugInResources" = "11:TRUE" 369 | } 370 | } 371 | } 372 | } 373 | } 374 | "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_4DCB455D66254F808E92331C9C711D76" 375 | { 376 | "Name" = "8:#1900" 377 | "Sequence" = "3:2" 378 | "Attributes" = "3:1" 379 | "Dialogs" 380 | { 381 | "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_5CAB84255A26445AAF1F5D9EE7EC01D4" 382 | { 383 | "Sequence" = "3:100" 384 | "DisplayName" = "8:欢迎使用" 385 | "UseDynamicProperties" = "11:TRUE" 386 | "IsDependency" = "11:FALSE" 387 | "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" 388 | "Properties" 389 | { 390 | "BannerBitmap" 391 | { 392 | "Name" = "8:BannerBitmap" 393 | "DisplayName" = "8:#1001" 394 | "Description" = "8:#1101" 395 | "Type" = "3:8" 396 | "ContextData" = "8:Bitmap" 397 | "Attributes" = "3:4" 398 | "Setting" = "3:1" 399 | "UsePlugInResources" = "11:TRUE" 400 | } 401 | "CopyrightWarning" 402 | { 403 | "Name" = "8:CopyrightWarning" 404 | "DisplayName" = "8:#1002" 405 | "Description" = "8:#1102" 406 | "Type" = "3:3" 407 | "ContextData" = "8:" 408 | "Attributes" = "3:0" 409 | "Setting" = "3:1" 410 | "Value" = "8:#1202" 411 | "DefaultValue" = "8:#1202" 412 | "UsePlugInResources" = "11:TRUE" 413 | } 414 | "Welcome" 415 | { 416 | "Name" = "8:Welcome" 417 | "DisplayName" = "8:#1003" 418 | "Description" = "8:#1103" 419 | "Type" = "3:3" 420 | "ContextData" = "8:" 421 | "Attributes" = "3:0" 422 | "Setting" = "3:1" 423 | "Value" = "8:#1203" 424 | "DefaultValue" = "8:#1203" 425 | "UsePlugInResources" = "11:TRUE" 426 | } 427 | } 428 | } 429 | "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_8193D67389204E4CAD5496F6FA717312" 430 | { 431 | "Sequence" = "3:300" 432 | "DisplayName" = "8:确认安装" 433 | "UseDynamicProperties" = "11:TRUE" 434 | "IsDependency" = "11:FALSE" 435 | "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" 436 | "Properties" 437 | { 438 | "BannerBitmap" 439 | { 440 | "Name" = "8:BannerBitmap" 441 | "DisplayName" = "8:#1001" 442 | "Description" = "8:#1101" 443 | "Type" = "3:8" 444 | "ContextData" = "8:Bitmap" 445 | "Attributes" = "3:4" 446 | "Setting" = "3:1" 447 | "UsePlugInResources" = "11:TRUE" 448 | } 449 | } 450 | } 451 | } 452 | } 453 | "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_8A5C7481B5144EB3B697934217C343D6" 454 | { 455 | "UseDynamicProperties" = "11:FALSE" 456 | "IsDependency" = "11:FALSE" 457 | "SourcePath" = "8:\\VsdUserInterface.wim" 458 | } 459 | "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_8DE69C67C6A042368F1394D6E93B0C56" 460 | { 461 | "UseDynamicProperties" = "11:FALSE" 462 | "IsDependency" = "11:FALSE" 463 | "SourcePath" = "8:\\VsdBasicDialogs.wim" 464 | } 465 | "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_98A46085F8B4437A872BC7F823CDC304" 466 | { 467 | "Name" = "8:#1902" 468 | "Sequence" = "3:1" 469 | "Attributes" = "3:3" 470 | "Dialogs" 471 | { 472 | "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_BFF2BA5F175B4DA88828D0EAC8168050" 473 | { 474 | "Sequence" = "3:100" 475 | "DisplayName" = "8:已完成" 476 | "UseDynamicProperties" = "11:TRUE" 477 | "IsDependency" = "11:FALSE" 478 | "SourcePath" = "8:\\VsdFinishedDlg.wid" 479 | "Properties" 480 | { 481 | "BannerBitmap" 482 | { 483 | "Name" = "8:BannerBitmap" 484 | "DisplayName" = "8:#1001" 485 | "Description" = "8:#1101" 486 | "Type" = "3:8" 487 | "ContextData" = "8:Bitmap" 488 | "Attributes" = "3:4" 489 | "Setting" = "3:1" 490 | "UsePlugInResources" = "11:TRUE" 491 | } 492 | "UpdateText" 493 | { 494 | "Name" = "8:UpdateText" 495 | "DisplayName" = "8:#1058" 496 | "Description" = "8:#1158" 497 | "Type" = "3:15" 498 | "ContextData" = "8:" 499 | "Attributes" = "3:0" 500 | "Setting" = "3:1" 501 | "Value" = "8:#1258" 502 | "DefaultValue" = "8:#1258" 503 | "UsePlugInResources" = "11:TRUE" 504 | } 505 | } 506 | } 507 | } 508 | } 509 | "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_B91DA525E1434996AC9EEEA418A61410" 510 | { 511 | "Name" = "8:#1902" 512 | "Sequence" = "3:2" 513 | "Attributes" = "3:3" 514 | "Dialogs" 515 | { 516 | "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_A55E99EAC95B4A28954C4313EE0D1DF0" 517 | { 518 | "Sequence" = "3:100" 519 | "DisplayName" = "8:已完成" 520 | "UseDynamicProperties" = "11:TRUE" 521 | "IsDependency" = "11:FALSE" 522 | "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" 523 | "Properties" 524 | { 525 | "BannerBitmap" 526 | { 527 | "Name" = "8:BannerBitmap" 528 | "DisplayName" = "8:#1001" 529 | "Description" = "8:#1101" 530 | "Type" = "3:8" 531 | "ContextData" = "8:Bitmap" 532 | "Attributes" = "3:4" 533 | "Setting" = "3:1" 534 | "UsePlugInResources" = "11:TRUE" 535 | } 536 | } 537 | } 538 | } 539 | } 540 | "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_CC6C2134217E456BBF7F2090997FC54A" 541 | { 542 | "Name" = "8:#1900" 543 | "Sequence" = "3:1" 544 | "Attributes" = "3:1" 545 | "Dialogs" 546 | { 547 | "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_CD50C986D7634FBDAB96EB760093840D" 548 | { 549 | "Sequence" = "3:300" 550 | "DisplayName" = "8:确认安装" 551 | "UseDynamicProperties" = "11:TRUE" 552 | "IsDependency" = "11:FALSE" 553 | "SourcePath" = "8:\\VsdConfirmDlg.wid" 554 | "Properties" 555 | { 556 | "BannerBitmap" 557 | { 558 | "Name" = "8:BannerBitmap" 559 | "DisplayName" = "8:#1001" 560 | "Description" = "8:#1101" 561 | "Type" = "3:8" 562 | "ContextData" = "8:Bitmap" 563 | "Attributes" = "3:4" 564 | "Setting" = "3:1" 565 | "UsePlugInResources" = "11:TRUE" 566 | } 567 | } 568 | } 569 | "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_DB2F13F0566C4D9B8145B82D0C14647D" 570 | { 571 | "Sequence" = "3:100" 572 | "DisplayName" = "8:欢迎使用" 573 | "UseDynamicProperties" = "11:TRUE" 574 | "IsDependency" = "11:FALSE" 575 | "SourcePath" = "8:\\VsdWelcomeDlg.wid" 576 | "Properties" 577 | { 578 | "BannerBitmap" 579 | { 580 | "Name" = "8:BannerBitmap" 581 | "DisplayName" = "8:#1001" 582 | "Description" = "8:#1101" 583 | "Type" = "3:8" 584 | "ContextData" = "8:Bitmap" 585 | "Attributes" = "3:4" 586 | "Setting" = "3:1" 587 | "UsePlugInResources" = "11:TRUE" 588 | } 589 | "CopyrightWarning" 590 | { 591 | "Name" = "8:CopyrightWarning" 592 | "DisplayName" = "8:#1002" 593 | "Description" = "8:#1102" 594 | "Type" = "3:3" 595 | "ContextData" = "8:" 596 | "Attributes" = "3:0" 597 | "Setting" = "3:1" 598 | "Value" = "8:#1202" 599 | "DefaultValue" = "8:#1202" 600 | "UsePlugInResources" = "11:TRUE" 601 | } 602 | "Welcome" 603 | { 604 | "Name" = "8:Welcome" 605 | "DisplayName" = "8:#1003" 606 | "Description" = "8:#1103" 607 | "Type" = "3:3" 608 | "ContextData" = "8:" 609 | "Attributes" = "3:0" 610 | "Setting" = "3:1" 611 | "Value" = "8:#1203" 612 | "DefaultValue" = "8:#1203" 613 | "UsePlugInResources" = "11:TRUE" 614 | } 615 | } 616 | } 617 | } 618 | } 619 | "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_D7E7981C02E2460A961D864B976F9421" 620 | { 621 | "Name" = "8:#1901" 622 | "Sequence" = "3:1" 623 | "Attributes" = "3:2" 624 | "Dialogs" 625 | { 626 | "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_5CDD3F16B84D4FDE86673194E57FCA5B" 627 | { 628 | "Sequence" = "3:100" 629 | "DisplayName" = "8:进度" 630 | "UseDynamicProperties" = "11:TRUE" 631 | "IsDependency" = "11:FALSE" 632 | "SourcePath" = "8:\\VsdProgressDlg.wid" 633 | "Properties" 634 | { 635 | "BannerBitmap" 636 | { 637 | "Name" = "8:BannerBitmap" 638 | "DisplayName" = "8:#1001" 639 | "Description" = "8:#1101" 640 | "Type" = "3:8" 641 | "ContextData" = "8:Bitmap" 642 | "Attributes" = "3:4" 643 | "Setting" = "3:1" 644 | "UsePlugInResources" = "11:TRUE" 645 | } 646 | "ShowProgress" 647 | { 648 | "Name" = "8:ShowProgress" 649 | "DisplayName" = "8:#1009" 650 | "Description" = "8:#1109" 651 | "Type" = "3:5" 652 | "ContextData" = "8:1;True=1;False=0" 653 | "Attributes" = "3:0" 654 | "Setting" = "3:0" 655 | "Value" = "3:1" 656 | "DefaultValue" = "3:1" 657 | "UsePlugInResources" = "11:TRUE" 658 | } 659 | } 660 | } 661 | } 662 | } 663 | } 664 | "MergeModule" 665 | { 666 | } 667 | "ProjectOutput" 668 | { 669 | "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_42A2812150BF42099CB2B803D5F4D51D" 670 | { 671 | "SourcePath" = "8:" 672 | "TargetName" = "8:" 673 | "Tag" = "8:" 674 | "Folder" = "8:_A1D96C96ACD244A0A8455E22079E7D71" 675 | "Condition" = "8:" 676 | "Transitive" = "11:FALSE" 677 | "Vital" = "11:TRUE" 678 | "ReadOnly" = "11:FALSE" 679 | "Hidden" = "11:FALSE" 680 | "System" = "11:FALSE" 681 | "Permanent" = "11:FALSE" 682 | "SharedLegacy" = "11:FALSE" 683 | "PackageAs" = "3:1" 684 | "Register" = "3:1" 685 | "Exclude" = "11:FALSE" 686 | "IsDependency" = "11:FALSE" 687 | "IsolateTo" = "8:" 688 | "ProjectOutputGroupRegister" = "3:1" 689 | "OutputConfiguration" = "8:" 690 | "OutputGroupCanonicalName" = "8:ContentFiles" 691 | "OutputProjectGuid" = "8:{0EAD059D-AA18-4D10-9CC9-5E9C250CA344}" 692 | "ShowKeyOutput" = "11:TRUE" 693 | "ExcludeFilters" 694 | { 695 | "ExcludeFilter" = "8:*.addin" 696 | } 697 | } 698 | "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_83195ED8ABF9451B8AF02D9B6287968F" 699 | { 700 | "SourcePath" = "8:..\\RevitLauncher.Addin\\obj\\x64\\Debug\\net452\\RevitLauncher.Addin.dll" 701 | "TargetName" = "8:" 702 | "Tag" = "8:" 703 | "Folder" = "8:_40E08F09D0BB482DA019B991DB411509" 704 | "Condition" = "8:" 705 | "Transitive" = "11:FALSE" 706 | "Vital" = "11:TRUE" 707 | "ReadOnly" = "11:FALSE" 708 | "Hidden" = "11:FALSE" 709 | "System" = "11:FALSE" 710 | "Permanent" = "11:FALSE" 711 | "SharedLegacy" = "11:FALSE" 712 | "PackageAs" = "3:1" 713 | "Register" = "3:1" 714 | "Exclude" = "11:FALSE" 715 | "IsDependency" = "11:FALSE" 716 | "IsolateTo" = "8:" 717 | "ProjectOutputGroupRegister" = "3:1" 718 | "OutputConfiguration" = "8:" 719 | "OutputGroupCanonicalName" = "8:Built" 720 | "OutputProjectGuid" = "8:{0EAD059D-AA18-4D10-9CC9-5E9C250CA344}" 721 | "ShowKeyOutput" = "11:TRUE" 722 | "ExcludeFilters" 723 | { 724 | } 725 | } 726 | "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_9F15ED28991A46DAADEECFD745573BA1" 727 | { 728 | "SourcePath" = "8:" 729 | "TargetName" = "8:" 730 | "Tag" = "8:" 731 | "Folder" = "8:_40E08F09D0BB482DA019B991DB411509" 732 | "Condition" = "8:" 733 | "Transitive" = "11:FALSE" 734 | "Vital" = "11:TRUE" 735 | "ReadOnly" = "11:FALSE" 736 | "Hidden" = "11:FALSE" 737 | "System" = "11:FALSE" 738 | "Permanent" = "11:FALSE" 739 | "SharedLegacy" = "11:FALSE" 740 | "PackageAs" = "3:1" 741 | "Register" = "3:1" 742 | "Exclude" = "11:FALSE" 743 | "IsDependency" = "11:FALSE" 744 | "IsolateTo" = "8:" 745 | "ProjectOutputGroupRegister" = "3:1" 746 | "OutputConfiguration" = "8:" 747 | "OutputGroupCanonicalName" = "8:ContentFiles" 748 | "OutputProjectGuid" = "8:{0EAD059D-AA18-4D10-9CC9-5E9C250CA344}" 749 | "ShowKeyOutput" = "11:TRUE" 750 | "ExcludeFilters" 751 | { 752 | "ExcludeFilter" = "8:*.xml" 753 | } 754 | } 755 | "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_CED7CD0B0CB5441A9A0CFCC3E5BFE7D0" 756 | { 757 | "SourcePath" = "8:" 758 | "TargetName" = "8:" 759 | "Tag" = "8:" 760 | "Folder" = "8:_47E567E7B7D9408C9ACA4C64C3D82C25" 761 | "Condition" = "8:" 762 | "Transitive" = "11:FALSE" 763 | "Vital" = "11:TRUE" 764 | "ReadOnly" = "11:FALSE" 765 | "Hidden" = "11:FALSE" 766 | "System" = "11:FALSE" 767 | "Permanent" = "11:FALSE" 768 | "SharedLegacy" = "11:FALSE" 769 | "PackageAs" = "3:1" 770 | "Register" = "3:1" 771 | "Exclude" = "11:FALSE" 772 | "IsDependency" = "11:FALSE" 773 | "IsolateTo" = "8:" 774 | "ProjectOutputGroupRegister" = "3:1" 775 | "OutputConfiguration" = "8:" 776 | "OutputGroupCanonicalName" = "8:PublishItems" 777 | "OutputProjectGuid" = "8:{04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}" 778 | "ShowKeyOutput" = "11:TRUE" 779 | "ExcludeFilters" 780 | { 781 | } 782 | } 783 | } 784 | } 785 | } 786 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/ContextMenu/CommandBase/BaseExplorerCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using RevitLauncher.ShellExtension.Interop; 5 | using RevitLauncher.ShellExtension.Interop.Shell32; 6 | 7 | namespace RevitLauncher.ShellExtension.ContextMenu.CommandBase 8 | { 9 | public abstract class BaseExplorerCommand : IExplorerCommand 10 | { 11 | public virtual Guid CanonicalName => GetType().GUID; 12 | 13 | public abstract EXPCMDFLAGS Flags { get; set; } 14 | public abstract string Icon { get; set; } 15 | 16 | public virtual IEnumerable SubCommands { get; set; } = Array.Empty(); 17 | 18 | public abstract string GetTitle(IEnumerable selectedFiles); 19 | 20 | public abstract string GetToolTip(IEnumerable selectedFiles); 21 | 22 | public abstract EXPCMDSTATE GetState(IEnumerable selectedFiles); 23 | 24 | public abstract void Invoke(IEnumerable selectedFiles); 25 | 26 | void IExplorerCommand.GetTitle(IShellItemArray itemArray, out string title) 27 | { 28 | title = GetTitle(itemArray.GetFilePaths()); 29 | } 30 | 31 | void IExplorerCommand.GetIcon(IShellItemArray itemArray, out string resourceString) 32 | { 33 | if (string.IsNullOrEmpty(Icon)) 34 | { 35 | throw new NotImplementedException(); 36 | } 37 | resourceString = Icon; 38 | } 39 | 40 | void IExplorerCommand.GetToolTip(IShellItemArray itemArray, out string tooltip) 41 | { 42 | tooltip = GetToolTip(itemArray.GetFilePaths()); 43 | } 44 | 45 | void IExplorerCommand.GetCanonicalName(out Guid guid) 46 | { 47 | guid = CanonicalName; 48 | } 49 | 50 | void IExplorerCommand.GetState(IShellItemArray itemArray, bool okToBeShow, out EXPCMDSTATE commandState) 51 | { 52 | commandState = GetState(itemArray.GetFilePaths()); 53 | } 54 | 55 | void IExplorerCommand.Invoke(IShellItemArray itemArray, object bindCtx) 56 | { 57 | Invoke(itemArray.GetFilePaths()); 58 | } 59 | 60 | void IExplorerCommand.GetFlags(out EXPCMDFLAGS flags) 61 | { 62 | flags = Flags; 63 | } 64 | 65 | HRESULT IExplorerCommand.EnumSubCommands(out IEnumExplorerCommand commandEnum) 66 | { 67 | IEnumerable subcommands = SubCommands; 68 | 69 | if (subcommands != null && subcommands.Any()) 70 | { 71 | commandEnum = new EnumExplorerCommand(subcommands); 72 | return HRESULT.S_OK; 73 | } 74 | else 75 | { 76 | commandEnum = null; 77 | return HRESULT.S_FALSE; 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/ContextMenu/CommandBase/EnumExplorerCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Runtime.InteropServices; 4 | using RevitLauncher.ShellExtension.Interop; 5 | using RevitLauncher.ShellExtension.Interop.Shell32; 6 | 7 | namespace RevitLauncher.ShellExtension.ContextMenu.CommandBase 8 | { 9 | public class EnumExplorerCommand : IEnumExplorerCommand 10 | { 11 | private readonly IExplorerCommand[] commands; 12 | private uint index; 13 | 14 | public EnumExplorerCommand(IEnumerable commands) 15 | { 16 | this.commands = commands.ToArray(); 17 | } 18 | 19 | public HRESULT Next(uint celt, [Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface, SizeParamIndex = 0)] IExplorerCommand[] pUICommand, out uint pceltFetched) 20 | { 21 | var hr = HRESULT.S_FALSE; 22 | pceltFetched = 0; 23 | if (index <= commands.Length) 24 | { 25 | uint uIndex = 0; 26 | while (uIndex < celt && index < commands.Length) 27 | { 28 | pUICommand[uIndex] = commands[index]; 29 | uIndex++; 30 | index++; 31 | } 32 | 33 | pceltFetched = uIndex; 34 | 35 | if (uIndex == celt) 36 | { 37 | hr = HRESULT.S_OK; 38 | } 39 | } 40 | return hr; 41 | } 42 | 43 | public HRESULT Skip(uint count) 44 | { 45 | index += count; 46 | if (index > commands.Length) 47 | { 48 | index = (uint)commands.Length; 49 | return HRESULT.S_FALSE; 50 | } 51 | return HRESULT.S_OK; 52 | } 53 | 54 | public void Reset() 55 | { 56 | index = 0; 57 | } 58 | 59 | public IEnumExplorerCommand Clone() 60 | { 61 | EnumExplorerCommand copy = new EnumExplorerCommand(commands); 62 | copy.index = index; 63 | return copy; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/ContextMenu/CommandBase/ShellExtensionHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using RevitLauncher.ShellExtension.Interop.Shell32; 3 | 4 | namespace RevitLauncher.ShellExtension.ContextMenu.CommandBase 5 | { 6 | public static class ShellExtensionHelper 7 | { 8 | public static IEnumerable GetFilePaths(this IShellItemArray itemArray) 9 | { 10 | var count = itemArray.GetCount(); 11 | string[] paths = new string[count]; 12 | 13 | for (int i = 0; i < count; i++) 14 | { 15 | IShellItem item = itemArray.GetItemAt((uint)i); 16 | item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var name); 17 | paths[i] = name; 18 | } 19 | 20 | return paths; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/ContextMenu/ExistProcessCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.IO.Pipes; 6 | using System.Linq; 7 | using RevitLauncher.Core.Utils; 8 | using RevitLauncher.ShellExtension.ContextMenu.CommandBase; 9 | using RevitLauncher.ShellExtension.Interop.Shell32; 10 | 11 | namespace RevitLauncher.ShellExtension.ContextMenu 12 | { 13 | public class ExistProcessCommand : BaseExplorerCommand 14 | { 15 | private readonly string file; 16 | private readonly Process process; 17 | private readonly string title; 18 | 19 | public override EXPCMDFLAGS Flags { get; set; } = EXPCMDFLAGS.ECF_DEFAULT; 20 | public override string Icon { get; set; } 21 | 22 | public ExistProcessCommand(string file, Process process) 23 | { 24 | this.file = file; 25 | this.process = process; 26 | this.title = string.IsNullOrEmpty(process.MainWindowTitle) 27 | ? Win32API.GetAllDesktopWindows().First(x => x.Pid.ToInt32() == process.Id).WindowName 28 | : process.MainWindowTitle; 29 | this.Icon = process.MainModule.FileName; 30 | } 31 | 32 | public override EXPCMDSTATE GetState(IEnumerable selectedFiles) 33 | { 34 | return EXPCMDSTATE.ECS_ENABLED; 35 | } 36 | 37 | public override string GetTitle(IEnumerable selectedFiles) 38 | { 39 | return title; 40 | } 41 | 42 | public override string GetToolTip(IEnumerable selectedFiles) 43 | { 44 | return title; 45 | } 46 | 47 | public override void Invoke(IEnumerable selectedFiles) 48 | { 49 | try 50 | { 51 | using (NamedPipeClientStream client = new NamedPipeClientStream(".", process.Id.ToString(), PipeDirection.Out)) 52 | { 53 | client.Connect(1000); 54 | StreamWriter streamWriter = new StreamWriter(client) { AutoFlush = true }; 55 | streamWriter.Write(file); 56 | client.WaitForPipeDrain(); 57 | } 58 | } 59 | catch (Exception exception) 60 | { 61 | Trace.WriteLine(exception.Message); 62 | Trace.WriteLine(exception.StackTrace); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/ContextMenu/LockingProcessCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using System.Reflection; 5 | using RevitLauncher.Core.Utils; 6 | using RevitLauncher.ShellExtension.ContextMenu.CommandBase; 7 | using RevitLauncher.ShellExtension.Interop.Shell32; 8 | 9 | namespace RevitLauncher.ShellExtension.ContextMenu 10 | { 11 | public class LockingProcessCommand : BaseExplorerCommand 12 | { 13 | private readonly Process process; 14 | private readonly string title; 15 | 16 | public override EXPCMDFLAGS Flags { get; set; } = EXPCMDFLAGS.ECF_DEFAULT; 17 | public override string Icon { get; set; } 18 | 19 | public LockingProcessCommand(Process process) 20 | { 21 | this.process = process; 22 | this.title = string.IsNullOrEmpty(process.MainWindowTitle) 23 | ? Win32API.GetAllDesktopWindows().First(x => x.Pid.ToInt32() == process.Id).WindowName 24 | : process.MainWindowTitle; 25 | this.Icon = process.MainModule.FileName; 26 | } 27 | 28 | public override EXPCMDSTATE GetState(IEnumerable selectedFiles) 29 | { 30 | return EXPCMDSTATE.ECS_ENABLED; 31 | } 32 | 33 | public override string GetTitle(IEnumerable selectedFiles) 34 | { 35 | return title; 36 | } 37 | 38 | public override string GetToolTip(IEnumerable selectedFiles) 39 | { 40 | return title; 41 | } 42 | 43 | public override void Invoke(IEnumerable selectedFiles) 44 | { 45 | ProcessUtils.SwitchToProcess(process); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/ContextMenu/NewProcessCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using RevitLauncher.Core.Utils; 3 | using RevitLauncher.ShellExtension.ContextMenu.CommandBase; 4 | using RevitLauncher.ShellExtension.Interop.Shell32; 5 | 6 | namespace RevitLauncher.ShellExtension.ContextMenu 7 | { 8 | public class NewProcessCommand : BaseExplorerCommand 9 | { 10 | private readonly string file; 11 | private readonly RevitProduct application; 12 | private string title; 13 | 14 | public override EXPCMDFLAGS Flags { get; set; } = EXPCMDFLAGS.ECF_DEFAULT; 15 | public override string Icon { get; set; } 16 | 17 | public NewProcessCommand(string file, RevitProduct application) 18 | { 19 | this.application = application; 20 | this.Icon = $"{application.InstallLocation}Revit.exe"; 21 | this.title = application.Name; 22 | this.file = file; 23 | } 24 | 25 | public override EXPCMDSTATE GetState(IEnumerable selectedFiles) 26 | { 27 | return EXPCMDSTATE.ECS_ENABLED; 28 | } 29 | 30 | public override string GetTitle(IEnumerable selectedFiles) 31 | { 32 | return title; 33 | } 34 | 35 | public override string GetToolTip(IEnumerable selectedFiles) 36 | { 37 | return title; 38 | } 39 | 40 | public override void Invoke(IEnumerable selectedFiles) 41 | { 42 | ProcessUtils.StartProcess($"{application.InstallLocation}Revit.exe", file); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/ContextMenu/RevitLauncherCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | using RevitLauncher.Core; 9 | using RevitLauncher.Core.Utils; 10 | using RevitLauncher.ShellExtension.ContextMenu.CommandBase; 11 | using RevitLauncher.ShellExtension.Interop.Shell32; 12 | 13 | namespace RevitLauncher.ShellExtension.ContextMenu 14 | { 15 | [ComVisible(true)] 16 | [Guid("5444C4A1-D5CE-4126-A734-58836F177027")] 17 | 18 | public class RevitLauncherCommand : BaseExplorerCommand 19 | { 20 | public override EXPCMDFLAGS Flags { get; set; } = EXPCMDFLAGS.ECF_HASSUBCOMMANDS; 21 | public override string Icon { get; set; } = Directory.GetParent(typeof(RevitLauncherCommand).Assembly.Location) + "\\launchericon.ico"; 22 | 23 | public override EXPCMDSTATE GetState(IEnumerable selectedFiles) 24 | { 25 | if (selectedFiles.Any(IsRevitFile) && selectedFiles.Count() == 1) 26 | { 27 | var file = selectedFiles.First(); 28 | var subCommands = new List(); 29 | var info = new RevitFileInfo(file); 30 | subCommands.Add(new StringInfoCommand($"Revit Version: {info.SavedInVersion}")); 31 | 32 | var lockCommands = GetLockingProcess(file); 33 | if (lockCommands.Any()) 34 | { 35 | subCommands.Add(new StringInfoCommand("Locking Process")); 36 | subCommands.AddRange(lockCommands); 37 | } 38 | 39 | var existCommands = GetExistProcess(file, info.SavedInVersion); 40 | if (existCommands.Any()) 41 | { 42 | subCommands.AddRange(existCommands); 43 | } 44 | 45 | var newCommands = GetNewProcess(file); 46 | if (newCommands.Any()) 47 | { 48 | subCommands.Add(new StringInfoCommand("Open In New Process")); 49 | subCommands.AddRange(newCommands); 50 | } 51 | 52 | SubCommands = subCommands; 53 | return EXPCMDSTATE.ECS_ENABLED; 54 | } 55 | 56 | return EXPCMDSTATE.ECS_HIDDEN; 57 | } 58 | 59 | public override string GetTitle(IEnumerable selectedFiles) 60 | { 61 | return $"RevitLauncher"; 62 | } 63 | private static bool IsRevitFile(string path) => Path.GetExtension(path) == ".rvt" || Path.GetExtension(path) == ".rfa" || Path.GetExtension(path) == ".rft" || Path.GetExtension(path) == ".rte"; 64 | public override string GetToolTip(IEnumerable selectedFiles) 65 | { 66 | return "RevitLauncher"; 67 | } 68 | 69 | public override void Invoke(IEnumerable selectedFiles) { } 70 | 71 | private IEnumerable GetLockingProcess(string file) 72 | { 73 | var lockingProcesses = ProcessUtils.GetLockingProcesses(file); 74 | return lockingProcesses.Select(x => new LockingProcessCommand(x)); 75 | } 76 | 77 | private IEnumerable GetExistProcess(string file, string version) 78 | { 79 | var processes = Process.GetProcesses().Where(x => x.ProcessName == ("Revit")); 80 | var subCommands = new List(); 81 | if (processes.Any()) 82 | { 83 | List matchCommand = new List(); 84 | List mismatchCommand = new List(); 85 | foreach (Process process in processes) 86 | { 87 | string title = string.IsNullOrEmpty(process.MainWindowTitle) 88 | ? Win32API.GetAllDesktopWindows().First(x => x.Pid.ToInt32() == process.Id).WindowName 89 | : process.MainWindowTitle; 90 | string[] titles = process.MainWindowTitle.Split('-'); 91 | title = title.StartsWith("Autodesk Revit") 92 | ? title.Substring(14).Trim() 93 | : title; 94 | 95 | if (titles[0].Contains(version)) 96 | { 97 | matchCommand.Add(new ExistProcessCommand(file, process)); 98 | } 99 | else 100 | { 101 | mismatchCommand.Add(new ExistProcessCommand(file, process)); 102 | } 103 | } 104 | 105 | if (matchCommand.Any()) 106 | { 107 | subCommands.Add(new StringInfoCommand("Match Vesion Process")); 108 | subCommands.AddRange(matchCommand); 109 | } 110 | 111 | if (mismatchCommand.Any()) 112 | { 113 | subCommands.Add(new StringInfoCommand("Mismatch Vesion Process")); 114 | subCommands.AddRange(mismatchCommand); 115 | } 116 | } 117 | return subCommands; 118 | } 119 | 120 | private IEnumerable GetNewProcess(string file) 121 | { 122 | return RevitProductUtility.GetAllInstalledRevitProducts().Select(x => new NewProcessCommand(file, x)); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/ContextMenu/StringInfoCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using RevitLauncher.Core; 3 | using RevitLauncher.ShellExtension.ContextMenu.CommandBase; 4 | using RevitLauncher.ShellExtension.Interop.Shell32; 5 | 6 | namespace RevitLauncher.ShellExtension.ContextMenu 7 | { 8 | public class StringInfoCommand : BaseExplorerCommand 9 | { 10 | public override EXPCMDFLAGS Flags { get; set; } = EXPCMDFLAGS.ECF_DEFAULT; 11 | public override string Icon { get; set; } 12 | 13 | private readonly string info; 14 | 15 | public StringInfoCommand(string info) 16 | { 17 | this.info = info; 18 | } 19 | 20 | public override EXPCMDSTATE GetState(IEnumerable selectedFiles) => EXPCMDSTATE.ECS_DISABLED; 21 | 22 | public override string GetTitle(IEnumerable selectedFiles) => info; 23 | 24 | public override string GetToolTip(IEnumerable selectedFiles) => info; 25 | 26 | public override void Invoke(IEnumerable selectedFiles) { } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/HRESULT.cs: -------------------------------------------------------------------------------- 1 | namespace RevitLauncher.ShellExtension.Interop 2 | { 3 | public enum HRESULT : uint 4 | { 5 | S_OK = 0, 6 | S_FALSE = 1, 7 | INPLACE_S_TRUNCATED = 0x000401A0, 8 | E_INVALIDARG = 0x80070057 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/PropSys/IInitializeWithFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace RevitLauncher.ShellExtension.Interop.PropSys 5 | { 6 | [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("b7d14566-0509-4cce-a71f-0a554233bd9b")] 7 | public interface IInitializeWithFile 8 | { 9 | void Initialize([In, MarshalAs(UnmanagedType.LPWStr)] string pszFilePath, STGM grfMode); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/PropSys/IInitializeWithStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Runtime.InteropServices.ComTypes; 4 | 5 | namespace RevitLauncher.ShellExtension.Interop.PropSys 6 | { 7 | [ComImport, Guid("b824b49d-22ac-4161-ac8a-9916e8fa3f7f"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 8 | public interface IInitializeWithStream 9 | { 10 | void Initialize(IStream pstream, STGM grfMode); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/PropSys/IPropertyStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Security; 4 | 5 | namespace RevitLauncher.ShellExtension.Interop.PropSys 6 | { 7 | [SuppressUnmanagedCodeSecurity] 8 | [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")] 9 | public interface IPropertyStore 10 | { 11 | uint GetCount(); 12 | 13 | PROPERTYKEY GetAt(uint iProp); 14 | 15 | void GetValue(in PROPERTYKEY pkey, [In, Out] PROPVARIANT pv); 16 | 17 | void SetValue(in PROPERTYKEY pkey, [In] PROPVARIANT pv); 18 | void Commit(); 19 | } 20 | } -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/PropSys/IPropertyStoreCapabilities.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace RevitLauncher.ShellExtension.Interop.PropSys 5 | { 6 | [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("c8e2d566-186e-4d49-bf41-6909ead56acc")] 7 | public interface IPropertyStoreCapabilities 8 | { 9 | [PreserveSig] 10 | HRESULT IsPropertyWritable(in PROPERTYKEY key); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/PropSys/PROPERTYKEY.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace RevitLauncher.ShellExtension.Interop.PropSys 5 | { 6 | [StructLayout(LayoutKind.Sequential, Pack = 4)] 7 | public readonly struct PROPERTYKEY : IEquatable 8 | { 9 | public Guid FmtId { get; } 10 | public int PId { get; } 11 | 12 | public PROPERTYKEY(Guid formatId, int propertyId) 13 | { 14 | FmtId = formatId; 15 | PId = propertyId; 16 | } 17 | 18 | public static bool operator ==(PROPERTYKEY propKey1, PROPERTYKEY propKey2) => propKey1.Equals(propKey2); 19 | 20 | public static bool operator !=(PROPERTYKEY propKey1, PROPERTYKEY propKey2) => !propKey1.Equals(propKey2); 21 | 22 | public override readonly int GetHashCode() => FmtId.GetHashCode() ^ PId; 23 | 24 | public readonly bool Equals(PROPERTYKEY other) => other.Equals((object)this); 25 | 26 | public override readonly bool Equals(object obj) => obj is PROPERTYKEY other && other.FmtId.Equals(FmtId) && other.PId == PId; 27 | 28 | public override readonly string ToString() => GetCanonicalName() ?? $"{FmtId:B} {PId}"; 29 | 30 | [DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true)] 31 | internal static extern HRESULT PSGetNameFromPropertyKey(in PROPERTYKEY propkey, [Out, MarshalAs(UnmanagedType.LPWStr)] out string ppszCanonicalName); 32 | 33 | public string GetCanonicalName() 34 | { 35 | var pk = this; 36 | return PSGetNameFromPropertyKey(pk, out var str) == HRESULT.S_OK ? str : null; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/PropSys/PROPVARIANT.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Security; 4 | 5 | namespace RevitLauncher.ShellExtension.Interop.PropSys 6 | { 7 | [StructLayout(LayoutKind.Explicit, Size = 16, Pack = 8)] 8 | public sealed class PROPVARIANT : IDisposable 9 | { 10 | [FieldOffset(0)] public VarEnum vt; 11 | 12 | [FieldOffset(8)] internal IntPtr _ptr; 13 | 14 | public void Dispose() 15 | { 16 | PropVariantClear(this); 17 | GC.SuppressFinalize(this); 18 | } 19 | ~PROPVARIANT() 20 | { 21 | Dispose(); 22 | } 23 | 24 | [SecurityCritical, SuppressUnmanagedCodeSecurity] 25 | [DllImport("ole32.dll", ExactSpelling = true, SetLastError = false)] 26 | public static extern HRESULT PropVariantClear([In, Out] PROPVARIANT pvar); 27 | 28 | public static HRESULT InitPropVariantFromString(string psz, [In, Out] PROPVARIANT ppropvar) 29 | { 30 | PropVariantClear(ppropvar); 31 | if (psz is null) return HRESULT.E_INVALIDARG; 32 | ppropvar._ptr = Marshal.StringToCoTaskMemUni(psz); 33 | ppropvar.vt = VarEnum.VT_LPWSTR; 34 | return HRESULT.S_OK; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/PropSys/STGM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RevitLauncher.ShellExtension.Interop.PropSys 4 | { 5 | [Flags] 6 | public enum STGM 7 | { 8 | STGM_READ = 0x00000000, 9 | 10 | STGM_WRITE = 0x00000001, 11 | 12 | STGM_READWRITE = 0x00000002, 13 | 14 | STGM_SHARE_DENY_NONE = 0x00000040, 15 | 16 | STGM_SHARE_DENY_READ = 0x00000030, 17 | 18 | STGM_SHARE_DENY_WRITE = 0x00000020, 19 | 20 | STGM_SHARE_EXCLUSIVE = 0x00000010, 21 | 22 | STGM_PRIORITY = 0x00040000, 23 | 24 | STGM_CREATE = 0x00001000, 25 | 26 | STGM_CONVERT = 0x00020000, 27 | 28 | STGM_FAILIFTHERE = 0x00000000, 29 | 30 | STGM_DIRECT = 0x00000000, 31 | 32 | STGM_TRANSACTED = 0x00010000, 33 | 34 | STGM_NOSCRATCH = 0x00100000, 35 | 36 | STGM_NOSNAPSHOT = 0x00200000, 37 | 38 | STGM_SIMPLE = 0x08000000, 39 | 40 | STGM_DIRECT_SWMR = 0x00400000, 41 | 42 | STGM_DELETEONRELEASE = 0x04000000, 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/Shell32/EXPCMDFLAGS.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RevitLauncher.ShellExtension.Interop.Shell32 4 | { 5 | /// 6 | /// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iexplorercommand-getflags 7 | /// 8 | [Flags] 9 | public enum EXPCMDFLAGS 10 | { 11 | ECF_DEFAULT = 0x000, 12 | ECF_HASSUBCOMMANDS = 0x001, 13 | ECF_HASSPLITBUTTON = 0x002, 14 | ECF_HIDELABEL = 0x004, 15 | ECF_ISSEPARATOR = 0x008, 16 | ECF_HASLUASHIELD = 0x010, 17 | ECF_SEPARATORBEFORE = 0x020, 18 | ECF_SEPARATORAFTER = 0x040, 19 | ECF_ISDROPDOWN = 0x080, 20 | ECF_TOGGLEABLE = 0x100, 21 | ECF_AUTOMENUICONS = 0x200, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/Shell32/EXPCMDSTATE.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RevitLauncher.ShellExtension.Interop.Shell32 4 | { 5 | /// 6 | /// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/ne-shobjidl_core-_expcmdstate 7 | /// 8 | [Flags] 9 | public enum EXPCMDSTATE 10 | { 11 | ECS_ENABLED = 0x00, 12 | ECS_DISABLED = 0x01, 13 | ECS_HIDDEN = 0x02, 14 | ECS_CHECKBOX = 0x04, 15 | ECS_CHECKED = 0x08, 16 | ECS_RADIOCHECK = 0x10, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/Shell32/IEnumExplorerCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace RevitLauncher.ShellExtension.Interop.Shell32 5 | { 6 | /// 7 | /// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ienumexplorercommand 8 | /// 9 | [ComImport] 10 | [Guid("a88826f8-186f-4987-aade-ea0cef8fbfe8")] 11 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 12 | public interface IEnumExplorerCommand 13 | { 14 | [PreserveSig] 15 | HRESULT Next(uint celt, [Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface, SizeParamIndex = 0)] IExplorerCommand[] pUICommand, out uint pceltFetched); 16 | 17 | [PreserveSig] 18 | HRESULT Skip(uint celt); 19 | 20 | void Reset(); 21 | 22 | [return: MarshalAs(UnmanagedType.Interface)] 23 | IEnumExplorerCommand Clone(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/Shell32/IExplorerCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace RevitLauncher.ShellExtension.Interop.Shell32 5 | { 6 | /// 7 | /// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-iexplorercommand 8 | /// 9 | [ComImport] 10 | [Guid("a08ce4d0-fa25-44ab-b57c-c7b1c323e0b9")] 11 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 12 | public interface IExplorerCommand 13 | { 14 | void GetTitle(IShellItemArray psiItemArray, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName); 15 | 16 | void GetIcon(IShellItemArray psiItemArray, [MarshalAs(UnmanagedType.LPWStr)] out string ppszIcon); 17 | 18 | void GetToolTip(IShellItemArray psiItemArray, [MarshalAs(UnmanagedType.LPWStr)] out string ppszInfotip); 19 | 20 | void GetCanonicalName(out Guid pguidCommandName); 21 | 22 | void GetState(IShellItemArray psiItemArray, [MarshalAs(UnmanagedType.Bool)] bool fOkToBeSlow, out EXPCMDSTATE pCmdState); 23 | 24 | void Invoke(IShellItemArray psiItemArray, [MarshalAs(UnmanagedType.Interface)] object pbc); 25 | 26 | void GetFlags(out EXPCMDFLAGS pFlags); 27 | 28 | [PreserveSig] 29 | HRESULT EnumSubCommands(out IEnumExplorerCommand ppEnum); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/Shell32/IShellItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace RevitLauncher.ShellExtension.Interop.Shell32 5 | { 6 | /// 7 | /// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ishellitem 8 | /// 9 | [ComImport] 10 | [Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")] 11 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 12 | public interface IShellItem 13 | { 14 | [return: MarshalAs(UnmanagedType.Interface)] 15 | object BindToHandler([In, MarshalAs(UnmanagedType.Interface)] object pbc, [In] ref Guid bhid, [In] ref Guid riid); 16 | 17 | void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); 18 | 19 | void GetDisplayName([In] SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName); 20 | 21 | void GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs); 22 | 23 | void Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/Shell32/IShellItemArray.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace RevitLauncher.ShellExtension.Interop.Shell32 5 | { 6 | /// 7 | /// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ishellitemarray 8 | /// 9 | [ComImport] 10 | [Guid("b63ea76d-1f85-456f-a19c-48159efa858b")] 11 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 12 | public interface IShellItemArray 13 | { 14 | [return: MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)] 15 | object BindToHandler(object pbc, in Guid rbhid, in Guid riid); 16 | 17 | [return: MarshalAs(UnmanagedType.Interface, IidParameterIndex = 1)] 18 | object GetPropertyStore(uint flags, in Guid riid); 19 | 20 | [return: MarshalAs(UnmanagedType.Interface, IidParameterIndex = 1)] 21 | object GetPropertyDescriptionList(in uint keyType, in Guid riid); 22 | 23 | uint GetAttributes(uint dwAttribFlags, uint sfgaoMask); 24 | 25 | uint GetCount(); 26 | 27 | IShellItem GetItemAt(uint dwIndex); 28 | 29 | object EnumItems(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/Interop/Shell32/SIGDN.cs: -------------------------------------------------------------------------------- 1 | namespace RevitLauncher.ShellExtension.Interop.Shell32 2 | { 3 | /// 4 | /// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/ne-shobjidl_core-sigdn 5 | /// 6 | public enum SIGDN : uint 7 | { 8 | SIGDN_NORMALDISPLAY = 0, 9 | SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, 10 | SIGDN_PARENTRELATIVEPARSING = 0x80018001, 11 | SIGDN_PARENTRELATIVEEDITING = 0x80031001, 12 | SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, 13 | SIGDN_FILESYSPATH = 0x80058000, 14 | SIGDN_URL = 0x80068000, 15 | SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001, 16 | SIGDN_PARENTRELATIVE = 0x80080001, 17 | SIGDN_PARENTRELATIVEFORUI = 0x80094001, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/PropertyHandler/IStreamExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Runtime.InteropServices; 3 | using System.Runtime.InteropServices.ComTypes; 4 | 5 | namespace RevitLauncher.ShellExtension.PropertyHandler 6 | { 7 | public static class IStreamExtensions 8 | { 9 | private const int bufferSize = 8192; 10 | public static MemoryStream ReadToMemoryStream(this IStream comStream) 11 | { 12 | var memoryStream = new MemoryStream(); 13 | 14 | var amtRead = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(int))); 15 | Marshal.WriteInt32(amtRead, bufferSize); 16 | var buffer = new byte[bufferSize]; 17 | while (Marshal.ReadInt32(amtRead) > 0) 18 | { 19 | comStream.Read(buffer, buffer.Length, amtRead); 20 | memoryStream.Write(buffer, 0, Marshal.ReadInt32(amtRead)); 21 | } 22 | memoryStream.Position = 0; 23 | 24 | return memoryStream; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/PropertyHandler/RevitPropertyStore.cs: -------------------------------------------------------------------------------- 1 | using OpenMcdf; 2 | using RevitLauncher.Core; 3 | using RevitLauncher.ShellExtension.Interop; 4 | using RevitLauncher.ShellExtension.Interop.PropSys; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Diagnostics; 8 | using System.IO; 9 | using System.Linq; 10 | using System.Runtime.InteropServices; 11 | using System.Runtime.InteropServices.ComTypes; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | 15 | namespace RevitLauncher.ShellExtension.PropertyHandler 16 | { 17 | [ComVisible(true)] 18 | [Guid("6542121F-1D79-4A27-9471-F80277DA8535")] 19 | public class RevitPropertyStore : IPropertyStore, IInitializeWithFile, IPropertyStoreCapabilities 20 | { 21 | private static Guid VersionPropdescId = new("{AD36148C-0DA3-4145-ADAD-0DDCCF79D4AE}"); 22 | private static PROPERTYKEY rKey = new PROPERTYKEY(VersionPropdescId, 88); 23 | private string version = "unknown"; 24 | 25 | public void Initialize([In, MarshalAs(UnmanagedType.LPWStr)] string pszFilePath, STGM grfMode) 26 | { 27 | var info = new RevitFileInfo(pszFilePath); 28 | version = info.SavedInVersion; 29 | } 30 | 31 | public HRESULT IsPropertyWritable(in PROPERTYKEY key) 32 | { 33 | if (key == rKey) 34 | { 35 | return HRESULT.S_FALSE; 36 | } 37 | return HRESULT.S_OK; 38 | } 39 | 40 | public uint GetCount() 41 | { 42 | return 1; 43 | } 44 | 45 | public PROPERTYKEY GetAt(uint iProp) 46 | { 47 | return rKey; 48 | } 49 | 50 | public void GetValue(in PROPERTYKEY pkey, PROPVARIANT pv) 51 | { 52 | if (pkey == rKey) 53 | { 54 | PROPVARIANT.InitPropVariantFromString(version, pv); 55 | } 56 | } 57 | 58 | public void SetValue(in PROPERTYKEY pkey, PROPVARIANT pv) { } 59 | 60 | public void Commit() { } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/RevitLauncher.ShellExtension.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net5.0-windows10.0.17763 4 | win-x64;win-x86 5 | CA1714 6 | x64;x86 7 | true 8 | true 9 | False 10 | 11 | 12 | 13 | 14 | 15 | 16 | Always 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/RevitLauncher.ShellExtension/launchericon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/src/RevitLauncher.ShellExtension/launchericon.ico -------------------------------------------------------------------------------- /src/RevitLauncher.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32825.248 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitLauncher", "RevitLauncher\RevitLauncher.csproj", "{04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitLauncher.Addin", "RevitLauncher.Addin\RevitLauncher.Addin.csproj", "{0EAD059D-AA18-4D10-9CC9-5E9C250CA344}" 9 | EndProject 10 | Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "RevitLauncher.Setup", "RevitLauncher.Setup\RevitLauncher.Setup.vdproj", "{53D85D63-B303-4710-91D5-46ED9A4ED8C6}" 11 | EndProject 12 | Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "RevitLaucher.Package", "RevitLaucher.Package\RevitLaucher.Package.wapproj", "{48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitLauncher.ShellExtension", "RevitLauncher.ShellExtension\RevitLauncher.ShellExtension.csproj", "{9AF12E7E-F7EF-4199-B080-764775A6B2ED}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitLauncher.Core", "RevitLauncher.Core\RevitLauncher.Core.csproj", "{2828F368-9EB5-407F-B5AC-FA2B924BBDE0}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitLauncher.InstallAction", "RevitLauncher.InstallAction\RevitLauncher.InstallAction.csproj", "{07E62775-CBDB-4EDE-874F-5AD5249A2D62}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Debug|ARM = Debug|ARM 24 | Debug|ARM64 = Debug|ARM64 25 | Debug|x64 = Debug|x64 26 | Debug|x86 = Debug|x86 27 | Release|Any CPU = Release|Any CPU 28 | Release|ARM = Release|ARM 29 | Release|ARM64 = Release|ARM64 30 | Release|x64 = Release|x64 31 | Release|x86 = Release|x86 32 | EndGlobalSection 33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 34 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Debug|ARM.ActiveCfg = Debug|Any CPU 37 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Debug|ARM.Build.0 = Debug|Any CPU 38 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Debug|ARM64.ActiveCfg = Debug|Any CPU 39 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Debug|ARM64.Build.0 = Debug|Any CPU 40 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Debug|x64.ActiveCfg = Debug|x64 41 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Debug|x64.Build.0 = Debug|x64 42 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Debug|x86.ActiveCfg = Debug|Any CPU 43 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Debug|x86.Build.0 = Debug|Any CPU 44 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Release|ARM.ActiveCfg = Release|Any CPU 47 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Release|ARM.Build.0 = Release|Any CPU 48 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Release|ARM64.ActiveCfg = Release|Any CPU 49 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Release|ARM64.Build.0 = Release|Any CPU 50 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Release|x64.ActiveCfg = Release|x64 51 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Release|x64.Build.0 = Release|x64 52 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Release|x86.ActiveCfg = Release|Any CPU 53 | {04BA99D4-5BE1-4F57-A9BC-9DEDB708E168}.Release|x86.Build.0 = Release|Any CPU 54 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Debug|ARM.ActiveCfg = Debug|Any CPU 57 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Debug|ARM.Build.0 = Debug|Any CPU 58 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Debug|ARM64.ActiveCfg = Debug|Any CPU 59 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Debug|ARM64.Build.0 = Debug|Any CPU 60 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Debug|x64.ActiveCfg = Debug|x64 61 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Debug|x64.Build.0 = Debug|x64 62 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Debug|x86.ActiveCfg = Debug|Any CPU 63 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Debug|x86.Build.0 = Debug|Any CPU 64 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Release|Any CPU.ActiveCfg = Release|Any CPU 65 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Release|Any CPU.Build.0 = Release|Any CPU 66 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Release|ARM.ActiveCfg = Release|Any CPU 67 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Release|ARM.Build.0 = Release|Any CPU 68 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Release|ARM64.ActiveCfg = Release|Any CPU 69 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Release|ARM64.Build.0 = Release|Any CPU 70 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Release|x64.ActiveCfg = Release|x64 71 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Release|x64.Build.0 = Release|x64 72 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Release|x86.ActiveCfg = Release|Any CPU 73 | {0EAD059D-AA18-4D10-9CC9-5E9C250CA344}.Release|x86.Build.0 = Release|Any CPU 74 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Debug|Any CPU.ActiveCfg = Debug 75 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Debug|ARM.ActiveCfg = Debug 76 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Debug|ARM.Build.0 = Debug 77 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Debug|ARM64.ActiveCfg = Debug 78 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Debug|ARM64.Build.0 = Debug 79 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Debug|x64.ActiveCfg = Debug 80 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Debug|x64.Build.0 = Debug 81 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Debug|x86.ActiveCfg = Debug 82 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Debug|x86.Build.0 = Debug 83 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Release|Any CPU.ActiveCfg = Release 84 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Release|ARM.ActiveCfg = Release 85 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Release|ARM.Build.0 = Release 86 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Release|ARM64.ActiveCfg = Release 87 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Release|ARM64.Build.0 = Release 88 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Release|x64.ActiveCfg = Release 89 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Release|x64.Build.0 = Release 90 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Release|x86.ActiveCfg = Release 91 | {53D85D63-B303-4710-91D5-46ED9A4ED8C6}.Release|x86.Build.0 = Release 92 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 93 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|Any CPU.Build.0 = Debug|Any CPU 94 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 95 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|ARM.ActiveCfg = Debug|ARM 96 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|ARM.Build.0 = Debug|ARM 97 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|ARM.Deploy.0 = Debug|ARM 98 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|ARM64.ActiveCfg = Debug|ARM64 99 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|ARM64.Build.0 = Debug|ARM64 100 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|ARM64.Deploy.0 = Debug|ARM64 101 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|x64.ActiveCfg = Debug|x64 102 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|x64.Build.0 = Debug|x64 103 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|x64.Deploy.0 = Debug|x64 104 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|x86.ActiveCfg = Debug|x86 105 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|x86.Build.0 = Debug|x86 106 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Debug|x86.Deploy.0 = Debug|x86 107 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|Any CPU.ActiveCfg = Release|Any CPU 108 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|Any CPU.Build.0 = Release|Any CPU 109 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|Any CPU.Deploy.0 = Release|Any CPU 110 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|ARM.ActiveCfg = Release|ARM 111 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|ARM.Build.0 = Release|ARM 112 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|ARM.Deploy.0 = Release|ARM 113 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|ARM64.ActiveCfg = Release|ARM64 114 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|ARM64.Build.0 = Release|ARM64 115 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|ARM64.Deploy.0 = Release|ARM64 116 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|x64.ActiveCfg = Release|x64 117 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|x64.Build.0 = Release|x64 118 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|x64.Deploy.0 = Release|x64 119 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|x86.ActiveCfg = Release|x86 120 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|x86.Build.0 = Release|x86 121 | {48FEDDB8-EB63-41B2-9833-9ABCF5BA434C}.Release|x86.Deploy.0 = Release|x86 122 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Debug|Any CPU.ActiveCfg = Debug|x64 123 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Debug|Any CPU.Build.0 = Debug|x64 124 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Debug|ARM.ActiveCfg = Debug|Any CPU 125 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Debug|ARM.Build.0 = Debug|Any CPU 126 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Debug|ARM64.ActiveCfg = Debug|Any CPU 127 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Debug|ARM64.Build.0 = Debug|Any CPU 128 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Debug|x64.ActiveCfg = Debug|x64 129 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Debug|x64.Build.0 = Debug|x64 130 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Debug|x86.ActiveCfg = Debug|Any CPU 131 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Debug|x86.Build.0 = Debug|Any CPU 132 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Release|Any CPU.ActiveCfg = Release|Any CPU 133 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Release|Any CPU.Build.0 = Release|Any CPU 134 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Release|ARM.ActiveCfg = Release|Any CPU 135 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Release|ARM.Build.0 = Release|Any CPU 136 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Release|ARM64.ActiveCfg = Release|Any CPU 137 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Release|ARM64.Build.0 = Release|Any CPU 138 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Release|x64.ActiveCfg = Release|Any CPU 139 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Release|x64.Build.0 = Release|Any CPU 140 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Release|x86.ActiveCfg = Release|Any CPU 141 | {9AF12E7E-F7EF-4199-B080-764775A6B2ED}.Release|x86.Build.0 = Release|Any CPU 142 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 143 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Debug|Any CPU.Build.0 = Debug|Any CPU 144 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Debug|ARM.ActiveCfg = Debug|Any CPU 145 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Debug|ARM.Build.0 = Debug|Any CPU 146 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Debug|ARM64.ActiveCfg = Debug|Any CPU 147 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Debug|ARM64.Build.0 = Debug|Any CPU 148 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Debug|x64.ActiveCfg = Debug|Any CPU 149 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Debug|x64.Build.0 = Debug|Any CPU 150 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Debug|x86.ActiveCfg = Debug|Any CPU 151 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Debug|x86.Build.0 = Debug|Any CPU 152 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Release|Any CPU.ActiveCfg = Release|Any CPU 153 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Release|Any CPU.Build.0 = Release|Any CPU 154 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Release|ARM.ActiveCfg = Release|Any CPU 155 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Release|ARM.Build.0 = Release|Any CPU 156 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Release|ARM64.ActiveCfg = Release|Any CPU 157 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Release|ARM64.Build.0 = Release|Any CPU 158 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Release|x64.ActiveCfg = Release|Any CPU 159 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Release|x64.Build.0 = Release|Any CPU 160 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Release|x86.ActiveCfg = Release|Any CPU 161 | {2828F368-9EB5-407F-B5AC-FA2B924BBDE0}.Release|x86.Build.0 = Release|Any CPU 162 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 163 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Debug|Any CPU.Build.0 = Debug|Any CPU 164 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Debug|ARM.ActiveCfg = Debug|Any CPU 165 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Debug|ARM.Build.0 = Debug|Any CPU 166 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Debug|ARM64.ActiveCfg = Debug|Any CPU 167 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Debug|ARM64.Build.0 = Debug|Any CPU 168 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Debug|x64.ActiveCfg = Debug|Any CPU 169 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Debug|x64.Build.0 = Debug|Any CPU 170 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Debug|x86.ActiveCfg = Debug|Any CPU 171 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Debug|x86.Build.0 = Debug|Any CPU 172 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Release|Any CPU.ActiveCfg = Release|Any CPU 173 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Release|Any CPU.Build.0 = Release|Any CPU 174 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Release|ARM.ActiveCfg = Release|Any CPU 175 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Release|ARM.Build.0 = Release|Any CPU 176 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Release|ARM64.ActiveCfg = Release|Any CPU 177 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Release|ARM64.Build.0 = Release|Any CPU 178 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Release|x64.ActiveCfg = Release|Any CPU 179 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Release|x64.Build.0 = Release|Any CPU 180 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Release|x86.ActiveCfg = Release|Any CPU 181 | {07E62775-CBDB-4EDE-874F-5AD5249A2D62}.Release|x86.Build.0 = Release|Any CPU 182 | EndGlobalSection 183 | GlobalSection(SolutionProperties) = preSolution 184 | HideSolutionNode = FALSE 185 | EndGlobalSection 186 | GlobalSection(ExtensibilityGlobals) = postSolution 187 | SolutionGuid = {90A18FF3-08F7-45D6-9CDB-C1F89B0FB4A1} 188 | EndGlobalSection 189 | EndGlobal 190 | -------------------------------------------------------------------------------- /src/RevitLauncher/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace RevitLauncher 8 | { 9 | public class Program 10 | { 11 | public static void Main(string[] args) 12 | { 13 | 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/RevitLauncher/RevitLauncher.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | true 6 | net462 7 | AnyCPU;x64 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Always 17 | 18 | 19 | 20 | 21 | 22 | Never 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/RevitLauncher/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 58 | 59 | 60 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/RevitLauncher/launchericon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/src/RevitLauncher/launchericon.ico -------------------------------------------------------------------------------- /src/RevitLauncher/launchericon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuangkh/RevitLauncher/013ea4684767225774264bbacc1eb6452405221b/src/RevitLauncher/launchericon.png --------------------------------------------------------------------------------