Repository: Activision/USDShellExtension Branch: main Commit: b7655b9436f2 Files: 132 Total size: 424.5 KB Directory structure: gitextract_0s2b2fo_/ ├── .gitignore ├── BUILDING.md ├── CONTRIBUTING.txt ├── LICENSE.txt ├── NOTICE.txt ├── README.md ├── UsdPreviewHandlerPython/ │ ├── Module.cpp │ ├── Module.h │ ├── StageViewWnd.cpp │ ├── StageViewWnd.h │ ├── UsdPreviewHandlerEvent.h │ ├── UsdPreviewHandlerMgr.cpp │ ├── UsdPreviewHandlerMgr.h │ ├── UsdPreviewHandlerPython.rc │ ├── UsdPreviewHandlerPython.vcxproj │ ├── UsdPreviewHandlerPython.vcxproj.filters │ ├── pyUsdPreviewHandler.cpp │ ├── resource.h │ ├── stdafx.cpp │ └── stdafx.h ├── UsdPreviewHandlerServer/ │ ├── Module.cpp │ ├── Module.h │ ├── UsdPreviewHandlerImpl.cpp │ ├── UsdPreviewHandlerImpl.h │ ├── UsdPreviewHandlerImpl.rgs │ ├── UsdPreviewHandlerPython.py │ ├── UsdPreviewLocalServer.idl │ ├── UsdPreviewLocalServer.rc │ ├── UsdPreviewLocalServer.vcxproj │ ├── UsdPreviewLocalServer.vcxproj.filters │ ├── UsdPreviewLocalServerModule.rgs │ ├── UsdPreviewThread.cpp │ ├── UsdPreviewThread.h │ ├── resource.h │ ├── stdafx.cpp │ └── stdafx.h ├── UsdPythonToolsServer/ │ ├── Module.cpp │ ├── Module.h │ ├── UsdPythonToolsImpl.cpp │ ├── UsdPythonToolsImpl.h │ ├── UsdPythonToolsImpl.rgs │ ├── UsdPythonToolsLocalServer.idl │ ├── UsdPythonToolsLocalServer.rc │ ├── UsdPythonToolsLocalServer.vcxproj │ ├── UsdPythonToolsLocalServer.vcxproj.filters │ ├── UsdPythonToolsLocalServerModule.rgs │ ├── UsdThumbnail.py │ ├── resource.h │ ├── stdafx.cpp │ └── stdafx.h ├── UsdSdkToolsServer/ │ ├── Module.cpp │ ├── Module.h │ ├── UsdSdkToolsImpl.cpp │ ├── UsdSdkToolsImpl.h │ ├── UsdSdkToolsImpl.rgs │ ├── UsdSdkToolsLocalServer.idl │ ├── UsdSdkToolsLocalServer.rc │ ├── UsdSdkToolsLocalServer.vcxproj │ ├── UsdSdkToolsLocalServer.vcxproj.filters │ ├── UsdSdkToolsLocalServerModule.rgs │ ├── resource.h │ ├── stdafx.cpp │ └── stdafx.h ├── UsdShellExtension/ │ ├── ArResolverShellExtension.cpp │ ├── ArResolverShellExtension.h │ ├── Module.cpp │ ├── Module.h │ ├── ShellExecute.cpp │ ├── ShellExt.def │ ├── ShellExt.idl │ ├── ShellExt.rc │ ├── ShellExtModule.rgs │ ├── ShellPreviewHandlerImpl.cpp │ ├── ShellPreviewHandlerImpl.h │ ├── ShellPreviewHandlerImpl.rgs │ ├── ShellPropertyStoreImpl.cpp │ ├── ShellPropertyStoreImpl.h │ ├── ShellPropertyStoreImpl.rgs │ ├── ShellThumbnailProviderImpl.cpp │ ├── ShellThumbnailProviderImpl.h │ ├── ShellThumbnailProviderImpl.rgs │ ├── UWPProgressBar.cpp │ ├── UWPProgressBar.h │ ├── UsdLoadScreenDlg.cpp │ ├── UsdLoadScreenDlg.h │ ├── UsdMetadata.cpp │ ├── UsdMetadata.h │ ├── UsdPropertyKeys.h │ ├── UsdPropertyKeys.propdesc │ ├── UsdShellExtension-monolithic.manifest │ ├── UsdShellExtension-shared.manifest │ ├── UsdShellExtension.ini │ ├── UsdShellExtension.vcxproj │ ├── UsdShellExtension.vcxproj.filters │ ├── plugInfo.json │ ├── register.bat │ ├── resource.h │ ├── stdafx.cpp │ ├── stdafx.h │ └── unregister.bat ├── UsdShellExtension.sln ├── UsdShellExtensionInstaller/ │ ├── CmdLineArgs.nsh │ ├── RestartManager.nsh │ ├── ShellLinkSetRunAs.nsh │ ├── UsdConfigPage.nsh │ ├── UsdConfigUtils.nsh │ ├── UsdPathPage.nsh │ ├── UsdShellExtensionInstaller.nsi │ ├── UsdShellExtensionInstaller.vcxproj │ └── UsdShellExtensionInstaller.vcxproj.filters ├── atviversion.h ├── atviversion.props ├── atviversion.rc2 ├── boost.props ├── docs/ │ ├── DEPLOYMENT.md │ ├── DESIGN.md │ ├── FEATURES.md │ └── INSTALLING.md ├── nsis.props ├── python.props ├── shared/ │ ├── EventViewerLog.h │ ├── EventViewerMessages.mc │ ├── EventViewerMessages.vcxproj │ ├── EventViewerMessages.vcxproj.filters │ ├── PythonUtil.h │ ├── emb.cpp │ ├── emb.h │ ├── environment.cpp │ └── environment.h ├── usd-monolithic.props ├── usd-shared.props └── usd.props ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .vs/ bin/ build/ *.aps *.user *_h.h *_i.c *_p.c dlldata.c EventViewerMessages.h EventViewerMessages.rc MSG00409.bin ================================================ FILE: BUILDING.md ================================================ ACTIVISION USD SHELL EXTENSION ============================== ## Dependencies * Boost * Python (2.7, 3.6, 3.7) * USD SDK * Windows 10 SDK * Visual Studio 2017+ * ATL * Python C++ Tools #### Boost `boost.props` Boost is required for Boost.Python. It is used to build a python extension module. The boost compilation must match the version of MSVC and Python used by the shell extension. #### Python `python.props` Currently only Python 2.7, 3.6, and 3.7 are supported. The USD SDK does not currently support Python 3.8+ on Windows. #### USD SDK `usd.props` The shell extension requires a bare-bones monolithic build of the USD SDK. The monolithic build is a single DLL which makes it easier to isolate it into its own activation context in Windows Explorer. The shell extension is currently set up to build against a build of USD that does not use Python. The shell extension is injected into Windows Explorer which is also the process that runs the Windows Desktop. We want to keep as much out of that process as we can. ``` python.exe build_scripts\build_usd.py d:\USD-monolithic-bare --build-monolithic --no-tests --no-examples --no-tutorials --no-tools --no-docs --no-python --no-imaging --no-ptex --no-openvdb --no-usdview --no-embree --no-prman --no-openimageio --no-opencolorio --no-alembic --no-hdf5 --no-draco --no-materialx ``` #### Windows 10 SDK Windows 10 SDK 10.0.14393.0 or higher is required to build the shell extension. This requirement is only due to High DPI support. It would be possible to remove High DPI support and compile the shell extension for Windows 7. #### Visual Studio Visual Studio is the only supported build tool at this time. The following Visual Studio components are required: - C++ ATL - Python Language Support ## Simple Build The simplest way to build the shell extension is to build two flavors of the USD SDK. The first being a bare-bones version of the SDK that is used by Windows Explorer. The second is a full version used by everything else. Bare-Bones USD SDK ``` python.exe build_scripts\build_usd.py d:\USD-monolithic-bare --build-monolithic --no-tests --no-examples --no-tutorials --no-tools --no-docs --no-python --no-imaging --no-ptex --no-openvdb --no-usdview --no-embree --no-prman --no-openimageio --no-opencolorio --no-alembic --no-hdf5 --no-draco --no-materialx ``` Full USD SDK ``` python.exe build_scripts\build_usd.py d:\USD-shared-full [--embree] [--materialx] ``` Then update the property sheets to point to these builds. `usd.props` Point this property sheet to the bare-bones USD SDK. `boost.props` Point this property sheet to the full USD SDK's version of boost. `UsdShellExtension.ini` Point the paths in this configuration file to the full USD SDK. ``` [USD] PATH=D:\USD-shared-full\bin\;D:\USD-shared-full\lib\ PYTHONPATH=D:\USD-shared-full\lib\python PXR_PLUGINPATH_NAME= ``` ================================================ FILE: CONTRIBUTING.txt ================================================ Thank you for your interest in USD Shell Extension. Before contributing code to the project, please sign a Contributor License Agreement (CLA). At the root of the repository you can find the two possible CLAs: Activision-Corporate-CLA-USD-Shell-Extension.pdf: for corporate contributors Activision-Individual-CLA-USD-Shell-Extension.pdf: for individual contributors Please send your signed CLAs to LegalAffairs@activision.com, making sure to include your github username in the email. Please wait for our confirmation that you're approved for contributions, after which you can submit pull requests. ================================================ FILE: LICENSE.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS ============================================================ emb.cpp, emb.h ============================================================ Copyright (C) 2011 Mateusz Loskot Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Blog article: http://mateusz.loskot.net/?p=2819 Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================ Universal Scene Description ============================================================ Universal Scene Description Copyright 2016 Pixar All rights reserved. This product includes software developed at: Pixar (http://www.pixar.com/). Modified Apache 2.0 License TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor and its affiliates, except as required to comply with Section 4(c) of the License and to reproduce the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ================================================ FILE: NOTICE.txt ================================================ Activision USD Shell Extension Copyright 2021 Activision Publishing, Inc. All rights reserved. This product includes software developed at Activision Publishing, Inc. ================================================ FILE: README.md ================================================ Activision USD Shell Extension ============================== A Windows Shell Extension for the Pixar USD file format. **Windows Explorer Features** * Hydra Realtime Preview * Thumbnails * Context Menus * Metadata Properties **Windows Search Features** * Metadata Search More details available [here](./docs/FEATURES.md). Goals ----- There are several goals that this shell extension tries to adhere to and takes extra precautions to meet. * **Performance** It is important that the shell extension not stall Windows Explorer. * **Stability** Instability in the shell extension will take down Window Explorer and/or the entire desktop. The mitigation strategy is to run the majority of the shell extension asynchronously out of the Windows Explorer process. Dependencies ------------ The following dependencies are required: * [Microsoft Visual Studio (2017 or newer)](https://visualstudio.microsoft.com/vs/) * [Universal Scene Description (USD)](https://graphics.pixar.com/usd/docs/index.html) * [Python (2.7, 3.6, 3.7)](https://www.python.org/) Required Microsoft Visual Studio Components: * Desktop development with C++ * C++ ATL * Windows 10 SDK * Windows Universal C Runtime * Python language support ================================================ FILE: UsdPreviewHandlerPython/Module.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "Module.h" HMODULE g_hInstance; BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { UNREFERENCED_PARAMETER( lpReserved ); switch ( ul_reason_for_call ) { case DLL_PROCESS_ATTACH: g_hInstance = hModule; break; } return TRUE; } ================================================ FILE: UsdPreviewHandlerPython/Module.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once extern HMODULE g_hInstance; ================================================ FILE: UsdPreviewHandlerPython/StageViewWnd.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "StageViewWnd.h" #include "Module.h" #include "resource.h" void CStageViewWnd::Init( HWND hWndToSubclass ) { if ( m_hWnd ) Term(); SubclassWindow( hWndToSubclass ); } void CStageViewWnd::Term() { UnsubclassWindow(); } ================================================ FILE: UsdPreviewHandlerPython/StageViewWnd.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "resource.h" class CStageViewWnd : public CWindowImpl { public: void Init( HWND hWndToSubclass ); void Term(); private: BEGIN_MSG_MAP(CStageViewWnd) END_MSG_MAP() }; ================================================ FILE: UsdPreviewHandlerPython/UsdPreviewHandlerEvent.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once enum eUsdPreviewEvent { USDPREVIEWEVENT_INVALID, USDPREVIEWEVENT_QUIT, USDPREVIEWEVENT_RESIZE, USDPREVIEWEVENT_RESIZERECT, USDPREVIEWEVENT_SETWINDOW, }; struct UsdPreviewEventData { eUsdPreviewEvent event; intptr_t data1; intptr_t data2; }; typedef void (*FNUSDPREVIEWPUSHEVENT)(eUsdPreviewEvent event, intptr_t data1, intptr_t data2); typedef HWND (*FNUSDPREVIEWGETPREVIEWWINDOW)(); ================================================ FILE: UsdPreviewHandlerPython/UsdPreviewHandlerMgr.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "UsdPreviewHandlerMgr.h" #include "UsdPreviewHandlerEvent.h" CUsdPreviewHandlerMgr CUsdPreviewHandlerMgr::s_Singleton; UsdPreviewEventData CUsdPreviewHandlerMgr::PeekEvent() { UsdPreviewEventData eventData = {}; std::lock_guard guard(m_EventQueueMutex); if (m_EventQueue.empty()) return eventData; eventData = m_EventQueue.front(); m_EventQueue.pop(); return eventData; } void CUsdPreviewHandlerMgr::LoadComplete() { m_bLoadComplete = true; if( m_bQuit == false ) SetParent( m_hWndParent, m_hWndChild, m_hWndStageView ); } void CUsdPreviewHandlerMgr::PostEvent(eUsdPreviewEvent event, intptr_t data1, intptr_t data2) { switch (event) { case USDPREVIEWEVENT_RESIZE: OnResize(static_cast(data1), static_cast(data2)); return; case USDPREVIEWEVENT_RESIZERECT: OnResizeRect(*reinterpret_cast(data1)); return; case USDPREVIEWEVENT_SETWINDOW: OnResizeRect(*reinterpret_cast(data2)); break; case USDPREVIEWEVENT_QUIT: OnQuit(); break; } UsdPreviewEventData eventData = {}; eventData.event = event; eventData.data1 = data1; eventData.data2 = data2; std::lock_guard guard(m_EventQueueMutex); m_EventQueue.push(std::move(eventData)); } void CUsdPreviewHandlerMgr::SetParent(HWND hWndParent, HWND hWndChild, HWND hWndStageView) { if ( m_bLoadComplete ) { // The parent passed in here is actually the load screen dialog. // We want to swap the load screen dialog here with our dialog. HWND hWndLoadScreen = hWndParent; RECT rcClient; ::GetClientRect( hWndLoadScreen, &rcClient ); HWND hWndPreviewParent = ::GetParent( hWndLoadScreen ); ::SetParent( hWndChild, hWndPreviewParent ); ::SetWindowLong( hWndChild, GWL_STYLE, WS_POPUP|WS_CLIPCHILDREN ); ::SetWindowPos( hWndChild, HWND_TOP, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, SWP_FRAMECHANGED ); ::ShowWindow( hWndChild, SW_SHOW ); ::ShowWindow( hWndLoadScreen, SW_HIDE ); m_StageViewWnd.Init( hWndStageView ); } m_hWndParent = hWndParent; m_hWndChild = hWndChild; m_hWndStageView = hWndStageView; } void CUsdPreviewHandlerMgr::OnResize(int cx, int cy) { if (m_bLoadComplete && m_hWndChild != nullptr) ::SetWindowPos(m_hWndChild, nullptr, 0, 0, cx, cy, 0); } void CUsdPreviewHandlerMgr::OnResizeRect(const RECT& rc) { if (m_bLoadComplete && m_hWndChild != nullptr) ::SetWindowPos(m_hWndChild, nullptr, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0); } void CUsdPreviewHandlerMgr::OnQuit() { m_bQuit = true; // clear out our data m_hWndChild = nullptr; m_hWndParent = nullptr; m_hWndStageView = nullptr; } HWND CUsdPreviewHandlerMgr::GetPreviewWindow() const { return m_hWndChild; } bool CUsdPreviewHandlerMgr::IsValid() const { return m_hWndChild != nullptr; } // pushes an event to Python extern "C" __declspec(dllexport) void UsdPreviewPushEvent(eUsdPreviewEvent event, intptr_t data1, intptr_t data2) { CUsdPreviewHandlerMgr::GetSingleton().PostEvent(event, data1, data2); } // pushes an event to Python extern "C" __declspec(dllexport) HWND UsdPreviewGetPreviewWindow() { return CUsdPreviewHandlerMgr::GetSingleton().GetPreviewWindow(); } ================================================ FILE: UsdPreviewHandlerPython/UsdPreviewHandlerMgr.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "UsdPreviewHandlerMgr.h" #include "UsdPreviewHandlerEvent.h" #include "StageViewWnd.h" #include #include class CUsdPreviewHandlerMgr { public: static CUsdPreviewHandlerMgr& GetSingleton(); UsdPreviewEventData PeekEvent(); void PostEvent(eUsdPreviewEvent event, intptr_t data1, intptr_t data2); void SetParent(HWND hWndParent, HWND hWndChild, HWND hWndStageView); HWND GetPreviewWindow() const; void LoadComplete(); bool IsValid() const; private: void OnResize(int cx, int cy); void OnResizeRect(const RECT& rc); void OnQuit(); static CUsdPreviewHandlerMgr s_Singleton; std::queue m_EventQueue; std::mutex m_EventQueueMutex; HWND m_hWndParent = nullptr; HWND m_hWndChild = nullptr; HWND m_hWndStageView = nullptr; bool m_bLoadComplete = false; bool m_bQuit = false; CStageViewWnd m_StageViewWnd; }; inline CUsdPreviewHandlerMgr& CUsdPreviewHandlerMgr::GetSingleton() { return s_Singleton; } ================================================ FILE: UsdPreviewHandlerPython/UsdPreviewHandlerPython.rc ================================================ // Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "#define ATVI_VERSION_DESCRIPTION ""Activision USD Preview Python Module""\r\n" "#include ""atviversion.rc2""\r\n" "\0" END #endif // APSTUDIO_INVOKED #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // #define ATVI_VERSION_DESCRIPTION "Activision USD Preview Python Module" #include "atviversion.rc2" ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: UsdPreviewHandlerPython/UsdPreviewHandlerPython.vcxproj ================================================ Debug x64 Release x64 16.0 Win32Proj {248f687e-4028-4243-87b8-2312f57be8a5} UsdPreviewHandlerPython UsdPreviewHandlerPython 10.0.14393.0 DynamicLibrary true v141 Unicode DynamicLibrary false v141 false Unicode RegistryView.Registry32 RegistryView.Registry64 $(PythonVersion)-32 $(PythonVersion) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $(PythonHome)python.exe $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) _d $([System.IO.Path]::GetDirectoryName($(PythonExe)))\python$(PythonDebugSuffix).exe $(PythonExe) true $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ .pyd UsdPreviewHandler false $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ .pyd UsdPreviewHandler Level4 true _DEBUG;USDPREVIEW_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) false Use stdafx.h $(PythonHome)include;%(AdditionalIncludeDirectories) Disabled Disabled true Windows true false $(PythonHome)libs;C:\usd-20.08\lib;%(AdditionalLibraryDirectories) UxTheme.lib;%(AdditionalDependencies) $(OutDir);$(SolutionDir);%(AdditionalIncludeDirectories) Level4 true true true NDEBUG;USDPREVIEW_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) false Use stdafx.h $(PythonHome)include;%(AdditionalIncludeDirectories) AnySuitable Windows false false true false $(PythonHome)libs;%(AdditionalLibraryDirectories) UxTheme.lib;%(AdditionalDependencies) $(OutDir);$(SolutionDir);%(AdditionalIncludeDirectories) Create Create ================================================ FILE: UsdPreviewHandlerPython/UsdPreviewHandlerPython.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Header Files Header Files Header Files Header Files Header Files Source Files Source Files Source Files Source Files Source Files Resource Files ================================================ FILE: UsdPreviewHandlerPython/pyUsdPreviewHandler.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "UsdPreviewHandlerEvent.h" #include "UsdPreviewHandlerMgr.h" using namespace boost::python; struct UsdPreviewApp { void SetParent( uint64_t nWndParent, uint64_t nWndChild, uint64_t nWndStageView ); UsdPreviewEventData PeekEvent(); void LoadComplete(); }; BOOST_PYTHON_MODULE( UsdPreviewHandler ) { using namespace boost::python; enum_( "UsdPreviewEvent" ) .value( "NoMoreEvents", USDPREVIEWEVENT_INVALID) .value( "Quit", USDPREVIEWEVENT_QUIT) ; class_( "UsdPreviewEventData", "help", no_init ) .def_readonly("event", &UsdPreviewEventData::event) .def_readonly("data1", &UsdPreviewEventData::data1) .def_readonly("data2", &UsdPreviewEventData::data2) ; class_( "UsdPreviewApp", "help", init<>() ) .def( "SetParent", &UsdPreviewApp::SetParent ) .def( "PeekEvent", &UsdPreviewApp::PeekEvent ) .def( "LoadComplete", &UsdPreviewApp::LoadComplete ) ; } void UsdPreviewApp::SetParent( uint64_t nWndParent, uint64_t nWndChild, uint64_t nWndStageView ) { HWND hWndParent = reinterpret_cast(nWndParent); HWND hWndChild = reinterpret_cast(nWndChild); HWND hWndStageView = reinterpret_cast(nWndStageView); CUsdPreviewHandlerMgr::GetSingleton().SetParent(hWndParent, hWndChild, hWndStageView); } UsdPreviewEventData UsdPreviewApp::PeekEvent() { return CUsdPreviewHandlerMgr::GetSingleton().PeekEvent(); } void UsdPreviewApp::LoadComplete() { CUsdPreviewHandlerMgr::GetSingleton().LoadComplete(); } ================================================ FILE: UsdPreviewHandlerPython/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by UsdPreviewHandlerPython.rc // // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40012 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: UsdPreviewHandlerPython/stdafx.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" ================================================ FILE: UsdPreviewHandlerPython/stdafx.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #pragma warning(push) #pragma warning(disable: 4244 4459) #include #include #include #include #pragma warning(pop) #include #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include #include ================================================ FILE: UsdPreviewHandlerServer/Module.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "Module.h" HMODULE g_hInstance; CUSDPreviewLocalServerModule g_AtlModule; extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd) { UNREFERENCED_PARAMETER( hPrevInstance ); UNREFERENCED_PARAMETER( lpCmdLine ); UNREFERENCED_PARAMETER( nShowCmd ); g_hInstance = hInstance; int nResult = g_AtlModule.WinMain( nShowCmd ); return nResult; } ================================================ FILE: UsdPreviewHandlerServer/Module.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "USDPreviewLocalServer_h.h" #include "resource.h" // Using an ATL module here because it removes a lot of the // boiler-plate COM work that we would have to implement ourselves. class CUSDPreviewLocalServerModule : public CAtlExeModuleT { public: DECLARE_LIBID( LIBID_USDPreview ) DECLARE_REGISTRY_APPID_RESOURCEID( IDR_REGISTRY_MODULE, "{067AAB34-285D-40D1-92EF-A5ED449EFEEE}" ) // Override CAtlExeModuleT::PreMessageLoop to change REGCLS_MULTIPLEUSE to REGCLS_SINGLEUSE. // REGCLS_SINGLEUSE will create a new Windows process for every instance of our COM classes, // REGCLS_MULTIPLEUSE will reuse the same Windows process. HRESULT PreMessageLoop( _In_ int /*nShowCmd*/ ) throw() { HRESULT hr = S_OK; CUSDPreviewLocalServerModule* pT = static_cast(this); #ifndef _ATL_NO_COM_SUPPORT hr = pT->RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE | // <- !!! REGCLS_SUSPENDED); if (FAILED(hr)) return hr; if (hr == S_OK) { if (m_bDelayShutdown) { CHandle h(pT->StartMonitor()); if (h.m_h == NULL) { hr = E_FAIL; } else { hr = CoResumeClassObjects(); ATLASSERT(SUCCEEDED(hr)); if (FAILED(hr)) { ::SetEvent(m_hEventShutdown); // tell monitor to shutdown ::WaitForSingleObject(h, m_dwTimeOut * 2); } } } else { hr = CoResumeClassObjects(); ATLASSERT(SUCCEEDED(hr)); } if (FAILED(hr)) pT->RevokeClassObjects(); } else { m_bDelayShutdown = false; } #endif // _ATL_NO_COM_SUPPORT ATLASSERT(SUCCEEDED(hr)); return hr; } }; extern CUSDPreviewLocalServerModule g_AtlModule; extern HMODULE g_hInstance; ================================================ FILE: UsdPreviewHandlerServer/UsdPreviewHandlerImpl.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "USDPreviewHandlerImpl.h" #include "Module.h" #include "shared\PythonUtil.h" #include "shared\emb.h" #include "shared\environment.h" #include "shared\EventViewerLog.h" HRESULT CUsdPreviewHandlerImpl::FinalConstruct() { SetupPythonEnvironment( g_hInstance ); m_hUsdPreviewLib = LoadLibraryEx(_T("UsdPreviewHandler.pyd"), nullptr, LOAD_LIBRARY_SEARCH_APPLICATION_DIR|LOAD_LIBRARY_SEARCH_SYSTEM32); if (m_hUsdPreviewLib == nullptr) return E_FAIL; m_fnUsdPreviewPushEvent = reinterpret_cast(GetProcAddress(m_hUsdPreviewLib, "UsdPreviewPushEvent")); if (m_fnUsdPreviewPushEvent == nullptr) return E_FAIL; m_fnUsdGetPreviewWindow = reinterpret_cast(GetProcAddress(m_hUsdPreviewLib, "UsdPreviewGetPreviewWindow")); if (m_fnUsdGetPreviewWindow == nullptr) return E_FAIL; if ( !m_PreviewThread.Init() ) return E_FAIL; m_clrBackground = ::GetSysColor( COLOR_WINDOW ); m_clrText = ::GetSysColor( COLOR_WINDOWTEXT ); return __super::FinalConstruct(); } void CUsdPreviewHandlerImpl::FinalRelease() { m_PreviewThread.Term(); if (m_hUsdPreviewLib) { FreeLibrary(m_hUsdPreviewLib); m_hUsdPreviewLib = nullptr; m_fnUsdPreviewPushEvent = nullptr; m_fnUsdGetPreviewWindow = nullptr; } __super::FinalRelease(); } // IInitializeWithFile STDMETHODIMP CUsdPreviewHandlerImpl::Initialize(__RPC__in_string LPCWSTR pszFilePath, DWORD grfMode) { UNREFERENCED_PARAMETER(grfMode); m_usdStagePath = pszFilePath; return S_OK; } // IObjectWithSite STDMETHODIMP CUsdPreviewHandlerImpl::SetSite(__RPC__in_opt IUnknown* pUnkSite) { m_pSite = nullptr; m_pPreviewHandlerFrame = nullptr; m_PreviewHandlerFrameInfo.Term(); if (pUnkSite != nullptr) { m_pSite = pUnkSite; CComQIPtr pIPreviewHandlerFrame(m_pSite); m_pPreviewHandlerFrame = pIPreviewHandlerFrame; if ( m_pPreviewHandlerFrame ) m_pPreviewHandlerFrame->GetWindowContext( &m_PreviewHandlerFrameInfo ); } return S_OK; } STDMETHODIMP CUsdPreviewHandlerImpl::GetSite(__RPC__in REFIID riid, __RPC__deref_out_opt void** ppvSite) { if (ppvSite == nullptr) return E_POINTER; if (m_pSite == nullptr) { *ppvSite = nullptr; return E_FAIL; } HRESULT hr; hr = m_pSite->QueryInterface(riid, ppvSite); return hr; } // IOleWindow STDMETHODIMP CUsdPreviewHandlerImpl::GetWindow(__RPC__deref_out_opt HWND* phwnd) { if (phwnd == nullptr) return E_POINTER; *phwnd = m_fnUsdGetPreviewWindow(); if ( *phwnd == nullptr ) return E_FAIL; return S_OK; } STDMETHODIMP CUsdPreviewHandlerImpl::ContextSensitiveHelp(BOOL fEnterMode) { UNREFERENCED_PARAMETER(fEnterMode); return E_NOTIMPL; } // IPreviewHandler STDMETHODIMP CUsdPreviewHandlerImpl::SetWindow(__RPC__in HWND hwnd, __RPC__in const RECT* prc) { if (prc == nullptr) return E_POINTER; m_hWndParent = hwnd; m_rcWindow = *prc; PushEvent( USDPREVIEWEVENT_SETWINDOW, reinterpret_cast(m_hWndParent), reinterpret_cast(&m_rcWindow) ); return S_OK; } STDMETHODIMP CUsdPreviewHandlerImpl::SetRect(__RPC__in const RECT* prc) { if (prc == nullptr) return E_POINTER; m_rcWindow = *prc; PushEvent( USDPREVIEWEVENT_RESIZERECT, reinterpret_cast(&m_rcWindow) ); return S_OK; } STDMETHODIMP CUsdPreviewHandlerImpl::DoPreview() { HRESULT hr; hr = m_PreviewThread.LaunchPreviewWindow( reinterpret_cast(m_hWndParent), m_usdStagePath ); if (FAILED(hr)) return hr; return S_OK; } STDMETHODIMP CUsdPreviewHandlerImpl::Unload() { // push the shutdown event to Python PushEvent( USDPREVIEWEVENT_QUIT ); m_usdStagePath.Empty(); m_pSite = nullptr; m_pPreviewHandlerFrame = nullptr; m_PreviewHandlerFrameInfo.Term(); m_hWndParent = nullptr; m_rcWindow = {}; return S_OK; } STDMETHODIMP CUsdPreviewHandlerImpl::SetFocus() { return S_OK; } STDMETHODIMP CUsdPreviewHandlerImpl::QueryFocus(__RPC__deref_out_opt HWND* phwnd) { if ( phwnd == nullptr ) return E_POINTER; *phwnd = nullptr; return S_OK; } STDMETHODIMP CUsdPreviewHandlerImpl::TranslateAccelerator(__RPC__in MSG* pmsg) { if (pmsg == nullptr) return E_POINTER; if ( m_pPreviewHandlerFrame && IsAccelerator( m_PreviewHandlerFrameInfo.haccel, m_PreviewHandlerFrameInfo.cAccelEntries, pmsg, nullptr ) ) { return m_pPreviewHandlerFrame->TranslateAccelerator(pmsg); } return S_FALSE; } STDMETHODIMP CUsdPreviewHandlerImpl::SetBackgroundColor( COLORREF color ) { m_clrBackground = color; return S_OK; } STDMETHODIMP CUsdPreviewHandlerImpl::SetFont( __RPC__in const LOGFONTW *plf ) { UNREFERENCED_PARAMETER( plf ); return S_OK; } STDMETHODIMP CUsdPreviewHandlerImpl::SetTextColor( COLORREF color ) { m_clrText = color; return S_OK; } bool CUsdPreviewHandlerImpl::PushEvent(eUsdPreviewEvent event, intptr_t data1, intptr_t data2) { // push the event to Python if (m_fnUsdPreviewPushEvent == nullptr) return false; m_fnUsdPreviewPushEvent(event, data1, data2); return true; } HRESULT WINAPI CUsdPreviewHandlerImpl::UpdateRegistry(_In_ BOOL bRegister) throw() { ATL::_ATL_REGMAP_ENTRY regMapEntries[] = { { L"APPID", L"{067AAB34-285D-40D1-92EF-A5ED449EFEEE}" }, { L"TYPELIB", L"{68DF0FAC-996B-4933-B092-9733E77061BB}" }, { L"CLSID_USDPREVIEWHANDLER", L"{07D4D38F-9C98-48F8-A057-26241405D5C8}" }, { nullptr, nullptr } }; return g_AtlModule.UpdateRegistryFromResource(IDR_REGISTRY_USDPREVIEWHANDLERIMPL, bRegister, regMapEntries); } ================================================ FILE: UsdPreviewHandlerServer/UsdPreviewHandlerImpl.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "USDPreviewLocalServer_h.h" #include "USDPreviewThread.h" #include "UsdPreviewHandlerPython\UsdPreviewHandlerEvent.h" #include "resource.h" class CPreviewHandlerFrameInfo : public PREVIEWHANDLERFRAMEINFO { public: CPreviewHandlerFrameInfo() { haccel = nullptr; cAccelEntries = 0; } ~CPreviewHandlerFrameInfo() { Term(); } void Term() { if ( haccel ) { DestroyAcceleratorTable( haccel ); haccel = nullptr; } } }; class ATL_NO_VTABLE CUsdPreviewHandlerImpl : public CComObjectRootEx, public CComCoClass, public IInitializeWithFile, public IObjectWithSite, public IOleWindow, public IPreviewHandler, public IPreviewHandlerVisuals { public: DECLARE_NOT_AGGREGATABLE(CUsdPreviewHandlerImpl) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CUsdPreviewHandlerImpl) COM_INTERFACE_ENTRY(IInitializeWithFile) COM_INTERFACE_ENTRY(IObjectWithSite) COM_INTERFACE_ENTRY(IOleWindow) COM_INTERFACE_ENTRY(IPreviewHandler) COM_INTERFACE_ENTRY(IPreviewHandlerVisuals) END_COM_MAP() HRESULT FinalConstruct(); void FinalRelease(); // IInitializeWithFile STDMETHODIMP Initialize( __RPC__in_string LPCWSTR pszFilePath, DWORD grfMode ) override; // IObjectWithSite STDMETHODIMP SetSite(__RPC__in_opt IUnknown* pUnkSite) override; STDMETHODIMP GetSite(__RPC__in REFIID riid, __RPC__deref_out_opt void** ppvSite) override; // IOleWindow STDMETHODIMP GetWindow(__RPC__deref_out_opt HWND* phwnd) override; STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) override; // IPreviewHandler STDMETHODIMP SetWindow( __RPC__in HWND hwnd, __RPC__in const RECT* prc) override; STDMETHODIMP SetRect( __RPC__in const RECT* prc ) override; STDMETHODIMP DoPreview() override; STDMETHODIMP Unload() override; STDMETHODIMP SetFocus() override; STDMETHODIMP QueryFocus( __RPC__deref_out_opt HWND* phwnd) override; STDMETHODIMP TranslateAccelerator(__RPC__in MSG* pmsg) override; // IPreviewHandlerVisuals STDMETHODIMP SetBackgroundColor(COLORREF color) override; STDMETHODIMP SetFont(__RPC__in const LOGFONTW *plf) override; STDMETHODIMP SetTextColor(COLORREF color) override; static HRESULT WINAPI UpdateRegistry(_In_ BOOL bRegister) throw(); private: bool PushEvent(eUsdPreviewEvent event, intptr_t data1 = 0, intptr_t data2 = 0); HMODULE m_hUsdPreviewLib = nullptr; FNUSDPREVIEWPUSHEVENT m_fnUsdPreviewPushEvent = nullptr; FNUSDPREVIEWGETPREVIEWWINDOW m_fnUsdGetPreviewWindow = nullptr; CUSDPreviewThread m_PreviewThread; CStringW m_usdStagePath; CComPtr m_pSite; CComPtr m_pPreviewHandlerFrame; HWND m_hWndParent = nullptr; RECT m_rcWindow = {}; CPreviewHandlerFrameInfo m_PreviewHandlerFrameInfo; COLORREF m_clrBackground; COLORREF m_clrText; }; OBJECT_ENTRY_AUTO(__uuidof(USDPreviewHandler), CUsdPreviewHandlerImpl) ================================================ FILE: UsdPreviewHandlerServer/UsdPreviewHandlerImpl.rgs ================================================ HKCR { NoRemove CLSID { ForceRemove %CLSID_USDPREVIEWHANDLER% = s 'Activision USD Preview Handler Server' { LocalServer32 = s '%MODULE%' val AppID = s '%APPID%' } } } ================================================ FILE: UsdPreviewHandlerServer/UsdPreviewHandlerPython.py ================================================ # Copyright 2021 Activision Publishing, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import print_function import sys import os import argparse from pxr import Usd, UsdUtils, Sdf, UsdAppUtils from pxr.Usdviewq.stageView import StageView from pxr.UsdAppUtils.complexityArgs import RefinementComplexities import UsdPreviewHandler try: from PySide2.QtCore import * from PySide2.QtGui import * from PySide2.QtWidgets import * except ImportError: from PySide.QtCore import * from PySide.QtGui import * class Widget(QWidget): def __init__(self, stage=None, app=None, previewApp=None): super(Widget, self).__init__() self.setStyleSheet(u"") self.model = StageView.DefaultDataModel() self.view = StageView(dataModel=self.model, printTiming=True) self.model.viewSettings.showHUD = False self.app = app self.previewApp = previewApp self.layout = QVBoxLayout(self) self.layout.addWidget(self.view) self.layout.setContentsMargins(0, 0, 0, 0) self.isLoadComplete = False if stage: self.setStage(stage) def setStage(self, stage): self.model.stage = stage def OnComplexity(self, action): self.model.viewSettings.complexity = RefinementComplexities.fromName(action.text()) def OnShadingMode(self, action): self.model.viewSettings.renderMode = str(action.text()) def OnToggleDisplayGuide(self, action): self.model.viewSettings.displayGuide = (self.actionDisplay_Guide.isChecked()) def OnToggleDisplayProxy(self, action): self.model.viewSettings.displayProxy = (self.actionDisplay_Proxy.isChecked()) def OnToggleDisplayRender(self, action): self.model.viewSettings.displayRender = (self.actionDisplay_Render.isChecked()) def OnRendererPlugin(self, plugin): if not self.view.SetRendererPlugin(plugin): # If SetRendererPlugin failed, we need to reset the check mark # to whatever the currently loaded renderer is. for action in self.rendererPluginActionGroup.actions(): if action.text() == self.view.rendererDisplayName: action.setChecked(True) break # Then display an error message to let the user know something # went wrong, and disable the menu item so it can't be selected # again. for action in self.rendererPluginActionGroup.actions(): if action.pluginType == plugin: self.statusMessage( 'Renderer not supported: %s' % action.text()) action.setText(action.text() + " (unsupported)") action.setDisabled(True) break def buildContextMenu_Renderer(self, contextMenu): self.rendererPluginActionGroup = QActionGroup(self) self.rendererPluginActionGroup.setExclusive(True) rendererMenu = contextMenu.addMenu("Hydra Renderer") pluginTypes = self.view.GetRendererPlugins() for pluginType in pluginTypes: name = self.view.GetRendererDisplayName(pluginType) action = rendererMenu.addAction(name) action.setCheckable(True) action.pluginType = pluginType self.rendererPluginActionGroup.addAction(action) action.triggered[bool].connect(lambda _, pluginType=pluginType: self.OnRendererPlugin(pluginType)) # Now set the checked box on the current renderer (it should # have been set by now). currentRendererId = self.view.GetCurrentRendererId() foundPlugin = False for action in self.rendererPluginActionGroup.actions(): if action.pluginType == currentRendererId: action.setChecked(True) foundPlugin = True break # Disable the menu if no plugins were found rendererMenu.setEnabled(foundPlugin) def buildContextMenu_Complexity(self, contextMenu): self.actionLow = QAction("Low", self) self.actionLow.setObjectName(u"actionLow") self.actionLow.setCheckable(True) self.actionMedium = QAction("Medium", self) self.actionMedium.setCheckable(True) self.actionMedium.setObjectName(u"actionMedium") self.actionHigh = QAction("High", self) self.actionHigh.setCheckable(True) self.actionHigh.setObjectName(u"actionHigh") self.actionVery_High = QAction("Very High", self) self.actionVery_High.setCheckable(True) self.actionVery_High.setObjectName(u"actionVery_High") self.complexityGroup = QActionGroup(self) self.complexityGroup.setExclusive(True) self.complexityGroup.addAction(self.actionLow) self.complexityGroup.addAction(self.actionMedium) self.complexityGroup.addAction(self.actionHigh) self.complexityGroup.addAction(self.actionVery_High) self.complexityGroup.triggered.connect(self.OnComplexity) self.actionLow.setChecked(True) complexityMenu = contextMenu.addMenu("Complexity") complexityMenu.addAction(self.actionLow) complexityMenu.addAction(self.actionMedium) complexityMenu.addAction(self.actionHigh) complexityMenu.addAction(self.actionVery_High) def buildContextMenu_ShadingMode(self, contextMenu): self.actionWireframe = QAction("Wireframe", self) self.actionWireframe.setCheckable(True) self.actionWireframeOnSurface = QAction("WireframeOnSurface", self) self.actionWireframeOnSurface.setCheckable(True) self.actionSmooth_Shaded = QAction("Smooth Shaded", self) self.actionSmooth_Shaded.setCheckable(True) self.actionFlat_Shaded = QAction("Flat Shaded", self) self.actionFlat_Shaded.setCheckable(True) self.actionPoints = QAction("Points", self) self.actionPoints.setCheckable(True) self.actionGeom_Only = QAction("Geom Only", self) self.actionGeom_Only.setCheckable(True) self.actionGeom_Smooth = QAction("Geom Smooth", self) self.actionGeom_Smooth.setCheckable(True) self.actionGeom_Flat = QAction("Geom Flat", self) self.actionGeom_Flat.setCheckable(True) self.actionHidden_Surface_Wireframe = QAction("Hidden Surface Wireframe", self) self.actionHidden_Surface_Wireframe.setCheckable(True) self.shadingGroup = QActionGroup(self) self.shadingGroup.setExclusive(True) self.shadingGroup.addAction(self.actionWireframe) self.shadingGroup.addAction(self.actionWireframeOnSurface) self.shadingGroup.addAction(self.actionSmooth_Shaded) self.shadingGroup.addAction(self.actionFlat_Shaded) self.shadingGroup.addAction(self.actionPoints) self.shadingGroup.addAction(self.actionGeom_Only) self.shadingGroup.addAction(self.actionGeom_Smooth) self.shadingGroup.addAction(self.actionGeom_Flat) self.shadingGroup.addAction(self.actionHidden_Surface_Wireframe) self.shadingGroup.triggered.connect(self.OnShadingMode) self.actionGeom_Smooth.setChecked(True) complexityMenu = contextMenu.addMenu("Shading Mode") complexityMenu.addAction(self.actionWireframe) complexityMenu.addAction(self.actionWireframeOnSurface) complexityMenu.addAction(self.actionSmooth_Shaded) complexityMenu.addAction(self.actionFlat_Shaded) complexityMenu.addAction(self.actionPoints) complexityMenu.addAction(self.actionGeom_Only) complexityMenu.addAction(self.actionGeom_Smooth) complexityMenu.addAction(self.actionGeom_Flat) complexityMenu.addAction(self.actionHidden_Surface_Wireframe) def buildContextMenu_DisplayPurposes(self, contextMenu): self.actionDisplay_Guide = QAction("Guide", self) self.actionDisplay_Guide.setCheckable(True) self.actionDisplay_Guide.triggered.connect(self.OnToggleDisplayGuide) self.actionDisplay_Guide.setChecked(self.model.viewSettings.displayGuide) self.actionDisplay_Proxy = QAction("Proxy", self) self.actionDisplay_Proxy.setCheckable(True) self.actionDisplay_Proxy.triggered.connect(self.OnToggleDisplayProxy) self.actionDisplay_Proxy.setChecked(self.model.viewSettings.displayProxy) self.actionDisplay_Render = QAction("Render", self) self.actionDisplay_Render.setCheckable(True) self.actionDisplay_Render.triggered.connect(self.OnToggleDisplayRender) self.actionDisplay_Render.setChecked(self.model.viewSettings.displayRender) displayPurposesMenu = contextMenu.addMenu("Display Purposes") displayPurposesMenu.addAction(self.actionDisplay_Guide) displayPurposesMenu.addAction(self.actionDisplay_Proxy) displayPurposesMenu.addAction(self.actionDisplay_Render) def buildContextMenu(self): self.contextMenu = QMenu(self) self.buildContextMenu_Renderer(self.contextMenu) self.buildContextMenu_Complexity(self.contextMenu) self.buildContextMenu_ShadingMode(self.contextMenu) self.buildContextMenu_DisplayPurposes(self.contextMenu) def closeEvent(self, event): # Ensure to close the renderer to avoid GlfPostPendingGLErrors self.view.closeRenderer() def contextMenuEvent(self, event): modifiers = self.app.keyboardModifiers() altModifer = ((modifiers & Qt.AltModifier) == Qt.AltModifier) shiftModifer = ((modifiers & Qt.ShiftModifier) == Qt.ShiftModifier) controlModifer = ((modifiers & Qt.ControlModifier) == Qt.ControlModifier) if not altModifer and not shiftModifer and not controlModifer: self.contextMenu.exec_(self.mapToGlobal(event.pos())) def timerEvent(self, event): if (not self.isLoadComplete) and (not self.view._isFirstImage): self.isLoadComplete = True self.previewApp.LoadComplete() eventData = self.previewApp.PeekEvent() while eventData.event != UsdPreviewHandler.UsdPreviewEvent.NoMoreEvents: if eventData.event == UsdPreviewHandler.UsdPreviewEvent.Quit: self.app.quit() eventData = self.previewApp.PeekEvent() def setStyleSheetUsingState(app, resourceDir): # We use a style file that is actually a template, which we fill # in from state, and is how we change app font sizes, for example. # Qt style sheet accepts only forward slashes as path separators resourceDir = resourceDir.replace("\\", "/") fontSize = 10 baseFontSizeStr = "%spt" % str(fontSize) # The choice of 8 for smallest smallSize is for performance reasons, # based on the "Gotham Rounded" font used by usdviewstyle.qss . If we # allow it to float, we get a 2-3 hundred millisecond hit in startup # time as Qt (apparently) manufactures a suitably sized font. # Mysteriously, we don't see this cost for larger font sizes. smallSize = 8 if fontSize < 12 else int(round(fontSize * 0.8)) smallFontSizeStr = "%spt" % str(smallSize) # Apply the style sheet to it sheet = open(os.path.join(resourceDir, 'usdviewstyle.qss'), 'r') sheetString = sheet.read() % { 'RESOURCE_DIR' : resourceDir, 'BASE_FONT_SZ' : baseFontSizeStr, 'SMALL_FONT_SZ' : smallFontSizeStr } app.setStyleSheet(sheetString) def main(): programName = os.path.basename(sys.argv[0]) parser = argparse.ArgumentParser(prog=programName, description='Preview for Windows Explorer') parser.add_argument('usdFilePath', action='store', type=str, help='USD file to preview') parser.add_argument('--hwnd', action='store', type=int, default=0, help='The HWND of the parent window') parser.add_argument('--usdviewqDir', action='store', type=str, help='Full path to the usdviewq python folder') UsdAppUtils.rendererArgs.AddCmdlineArgs(parser) args = parser.parse_args() with Usd.StageCacheContext(UsdUtils.StageCache.Get()): stage = Usd.Stage.Open(args.usdFilePath) previewApp = UsdPreviewHandler.UsdPreviewApp() app = QApplication([]) setStyleSheetUsingState(app, args.usdviewqDir) window = Widget(stage, app, previewApp) window.setWindowFlags( Qt.Popup | Qt.Tool ) window.setAttribute( Qt.WA_DontShowOnScreen ) window.show() # poll for events every so often window.startTimer( 250 ) try: import ctypes ctypes.pythonapi.PyCObject_AsVoidPtr.restype = ctypes.c_void_p ctypes.pythonapi.PyCObject_AsVoidPtr.argtypes = [ctypes.py_object] previewApp.SetParent( args.hwnd, ctypes.pythonapi.PyCObject_AsVoidPtr(window.effectiveWinId()), ctypes.pythonapi.PyCObject_AsVoidPtr(window.view.effectiveWinId()) ) except: previewApp.SetParent( args.hwnd, window.effectiveWinId(), window.view.effectiveWinId() ) window.setAttribute( Qt.WA_DontShowOnScreen, False ) # Make camera fit the loaded geometry window.view.updateView(resetCam=True, forceComputeBBox=True) # force a draw when hidden window.view.glDraw() window.buildContextMenu() app.exec_() if __name__ == "__main__": sys.exit(main()) ================================================ FILE: UsdPreviewHandlerServer/UsdPreviewLocalServer.idl ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import "oaidl.idl"; import "ocidl.idl"; import "ShObjIdl.idl"; [ uuid(68DF0FAC-996B-4933-B092-9733E77061BB), helpstring("USDPreview Type Library"), version(1.0), ] library USDPreview { [ uuid(07D4D38F-9C98-48F8-A057-26241405D5C8), helpstring("USD IPreviewHandler Server implementation") ] coclass USDPreviewHandler { [default] interface IPreviewHandler; } }; ================================================ FILE: UsdPreviewHandlerServer/UsdPreviewLocalServer.rc ================================================ // Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "1 TYPELIB ""USDPreviewLocalServer.tlb""\r\n" "\r\n" "#define ATVI_VERSION_DESCRIPTION ""Activision USD Preview Server""\r\n" "#include ""atviversion.rc2""\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // REGISTRY // IDR_REGISTRY_MODULE REGISTRY "USDPreviewLocalServerModule.rgs" IDR_REGISTRY_USDPREVIEWHANDLERIMPL REGISTRY "USDPreviewHandlerImpl.rgs" ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ICON_USD ICON "shared\\usd.ico" ///////////////////////////////////////////////////////////////////////////// // // PYTHON // IDR_PYTHON_PREVIEWHANLDER PYTHON "UsdPreviewHandlerPython.py" #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // 1 TYPELIB "USDPreviewLocalServer.tlb" #define ATVI_VERSION_DESCRIPTION "Activision USD Preview Server" #include "atviversion.rc2" ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: UsdPreviewHandlerServer/UsdPreviewLocalServer.vcxproj ================================================ Debug x64 Release x64 16.0 Win32Proj {279AFA6D-6E35-4798-BA63-8A7E15D11185} UsdPreviewLocalServer 10.0.14393.0 Application true v141 false Unicode Application false v141 false Unicode RegistryView.Registry32 RegistryView.Registry64 $(PythonVersion)-32 $(PythonVersion) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $(PythonHome)python.exe $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) _d $([System.IO.Path]::GetDirectoryName($(PythonExe)))\python$(PythonDebugSuffix).exe $(PythonExe) false $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ true false $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ true Level3 true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true true true Level3 true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true true true Level4 true true true _WINDOWS;_DEBUG;%(PreprocessorDefinitions) false Use Disabled MultiThreadedDebugDLL $(SolutionDir);$(PythonHome)include;%(AdditionalIncludeDirectories) Disabled Windows false false true $(PythonHome)libs;%(AdditionalLibraryDirectories) Pathcch.lib;%(AdditionalDependencies) $(OutDir);$(SolutionDir);%(AdditionalIncludeDirectories) %(Filename)_i.c false true 0 All $(OutDir)$(ProjectName).tlb %(Command) Level4 true true true _WINDOWS;NDEBUG;%(PreprocessorDefinitions) false Use $(SolutionDir);$(PythonHome)include;%(AdditionalIncludeDirectories) MaxSpeed AnySuitable Windows false false true $(PythonHome)libs;%(AdditionalLibraryDirectories) Pathcch.lib;%(AdditionalDependencies) $(OutDir);$(SolutionDir);%(AdditionalIncludeDirectories) %(Filename)_i.c false true 0 All $(OutDir)$(ProjectName).tlb %(Command) Create Create NotUsing NotUsing All true {f12e597b-b731-4f5a-bec3-980d20159320} ================================================ FILE: UsdPreviewHandlerServer/UsdPreviewLocalServer.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {31617a27-1920-4188-aada-071adaa53b76} Header Files Header Files Header Files Header Files Header Files Header Files Shared Shared Shared Shared Source Files Source Files Source Files Source Files Source Files Shared Shared Resource Files Resource Files Source Files Resource Files Shared Resource Files ================================================ FILE: UsdPreviewHandlerServer/UsdPreviewLocalServerModule.rgs ================================================ HKCU { NoRemove AppID { '%APPID%' = s 'USDPreviewLocalServer' 'USDPreviewLocalServer.exe' { val AppID = s '%APPID%' } } } ================================================ FILE: UsdPreviewHandlerServer/UsdPreviewThread.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "USDPreviewThread.h" #include "Module.h" #include "shared\PythonUtil.h" #include "shared\emb.h" #include "shared\environment.h" #include "shared\EventViewerLog.h" CUSDPreviewThread::~CUSDPreviewThread() { Term(); } bool CUSDPreviewThread::Init() { return true; } void CUSDPreviewThread::Term() { WaitForExit(); } static bool GetRendererFromConfig( LPCTSTR system, CStringW &out ) { std::vector ConfigFileList = BuildConfigFileList( g_hInstance ); CStringW sRenderer; GetPrivateProfileStringAndExpandEnvironmentStrings( L"RENDERER", system, L"GL", sRenderer, ConfigFileList ); if ( sRenderer.IsEmpty() ) return false; out = sRenderer; return true; } HRESULT CUSDPreviewThread::LaunchPreviewWindow( HWND hWndParent, LPCTSTR pPathToUsdStage ) { m_hParent = hWndParent; m_sPathToUsdStage = pPathToUsdStage; m_hThread = ::CreateThread( nullptr, 0, ThreadProc, this, 0, nullptr ); if ( m_hThread == nullptr ) return false; return S_OK; } void CUSDPreviewThread::WaitForExit() { if ( m_hThread == nullptr ) return; if ( ::WaitForSingleObject( m_hThread, 1000 ) == WAIT_TIMEOUT ) { TerminateThread( m_hThread, (DWORD)-1 ); } m_hThread = nullptr; } static CStringW LocateUsdviewq() { const std::vector &PathList = GetUsdPythonPathList(); for ( const CString &sDir : PathList ) { TCHAR sFilePath[512]; _tcscpy_s( sFilePath, sDir.GetString() ); ::PathCchAppend( sFilePath, ARRAYSIZE( sFilePath ), _T("pxr\\Usdviewq") ); DWORD nAttribs = ::GetFileAttributes( sFilePath ); if ( (nAttribs != INVALID_FILE_ATTRIBUTES) && (nAttribs & FILE_ATTRIBUTE_DIRECTORY) ) return sFilePath; } return L""; } DWORD WINAPI CUSDPreviewThread::ThreadProc( _In_ LPVOID lpParameter ) { CUSDPreviewThread *pThis = reinterpret_cast(lpParameter); TPyChar sPathToHostExe[MAX_PATH]; #if PY_MAJOR_VERSION >= 3 ::GetModuleFileNameW(nullptr, sPathToHostExe, ARRAYSIZE(sPathToHostExe)); #else ::GetModuleFileNameA(nullptr, sPathToHostExe, ARRAYSIZE(sPathToHostExe)); #endif Py_SetProgramName(sPathToHostExe); PyImport_AppendInittab("emb", emb::PyInit_emb); CPyInterpreter pyInterpreter; PyImport_ImportModule("emb"); CStringW shWndParent; shWndParent.Format(L"%d", pThis->m_hParent); CStringW sRenderer; GetRendererFromConfig( _T( "PREVIEW" ), sRenderer ); CStringW sUsdViewqFolder; sUsdViewqFolder = LocateUsdviewq(); // UsdStageView initializes the renderer from this environment variable _tputenv_s( _T("HD_DEFAULT_RENDERER"), sRenderer ); std::vector ArgV; ArgV.push_back( sPathToHostExe ); ArgV.push_back( _Tpy( "--hwnd" ) ); CW2Py pyhWndParent( shWndParent ); ArgV.push_back( pyhWndParent ); ArgV.push_back( _Tpy( "--usdviewqDir" ) ); CW2Py pyUsdViewqFolder( sUsdViewqFolder ); ArgV.push_back( pyUsdViewqFolder ); CW2Py pyPathToUsdStage( pThis->m_sPathToUsdStage ); ArgV.push_back( pyPathToUsdStage ); PyAppendSysPath( GetUsdPythonPathList() ); PySetEnvironmentVariable( L"PATH", GetUsdPath() ); PySetEnvironmentVariable( L"PYTHONPATH", GetUsdPythonPath() ); PySys_SetArgvEx( static_cast(ArgV.size()), const_cast(&ArgV[0]), 1 ); HRSRC hrscPy = ::FindResource( g_hInstance, MAKEINTRESOURCE( IDR_PYTHON_PREVIEWHANLDER ), _T("PYTHON") ); if ( hrscPy == nullptr ) return static_cast(-1); HGLOBAL hPy = ::LoadResource( g_hInstance, hrscPy ); if ( hPy == nullptr ) return static_cast(-1); void* pScriptData = ::LockResource( hPy ); if ( pScriptData == nullptr ) return static_cast(-1); DWORD nSize = SizeofResource( g_hInstance, hrscPy ); CStringA pyScript; pyScript.SetString( reinterpret_cast(pScriptData), nSize ); PyObject* pMainModule = PyImport_AddModule("__main__"); PyObject* pGlobalDict = PyModule_GetDict(pMainModule); std::string buffer; emb::stdout_write_type writeStdOut = [&buffer] (std::string s) { buffer += s; }; emb::set_stdout(writeStdOut); emb::stdout_write_type writeStdErr = [&buffer] (std::string s) { buffer += s; }; emb::set_stderr(writeStdErr); CPyObject result = CPyObject( PyRun_String( pyScript.GetString(), Py_file_input, pGlobalDict, pGlobalDict ) ); emb::reset_stdout(); emb::reset_stderr(); int exitCode = 0; if ( PyErr_Occurred() ) { CPyException e; if ( !e.IsExceptionSystemExit() ) { CString sErrorMsg = e.tracebackW(); if ( !buffer.empty() ) sErrorMsg.AppendFormat( _T( "\n\n[STDOUT]\n%hs" ), buffer.c_str() ); if ( sErrorMsg.IsEmpty() ) { sErrorMsg = e.typeW(); } LogEventMessage( PREVIEWHANDLER_CATEGORY, sErrorMsg.GetString(), LogEventType::Error ); return static_cast(-1); } else { PySystemExitObject* pSystemExitObject = reinterpret_cast(e.GetValue()); if ( pSystemExitObject && pSystemExitObject->code ) { if ( PyLong_Check( pSystemExitObject->code ) ) { exitCode = PyLong_AsLong( pSystemExitObject->code ); } else if ( PyUnicode_Check( pSystemExitObject->code ) ) { // unexpected buffer += e.what(); exitCode = -1; LogEventMessage( PREVIEWHANDLER_CATEGORY, e.whatW(), LogEventType::Error ); } } } } return exitCode; } ================================================ FILE: UsdPreviewHandlerServer/UsdPreviewThread.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once class CUSDPreviewThread { public: ~CUSDPreviewThread(); bool Init(); void Term(); HRESULT LaunchPreviewWindow(HWND hWndParent, LPCTSTR pPathToUsdStage); void WaitForExit(); bool IsValid() const; private: static DWORD WINAPI ThreadProc( _In_ LPVOID lpParameter ); HANDLE m_hThread = nullptr; HWND m_hParent = 0; CString m_sPathToUsdStage; }; inline bool CUSDPreviewThread::IsValid() const { return m_hThread != nullptr; } ================================================ FILE: UsdPreviewHandlerServer/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by UsdPreviewLocalServer.rc // #define IDR_REGISTRY_MODULE 101 #define IDR_REGISTRY_USDPREVIEWIMPL 102 #define IDR_REGISTRY_PREVIEWHANDLERIMPL 105 #define IDR_REGISTRY_USDPREVIEWHANDLERIMPL 105 #define IDI_ICONUSD 106 #define IDI_ICON_USD 106 #define IDR_PYTHON_PREVIEWHANLDER 107 #define IDR_REGISTRY_THUMBNAILIMPL 108 #define IDR_REGISTRY_USDTHUMBNAILIMPL 108 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 109 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1004 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: UsdPreviewHandlerServer/stdafx.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" ================================================ FILE: UsdPreviewHandlerServer/stdafx.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #ifndef STRICT #define STRICT #endif #pragma warning(push) #pragma warning(disable: 4244 4459) #include #include #include #include #pragma warning(pop) #include #define _WIN32_WINNT 0x0A00 #include #define _ATL_APARTMENT_THREADED #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit #define ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW // Use the C++ standard templated min/max #define NOMINMAX #define NOBITMAP // Include if you need this #define NOMCX // Include if you need this #define NOSERVICE #include #include #include #include #include #include #include #include #include #include ================================================ FILE: UsdPythonToolsServer/Module.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "Module.h" HMODULE g_hInstance; CUsdPythonToolsLocalServerModule g_AtlModule; CString g_DebugIUsdPythonToolsMethod; extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd) { UNREFERENCED_PARAMETER( hPrevInstance ); UNREFERENCED_PARAMETER( lpCmdLine ); UNREFERENCED_PARAMETER( nShowCmd ); g_hInstance = hInstance; int nResult = g_AtlModule.WinMain( nShowCmd ); return nResult; } ================================================ FILE: UsdPythonToolsServer/Module.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "UsdPythonToolsLocalServer_h.h" #include "resource.h" // Using an ATL module here because it removes a lot of the // boiler-plate COM work that we would have to implement ourselves. class CUsdPythonToolsLocalServerModule : public CAtlExeModuleT { public: DECLARE_LIBID( LIBID_UsdPythonToolsLib ) DECLARE_REGISTRY_APPID_RESOURCEID( IDR_REGISTRY_MODULE, "{8777F2C4-2318-408A-85D8-F65E15811971}" ) // Override CAtlExeModuleT::PreMessageLoop to change REGCLS_MULTIPLEUSE to REGCLS_SINGLEUSE. // REGCLS_SINGLEUSE will create a new Windows process for every instance of our COM classes, // REGCLS_MULTIPLEUSE will reuse the same Windows process. HRESULT PreMessageLoop( _In_ int /*nShowCmd*/ ) throw() { HRESULT hr = S_OK; CUsdPythonToolsLocalServerModule* pT = static_cast(this); #ifndef _ATL_NO_COM_SUPPORT hr = pT->RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE | // <- !!! REGCLS_SUSPENDED); if (FAILED(hr)) return hr; if (hr == S_OK) { if (m_bDelayShutdown) { CHandle h(pT->StartMonitor()); if (h.m_h == NULL) { hr = E_FAIL; } else { hr = CoResumeClassObjects(); ATLASSERT(SUCCEEDED(hr)); if (FAILED(hr)) { ::SetEvent(m_hEventShutdown); // tell monitor to shutdown ::WaitForSingleObject(h, m_dwTimeOut * 2); } } } else { hr = CoResumeClassObjects(); ATLASSERT(SUCCEEDED(hr)); } if (FAILED(hr)) pT->RevokeClassObjects(); } else { m_bDelayShutdown = false; } #endif // _ATL_NO_COM_SUPPORT ATLASSERT(SUCCEEDED(hr)); return hr; } }; extern CUsdPythonToolsLocalServerModule g_AtlModule; extern HMODULE g_hInstance; // Helpful for debugging zombie processes. // Set to the last method that was called in IUSDTools extern CString g_DebugIUsdPythonToolsMethod; #define DEBUG_RECORD_ENTRY() \ g_DebugIUsdPythonToolsMethod = _T(__FUNCTION__) ================================================ FILE: UsdPythonToolsServer/UsdPythonToolsImpl.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "UsdPythonToolsImpl.h" #include "Module.h" #include "shared\PythonUtil.h" #include "shared\emb.h" #include "shared\environment.h" #include "shared\EventViewerLog.h" #include "UsdPythonToolsLocalServer_h.h" #include HRESULT CUsdPythonToolsImpl::FinalConstruct() { SetupPythonEnvironment( g_hInstance ); return __super::FinalConstruct(); } void CUsdPythonToolsImpl::FinalRelease() { __super::FinalRelease(); } static std::wstring FindRelativeFile(LPCWSTR sToolFileName) { const std::vector &PathList = GetUsdPathList(); for ( const CString &sDir : PathList ) { TCHAR sFilePath[512]; _tcscpy_s( sFilePath, sDir.GetString() ); ::PathCchAppend( sFilePath, ARRAYSIZE( sFilePath ), sToolFileName ); DWORD nAttribs = ::GetFileAttributes( sFilePath ); if ( (nAttribs != INVALID_FILE_ATTRIBUTES) && !(nAttribs & FILE_ATTRIBUTE_DIRECTORY) ) return sFilePath; } return L""; } static FILE *OpenRelativeFile(LPCWSTR sToolFileName, std::wstring& sOutFilePath) { sOutFilePath = FindRelativeFile( sToolFileName ); FILE *fp = _wfsopen( sOutFilePath.c_str(), L"rb", _SH_SECURE ); if ( fp == nullptr ) return nullptr; return fp; } static HRESULT RunDiskPythonScript( LPCWSTR sToolFileName, std::vector &ArgV, std::string &sStdOut, int& exitCode ) { exitCode = 0; std::wstring sFilePath; FILE *fp = OpenRelativeFile( sToolFileName, sFilePath ); if (fp == nullptr) return E_FAIL; fseek( fp, 0, SEEK_END ); int sizeOfFile = ftell( fp ); fseek( fp, 0, SEEK_SET ); CStringA pyScript; LPSTR pScriptData = pyScript.GetBufferSetLength( sizeOfFile ); fread( pScriptData, 1, sizeOfFile, fp ); pyScript.ReleaseBuffer( sizeOfFile ); fclose( fp ); fp = nullptr; PyImport_AppendInittab("emb", emb::PyInit_emb); CPyInterpreter pyInterpreter; PyImport_ImportModule("emb"); emb::stdout_write_type writeStdOut = [&sStdOut] (std::string s) { sStdOut += s; }; emb::set_stdout(writeStdOut); emb::stdout_write_type writeStdErr = [&sStdOut] (std::string s) { sStdOut += s; }; emb::set_stderr(writeStdErr); PyAppendSysPath( GetUsdPythonPathList() ); PySetEnvironmentVariable( L"PATH", GetUsdPath() ); PySetEnvironmentVariable( L"PYTHONPATH", GetUsdPythonPath() ); PySys_SetArgvEx( static_cast(ArgV.size()), const_cast(&ArgV[0]), 1 ); PyObject* pMainModule = PyImport_AddModule("__main__"); PyObject* pGlobalDict = PyModule_GetDict(pMainModule); CPyObject result = CPyObject( PyRun_String( pyScript.GetString(), Py_file_input, pGlobalDict, pGlobalDict ) ); HRESULT hr = S_OK; if ( PyErr_Occurred() ) { CPyException e; if ( !e.IsExceptionSystemExit() ) { CString sErrorMsg = e.tracebackW(); if ( sErrorMsg.IsEmpty() ) sErrorMsg.Format( _T( "[Error]\n%hs" ), e.what() ); if ( !sStdOut.empty() ) sErrorMsg.AppendFormat( _T( "\n\n[STDOUT]\n%hs" ), sStdOut.c_str() ); LogEventMessage( PYTHONTOOLS_CATEGORY, sErrorMsg.GetString(), LogEventType::Error ); hr = E_FAIL; } else { PySystemExitObject* pSystemExitObject = reinterpret_cast(e.GetValue()); if ( pSystemExitObject && pSystemExitObject->code ) { if ( PyLong_Check( pSystemExitObject->code ) ) { exitCode = PyLong_AsLong( pSystemExitObject->code ); } else if ( PyUnicode_Check( pSystemExitObject->code ) ) { // unexpected sStdOut += e.what(); exitCode = -1; LogEventMessage( PYTHONTOOLS_CATEGORY, e.whatW(), LogEventType::Error ); hr = E_FAIL; } } } } emb::reset_stdout(); emb::reset_stderr(); return hr; } static HRESULT RunResourcePythonScript( UINT nResourceId, std::vector &ArgV, std::string &sStdOut, int& exitCode ) { exitCode = 0; HRSRC hrscPy = ::FindResource( g_hInstance, MAKEINTRESOURCE( nResourceId ), _T("PYTHON") ); if ( hrscPy == nullptr ) return E_FAIL; HGLOBAL hPy = ::LoadResource( g_hInstance, hrscPy ); if ( hPy == nullptr ) return E_FAIL; void* pScriptData = ::LockResource( hPy ); if ( pScriptData == nullptr ) return E_FAIL; DWORD nSize = SizeofResource( g_hInstance, hrscPy ); CStringA pyScript; pyScript.SetString( reinterpret_cast(pScriptData), nSize ); PyImport_AppendInittab("emb", emb::PyInit_emb); CPyInterpreter pyInterpreter; PyImport_ImportModule("emb"); emb::stdout_write_type writeStdOut = [&sStdOut] (std::string s) { sStdOut += s; }; emb::set_stdout(writeStdOut); emb::stdout_write_type writeStdErr = [&sStdOut] (std::string s) { sStdOut += s; }; emb::set_stderr(writeStdErr); PyAppendSysPath( GetUsdPythonPathList() ); PySetEnvironmentVariable( L"PATH", GetUsdPath() ); PySetEnvironmentVariable( L"PYTHONPATH", GetUsdPythonPath() ); PySys_SetArgvEx( static_cast(ArgV.size()), const_cast(&ArgV[0]), 1 ); PyObject* pMainModule = PyImport_AddModule("__main__"); PyObject* pGlobalDict = PyModule_GetDict(pMainModule); CPyObject result = CPyObject( PyRun_String( pyScript.GetString(), Py_file_input, pGlobalDict, pGlobalDict ) ); HRESULT hr = S_OK; if ( PyErr_Occurred() ) { CPyException e; if ( !e.IsExceptionSystemExit() ) { CString sErrorMsg = e.tracebackW(); if ( sErrorMsg.IsEmpty() ) sErrorMsg.Format( _T( "[Error]\n%hs" ), e.what() ); if ( !sStdOut.empty() ) sErrorMsg.AppendFormat( _T( "\n\n[STDOUT]\n%hs" ), sStdOut.c_str() ); LogEventMessage( PYTHONTOOLS_CATEGORY, sErrorMsg.GetString(), LogEventType::Error ); hr = E_FAIL; } else { PySystemExitObject* pSystemExitObject = reinterpret_cast(e.GetValue()); if ( pSystemExitObject && pSystemExitObject->code ) { if ( PyLong_Check( pSystemExitObject->code ) ) { exitCode = PyLong_AsLong( pSystemExitObject->code ); } else if ( PyUnicode_Check( pSystemExitObject->code ) ) { // unexpected sStdOut += e.what(); exitCode = -1; LogEventMessage( PYTHONTOOLS_CATEGORY, e.whatW(), LogEventType::Error ); hr = E_FAIL; } } } } emb::reset_stdout(); emb::reset_stderr(); return hr; } STDMETHODIMP CUsdPythonToolsImpl::Record( IN BSTR usdStagePath, IN int imageWidth, IN BSTR renderer, OUT BSTR *outputImagePath ) { DEBUG_RECORD_ENTRY(); HRESULT hr; TPyChar sPathToHostExe[MAX_PATH]; #if PY_MAJOR_VERSION >= 3 ::GetModuleFileNameW( nullptr, sPathToHostExe, ARRAYSIZE( sPathToHostExe ) ); #else ::GetModuleFileNameA( nullptr, sPathToHostExe, ARRAYSIZE( sPathToHostExe ) ); #endif Py_SetProgramName( sPathToHostExe ); wchar_t sTempPath[MAX_PATH]; ::GetTempPathW( ARRAYSIZE( sTempPath ), sTempPath ); wchar_t sTempFileName[MAX_PATH]; // search for a unique temp file name std::vector tempFileList; for ( ;; ) { ::GetTempFileNameW( sTempPath, L"usd", 0, sTempFileName ); tempFileList.push_back( sTempFileName ); ::PathCchRenameExtension( sTempFileName, ARRAYSIZE( sTempFileName ), L"png" ); if ( GetFileAttributesW( sTempFileName ) == INVALID_FILE_ATTRIBUTES ) break; } // delete the temp files that GetTempFileNameW created for ( const CStringW &str : tempFileList ) DeleteFileW( str ); std::string sStdOut; CStringW sImageWidth; sImageWidth.Format( L"%d", imageWidth ); // locate usdrecord std::wstring sUsdRecordAbsolutePath = FindRelativeFile( L"usdrecord" ); if ( sUsdRecordAbsolutePath.empty() ) { LogEventMessage( PYTHONTOOLS_CATEGORY, L"Failed to locate usdrecord", LogEventType::Error ); return E_FAIL; } std::vector ArgV; // Set the first argument as the absolute path to the usdrecord python script // We will use argv[0] to load it using importlib CW2Py pyUsdRecordAbsolutePath( sUsdRecordAbsolutePath.c_str() ); ArgV.push_back( pyUsdRecordAbsolutePath ); ArgV.push_back( _Tpy("--imageWidth") ); CW2Py pyImageWidth( sImageWidth ); ArgV.push_back( pyImageWidth ); CW2Py pyRenderer(renderer); if ( renderer != nullptr && renderer[0] != '\0' ) { ArgV.push_back( _Tpy("--renderer") ); ArgV.push_back( pyRenderer ); } CW2Py pyUsdStagePath(usdStagePath); ArgV.push_back( pyUsdStagePath ); CW2Py pyTempFileName(sTempFileName); ArgV.push_back( pyTempFileName ); int exitCode = 0; hr = RunResourcePythonScript( IDR_PYTHON_THUMBNAIL, ArgV, sStdOut, exitCode ); if ( FAILED( hr ) ) return hr; if ( exitCode != 0 ) { CString sErrorMsg; sErrorMsg.Format( _T( "Error generating thumbnail for %ls\n\n%hs\n\nExit Code: %d" ), usdStagePath, sStdOut.c_str(), exitCode ); LogEventMessage( PYTHONTOOLS_CATEGORY, sErrorMsg.GetString(), LogEventType::Error ); return E_FAIL; } CComBSTR bstrOutputFile( sTempFileName ); *outputImagePath = bstrOutputFile.Detach(); return S_OK; } STDMETHODIMP CUsdPythonToolsImpl::View( IN BSTR usdStagePath, IN BSTR renderer ) { DEBUG_RECORD_ENTRY(); HRESULT hr; TPyChar sPathToHostExe[MAX_PATH]; #if PY_MAJOR_VERSION >= 3 ::GetModuleFileNameW( nullptr, sPathToHostExe, ARRAYSIZE( sPathToHostExe ) ); #else ::GetModuleFileNameA( nullptr, sPathToHostExe, ARRAYSIZE( sPathToHostExe ) ); #endif Py_SetProgramName( sPathToHostExe ); std::string sStdOut; std::vector ArgV; ArgV.push_back( sPathToHostExe ); CW2Py pyRenderer(renderer); if ( renderer != nullptr && renderer[0] != '\0' ) { ArgV.push_back( _Tpy("--renderer") ); ArgV.push_back( pyRenderer ); } CW2Py pyUsdStagePath(usdStagePath); ArgV.push_back( pyUsdStagePath ); int exitCode = 0; hr = RunDiskPythonScript( L"usdview", ArgV, sStdOut, exitCode ); if ( FAILED( hr ) ) return hr; if ( exitCode != 0 ) { CString sErrorMsg; sErrorMsg.Format( _T( "Error launching usdview for %ls\n\n%hs\n\nExit Code: %d" ), usdStagePath, sStdOut.c_str(), exitCode ); LogEventMessage( PYTHONTOOLS_CATEGORY, sErrorMsg.GetString(), LogEventType::Error ); return E_FAIL; } return S_OK; } HRESULT WINAPI CUsdPythonToolsImpl::UpdateRegistry(_In_ BOOL bRegister) throw() { ATL::_ATL_REGMAP_ENTRY regMapEntries[] = { { L"APPID", L"{8777F2C4-2318-408A-85D8-F65E15811971}" }, { L"CLSID_USDPYTHONTOOLS", L"{67F43831-59C3-450E-8956-AA76273F3E9F}" }, { nullptr, nullptr } }; return g_AtlModule.UpdateRegistryFromResource(IDR_REGISTRY_USDTOOLSIMPL, bRegister, regMapEntries); } ================================================ FILE: UsdPythonToolsServer/UsdPythonToolsImpl.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "UsdPythonToolsLocalServer_h.h" #include "resource.h" class ATL_NO_VTABLE CUsdPythonToolsImpl : public IDispatchImpl, public CComObjectRootEx, public CComCoClass { public: DECLARE_NOT_AGGREGATABLE(CUsdPythonToolsImpl) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP( CUsdPythonToolsImpl ) COM_INTERFACE_ENTRY( IUsdPythonTools ) COM_INTERFACE_ENTRY2( IDispatch, IUsdPythonTools ) END_COM_MAP() HRESULT FinalConstruct(); void FinalRelease(); STDMETHODIMP Record( IN BSTR usdStagePath, IN int imageWidth, IN BSTR renderer, OUT BSTR *outputImagePath ) override; STDMETHODIMP View( IN BSTR usdStagePath, IN BSTR renderer ) override; static HRESULT WINAPI UpdateRegistry(_In_ BOOL bRegister) throw(); private: }; OBJECT_ENTRY_AUTO( __uuidof(UsdPythonTools), CUsdPythonToolsImpl ) ================================================ FILE: UsdPythonToolsServer/UsdPythonToolsImpl.rgs ================================================ HKCR { NoRemove CLSID { ForceRemove %CLSID_USDPYTHONTOOLS% = s 'Activision USD Python Tools Server' { LocalServer32 = s '%MODULE%' val AppID = s '%APPID%' } } } ================================================ FILE: UsdPythonToolsServer/UsdPythonToolsLocalServer.idl ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import "oaidl.idl"; import "ocidl.idl"; [ uuid(88D2DCD9-4E41-49B1-B49A-4BD2942FE737), helpstring("UsdPythonTools Type Library"), version(1.0), ] library UsdPythonToolsLib { [ uuid(A73B8191-52C6-416E-ADAF-B2D1572CB0FE) ] struct UsdVariantPair { BSTR key; VARIANT value; }; [ uuid(36B7B0A6-E4FC-4728-86C1-05AFD6CFCA52), object, nonextensible, oleautomation, helpstring("IUsdPythonTools interface"), dual ] interface IUsdPythonTools : IDispatch { [helpstring("Launches usdrecord to generate a thumbnail of a USD stage.")] HRESULT Record( [in] BSTR usdStagePath, [in] int imageWidth, [in, optional] BSTR renderer, [out, retval] BSTR* outputImagePath ); [helpstring("Launches usdview for a given USD stage.")] HRESULT View( [in] BSTR usdStagePath, [in, optional] BSTR renderer ); } [ uuid(67F43831-59C3-450E-8956-AA76273F3E9F), helpstring("UsdPythonTools Server implementation") ] coclass UsdPythonTools { [default] interface IUsdPythonTools; } }; ================================================ FILE: UsdPythonToolsServer/UsdPythonToolsLocalServer.rc ================================================ // Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "1 TYPELIB ""USDPythonToolsLocalServer.tlb""\r\n" "\r\n" "#define ATVI_VERSION_DESCRIPTION ""Activision USD Python Tools Server""\r\n" "#include ""atviversion.rc2""\r\n" "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // REGISTRY // IDR_REGISTRY_MODULE REGISTRY "USDPythonToolsLocalServerModule.rgs" IDR_REGISTRY_USDTOOLSIMPL REGISTRY "UsdPythonToolsImpl.rgs" ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ICON_USD ICON "shared\\usd.ico" ///////////////////////////////////////////////////////////////////////////// // // PYTHON // IDR_PYTHON_THUMBNAIL PYTHON "UsdThumbnail.py" #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // 1 TYPELIB "USDPythonToolsLocalServer.tlb" #define ATVI_VERSION_DESCRIPTION "Activision USD Python Tools Server" #include "atviversion.rc2" ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: UsdPythonToolsServer/UsdPythonToolsLocalServer.vcxproj ================================================ Debug x64 Release x64 16.0 Win32Proj {6AD79C79-3A9D-4C39-B028-C45072541C28} UsdPythonToolsLocalServer 10.0.14393.0 Application true v141 false Unicode Application false v141 false Unicode RegistryView.Registry32 RegistryView.Registry64 $(PythonVersion)-32 $(PythonVersion) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $(PythonHome)python.exe $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) _d $([System.IO.Path]::GetDirectoryName($(PythonExe)))\python$(PythonDebugSuffix).exe $(PythonExe) false $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ true false $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ true Level3 true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true true true Level3 true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true true true Level4 true true true _WINDOWS;_DEBUG;%(PreprocessorDefinitions) false Use Disabled MultiThreadedDebugDLL $(SolutionDir);$(PythonHome)include;%(AdditionalIncludeDirectories) Disabled Windows false false true $(PythonHome)libs;%(AdditionalLibraryDirectories) Pathcch.lib;%(AdditionalDependencies) $(OutDir);$(SolutionDir);%(AdditionalIncludeDirectories) %(Filename)_i.c false true 0 All $(OutDir)$(ProjectName).tlb %(Command) Level4 true true true _WINDOWS;NDEBUG;%(PreprocessorDefinitions) false Use $(SolutionDir);$(PythonHome)include;%(AdditionalIncludeDirectories) MaxSpeed AnySuitable Windows false false true $(PythonHome)libs;%(AdditionalLibraryDirectories) Pathcch.lib;%(AdditionalDependencies) $(OutDir);$(SolutionDir);%(AdditionalIncludeDirectories) %(Filename)_i.c false true 0 All $(OutDir)$(ProjectName).tlb %(Command) Create Create NotUsing NotUsing {f12e597b-b731-4f5a-bec3-980d20159320} ================================================ FILE: UsdPythonToolsServer/UsdPythonToolsLocalServer.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {a27a5032-5dc7-4c59-b490-e65c0cc5fee0} Header Files Header Files Header Files Header Files Header Files Shared Shared Shared Shared Source Files Source Files Source Files Source Files Shared Shared Resource Files Resource Files Source Files Resource Files Shared Resource Files ================================================ FILE: UsdPythonToolsServer/UsdPythonToolsLocalServerModule.rgs ================================================ HKCU { NoRemove AppID { '%APPID%' = s 'UsdPythonToolsLocalServer' 'UsdPythonToolsLocalServer.exe' { val AppID = s '%APPID%' } } } ================================================ FILE: UsdPythonToolsServer/UsdThumbnail.py ================================================ # Copyright 2021 Activision Publishing, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This is a fix for USD issue #1521 # https://github.com/PixarAnimationStudios/USD/issues/1521 import sys try: from importlib.util import spec_from_loader, module_from_spec from importlib.machinery import SourceFileLoader except ImportError: import imp def _SetupOpenGLContextFix(width=100, height=100): try: from PySide2 import QtOpenGL from PySide2.QtWidgets import QApplication from PySide2 import QtCore # Activision Change except ImportError: from PySide import QtOpenGL from PySide.QtGui import QApplication from PySide import QtCore # Activision Change application = QApplication(sys.argv) glFormat = QtOpenGL.QGLFormat() glFormat.setSampleBuffers(True) glFormat.setSamples(4) glWidget = QtOpenGL.QGLWidget(glFormat) glWidget.setFixedSize(width, height) # BEGIN - Activision Change glWidget.setAttribute( QtCore.Qt.WA_DontShowOnScreen ) # END - Activision Change glWidget.show() glWidget.setHidden(True) return glWidget def main(): try: spec = spec_from_loader("usdrecord", SourceFileLoader("usdrecord", sys.argv[0])) usdrecord = module_from_spec(spec) spec.loader.exec_module(usdrecord) except: usdrecord = imp.load_source('usdrecord', sys.argv[0]) usdrecord._SetupOpenGLContext = _SetupOpenGLContextFix return usdrecord.main() if __name__ == '__main__': sys.exit(main()) ================================================ FILE: UsdPythonToolsServer/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by UsdPythonToolsLocalServer.rc // #define IDR_REGISTRY_MODULE 101 #define IDR_REGISTRY_USDTOOLSIMPL 102 #define IDI_ICONUSD 106 #define IDI_ICON_USD 106 #define IDR_PYTHON_PREVIEWHANLDER 107 #define IDR_REGISTRY_THUMBNAILIMPL 108 #define IDR_REGISTRY_USDTHUMBNAILIMPL 108 #define IDD_DIALOG1 109 #define IDR_PYTHON1 111 #define IDR_PYTHON_THUMBNAIL 111 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 112 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1004 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: UsdPythonToolsServer/stdafx.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" ================================================ FILE: UsdPythonToolsServer/stdafx.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #ifndef STRICT #define STRICT #endif #pragma warning(push) #pragma warning(disable: 4244 4459) #include #include #include #include #pragma warning(pop) #include #define _WIN32_WINNT 0x0A00 #include #define _ATL_APARTMENT_THREADED #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit #define ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW // Use the C++ standard templated min/max #define NOMINMAX #define NOBITMAP // Include if you need this #define NOMCX // Include if you need this #define NOSERVICE #include #include #include #include #include #include #include #include #include #include #include ================================================ FILE: UsdSdkToolsServer/Module.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "Module.h" HMODULE g_hInstance; CUsdSdkToolsLocalServerModule g_AtlModule; CString g_DebugIUsdSdkToolsMethod; extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd) { UNREFERENCED_PARAMETER( hPrevInstance ); UNREFERENCED_PARAMETER( lpCmdLine ); UNREFERENCED_PARAMETER( nShowCmd ); g_hInstance = hInstance; int nResult = g_AtlModule.WinMain( nShowCmd ); return nResult; } ================================================ FILE: UsdSdkToolsServer/Module.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "UsdSdkToolsLocalServer_h.h" #include "resource.h" // Using an ATL module here because it removes a lot of the // boiler-plate COM work that we would have to implement ourselves. class CUsdSdkToolsLocalServerModule : public CAtlExeModuleT { public: DECLARE_LIBID( LIBID_UsdSdkToolsLib ) DECLARE_REGISTRY_APPID_RESOURCEID( IDR_REGISTRY_MODULE, "{123A65E6-B4B4-4B46-BEF5-D0FCE7173261}" ) // Override CAtlExeModuleT::PreMessageLoop to change REGCLS_MULTIPLEUSE to REGCLS_SINGLEUSE. // REGCLS_SINGLEUSE will create a new Windows process for every instance of our COM classes, // REGCLS_MULTIPLEUSE will reuse the same Windows process. HRESULT PreMessageLoop( _In_ int /*nShowCmd*/ ) throw() { HRESULT hr = S_OK; CUsdSdkToolsLocalServerModule* pT = static_cast(this); #ifndef _ATL_NO_COM_SUPPORT hr = pT->RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE | // <- !!! REGCLS_SUSPENDED); if (FAILED(hr)) return hr; if (hr == S_OK) { if (m_bDelayShutdown) { CHandle h(pT->StartMonitor()); if (h.m_h == NULL) { hr = E_FAIL; } else { hr = CoResumeClassObjects(); ATLASSERT(SUCCEEDED(hr)); if (FAILED(hr)) { ::SetEvent(m_hEventShutdown); // tell monitor to shutdown ::WaitForSingleObject(h, m_dwTimeOut * 2); } } } else { hr = CoResumeClassObjects(); ATLASSERT(SUCCEEDED(hr)); } if (FAILED(hr)) pT->RevokeClassObjects(); } else { m_bDelayShutdown = false; } #endif // _ATL_NO_COM_SUPPORT ATLASSERT(SUCCEEDED(hr)); return hr; } }; extern CUsdSdkToolsLocalServerModule g_AtlModule; extern HMODULE g_hInstance; // Helpful for debugging zombie processes. // Set to the last method that was called in IUsdSdkTools extern CString g_DebugIUsdSdkToolsMethod; #define DEBUG_RECORD_ENTRY() \ g_DebugIUsdSdkToolsMethod = _T(__FUNCTION__) ================================================ FILE: UsdSdkToolsServer/UsdSdkToolsImpl.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "UsdSdkToolsImpl.h" #include "Module.h" #include "shared\environment.h" #include "shared\EventViewerLog.h" #include HRESULT CUsdSdkToolsImpl::FinalConstruct() { SetupPythonEnvironment( g_hInstance ); return __super::FinalConstruct(); } void CUsdSdkToolsImpl::FinalRelease() { __super::FinalRelease(); } static void RegisterUsdPlugins() { static bool sUsdPluginsRegistered = false; static std::mutex sUsdPluginsRegisteredLock; std::lock_guard guard( sUsdPluginsRegisteredLock ); // Plugins should be registered only once per session. if( sUsdPluginsRegistered ) return; sUsdPluginsRegistered = true; TCHAR sModulePath[MAX_PATH]; GetModuleFileName( g_hInstance, sModulePath, ARRAYSIZE( sModulePath ) ); std::vector pathsToPlugInfo; // add the folder that contains the shell extension PathCchRemoveFileSpec( sModulePath, ARRAYSIZE( sModulePath ) ); pathsToPlugInfo.push_back( static_cast(ATL::CW2A(sModulePath, CP_UTF8)) ); // add the bare-bones usd plugins PathCchAppend( sModulePath, ARRAYSIZE( sModulePath ), L"usd" ); pathsToPlugInfo.push_back( static_cast(ATL::CW2A(sModulePath, CP_UTF8)) ); pxr::PlugRegistry::GetInstance().RegisterPlugins( pathsToPlugInfo ); pxr::ArSetPreferredResolver( "ArResolverShellExtension" ); } STDMETHODIMP CUsdSdkToolsImpl::Cat( IN BSTR usdStagePathInput, IN BSTR usdStagePathOuput, IN eUsdFormat formatOutput, IN VARIANT_BOOL flatten ) { DEBUG_RECORD_ENTRY(); RegisterUsdPlugins(); pxr::SdfLayer::FileFormatArguments fileFormat; if ( formatOutput == USD_FORMAT_USDA ) fileFormat["target"] = "usda"; else if ( formatOutput == USD_FORMAT_USDC ) fileFormat["target"] = "usdc"; if ( flatten == VARIANT_FALSE ) { std::string usdStagePathInputA = static_cast(ATL::CW2A( usdStagePathInput, CP_UTF8 )); pxr::SdfLayerRefPtr rootLayer = pxr::SdfLayer::OpenAsAnonymous( usdStagePathInputA, false ); if ( rootLayer == nullptr ) return E_FAIL; std::string usdStagePathOuputA = static_cast(ATL::CW2A( usdStagePathOuput, CP_UTF8 )); if ( !rootLayer->Export( usdStagePathOuputA, std::string(), fileFormat ) ) return E_FAIL; } else { std::string usdStagePathInputA = static_cast(ATL::CW2A( usdStagePathInput, CP_UTF8 )); pxr::UsdStageRefPtr stage = pxr::UsdStage::Open( usdStagePathInputA ); if ( stage == nullptr ) return E_FAIL; stage->Flatten(); std::string usdStagePathOuputA = static_cast(ATL::CW2A( usdStagePathOuput, CP_UTF8 )); if ( !stage->Export( usdStagePathOuputA, true, fileFormat ) ) return E_FAIL; } return S_OK; } STDMETHODIMP CUsdSdkToolsImpl::Edit( IN BSTR usdStagePath, IN VARIANT_BOOL force ) { DEBUG_RECORD_ENTRY(); RegisterUsdPlugins(); DWORD inputFileAttribs = GetFileAttributes( usdStagePath ); if ( inputFileAttribs == INVALID_FILE_ATTRIBUTES ) return E_INVALIDARG; std::string usdStagePathA = static_cast(ATL::CW2A( usdStagePath, CP_UTF8 )); pxr::SdfLayerRefPtr rootLayer = pxr::SdfLayer::OpenAsAnonymous( usdStagePathA, false ); if ( rootLayer == nullptr ) return E_FAIL; CStringW usdStagePathOuputW; usdStagePathOuputW = usdStagePath; usdStagePathOuputW += L"-edit.usda"; std::string exportString; if ( !rootLayer->ExportToString( &exportString ) ) return E_FAIL; std::ofstream fileOut(usdStagePathOuputW.GetString(), std::ofstream::out|std::ofstream::trunc); if (!fileOut.is_open()) return E_FAIL; fileOut << exportString; fileOut.close(); WIN32_FILE_ATTRIBUTE_DATA wfadBefore = {}; ::GetFileAttributesEx( usdStagePathOuputW, GetFileExInfoStandard, &wfadBefore ); // hide the file we're editing ::SetFileAttributes( usdStagePathOuputW, wfadBefore.dwFileAttributes | FILE_ATTRIBUTE_HIDDEN ); CStringW sEditor = GetUsdEditor(); if ( sEditor.IsEmpty() ) sEditor = L"notepad.exe"; CStringW sCommandLine; sCommandLine.Format( L"%s \"%s\"", sEditor.GetString(), usdStagePathOuputW.GetString() ); STARTUPINFO si = {}; si.cb = sizeof( si ); PROCESS_INFORMATION pi = {}; if ( !::CreateProcess( nullptr, sCommandLine.GetBuffer(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi ) ) { return E_FAIL; } ::WaitForSingleObject( pi.hProcess, INFINITE ); ::CloseHandle( pi.hProcess ); ::CloseHandle( pi.hThread ); WIN32_FILE_ATTRIBUTE_DATA wfadAfter = {}; ::GetFileAttributesEx( usdStagePathOuputW, GetFileExInfoStandard, &wfadAfter ); if ( ::CompareFileTime( &wfadAfter.ftLastWriteTime, &wfadBefore.ftLastWriteTime ) != 0 ) { if ( (inputFileAttribs & FILE_ATTRIBUTE_READONLY) ) { if ( force == VARIANT_FALSE ) { ::DeleteFileW( usdStagePathOuputW ); return S_OK; } ::SetFileAttributes( usdStagePath, inputFileAttribs & ~FILE_ATTRIBUTE_READONLY ); } std::ifstream fileIn(usdStagePathOuputW.GetString(), std::ifstream::in); if (!fileIn.is_open()) return E_FAIL; std::ostringstream importString; importString << fileIn.rdbuf(); fileIn.close(); if ( rootLayer->ImportFromString( importString.str() ) == false ) return E_FAIL; if ( rootLayer->Export( usdStagePathA ) == false ) return E_FAIL; } ::DeleteFileW( usdStagePathOuputW ); return S_OK; } static void pause() { std::cout << std::endl; std::cout << "Press any key to continue..." << std::endl; _getch(); } STDMETHODIMP CUsdSdkToolsImpl::Package( IN BSTR usdStagePathInput, IN BSTR usdStagePathOuput, IN eUsdPackageType packageType, IN VARIANT_BOOL verbose ) { DEBUG_RECORD_ENTRY(); // create and display a console if (AllocConsole()) { FILE *fout = nullptr; freopen_s(&fout, "CONOUT$", "w", stdout); FILE *ferr = nullptr; freopen_s(&ferr, "CONOUT$", "w", stderr); } SetConsoleTitleW( L"USD Package" ); // ask the user to press a key to exit atexit( pause ); RegisterUsdPlugins(); if ( verbose != VARIANT_FALSE ) pxr::TfDebug::SetDebugSymbolsByName( "USDUTILS_CREATE_USDZ_PACKAGE", 1 ); DWORD inputFileAttribs = GetFileAttributes( usdStagePathInput ); if ( inputFileAttribs == INVALID_FILE_ATTRIBUTES ) return E_INVALIDARG; std::string usdStagePathInputA = static_cast(ATL::CW2A( usdStagePathInput, CP_UTF8 )); std::string usdStagePathOuputA = static_cast(ATL::CW2A( usdStagePathOuput, CP_UTF8 )); if ( packageType == USD_PACKAGE_DEFAULT ) { if ( !pxr::UsdUtilsCreateNewUsdzPackage( pxr::SdfAssetPath( usdStagePathInputA ), usdStagePathOuputA ) ) return E_FAIL; } else if( packageType == USD_FORMAT_APPLE_ARKIT ) { if ( !pxr::UsdUtilsCreateNewARKitUsdzPackage( pxr::SdfAssetPath( usdStagePathInputA ), usdStagePathOuputA ) ) return E_FAIL; } else { return E_INVALIDARG; } return S_OK; } static void PrintDictionary( const pxr::VtDictionary &dict, int indent ) { for ( const std::pair& stat : dict ) { for ( int i = 0; i < indent; ++i ) std::cout << " "; if ( stat.second.GetTypeid() == typeid(pxr::VtDictionary) ) { std::cout << stat.first << std::endl; pxr::VtDictionary nestedDict = stat.second.Get(); PrintDictionary( nestedDict, indent + 1 ); } else { if ( stat.second.GetTypeid() == typeid(size_t) ) std::cout << stat.first << " = " << stat.second.Get() << std::endl; else if ( stat.second.GetTypeid() == typeid(double) ) std::cout << stat.first << " = " << stat.second.Get() << std::endl; else std::cout << stat.first << " = " << "[UNKNOWN TYPE]" << std::endl; } } } STDMETHODIMP CUsdSdkToolsImpl::DisplayStageStats( IN BSTR usdStagePath ) { DEBUG_RECORD_ENTRY(); // create and display a console if (AllocConsole()) { FILE *fout = nullptr; freopen_s(&fout, "CONOUT$", "w", stdout); FILE *ferr = nullptr; freopen_s(&ferr, "CONOUT$", "w", stderr); } SetConsoleTitleW( L"USD Stage Stats" ); // ask the user to press a key to exit atexit( pause ); RegisterUsdPlugins(); std::string sError; pxr::TfMallocTag::Initialize( &sError ); std::string usdStagePathA = static_cast(ATL::CW2A( usdStagePath, CP_UTF8 )); std::cout << usdStagePathA << std::endl; std::cout << std::endl; pxr::VtDictionary dictStats; pxr::UsdStageRefPtr stage = pxr::UsdUtilsComputeUsdStageStats( usdStagePathA, &dictStats ); if ( stage == nullptr ) return E_FAIL; PrintDictionary( dictStats, 0 ); return S_OK; } HRESULT WINAPI CUsdSdkToolsImpl::UpdateRegistry(_In_ BOOL bRegister) throw() { ATL::_ATL_REGMAP_ENTRY regMapEntries[] = { { L"APPID", L"{123A65E6-B4B4-4B46-BEF5-D0FCE7173261}" }, { L"CLSID_USDSDKTOOLS", L"{5F016739-AF12-4899-B710-3FB5C242A11D}" }, { nullptr, nullptr } }; return g_AtlModule.UpdateRegistryFromResource(IDR_REGISTRY_USDTOOLSIMPL, bRegister, regMapEntries); } ================================================ FILE: UsdSdkToolsServer/UsdSdkToolsImpl.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "UsdSdkToolsLocalServer_h.h" #include "resource.h" class ATL_NO_VTABLE CUsdSdkToolsImpl : public IDispatchImpl, public CComObjectRootEx, public CComCoClass { public: DECLARE_NOT_AGGREGATABLE(CUsdSdkToolsImpl) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP( CUsdSdkToolsImpl ) COM_INTERFACE_ENTRY( IUsdSdkTools ) COM_INTERFACE_ENTRY2( IDispatch, IUsdSdkTools ) END_COM_MAP() HRESULT FinalConstruct(); void FinalRelease(); STDMETHODIMP Cat( IN BSTR usdStagePathInput, IN BSTR usdStagePathOuput, IN eUsdFormat formatOutput = USD_FORMAT_INPUT, IN VARIANT_BOOL flatten = 0 ) override; STDMETHODIMP Edit( IN BSTR usdStagePath, IN VARIANT_BOOL force = 0 ) override; STDMETHODIMP Package( IN BSTR usdStagePathInput, IN BSTR usdStagePathOuput, IN eUsdPackageType packageType = USD_PACKAGE_DEFAULT, IN VARIANT_BOOL verbose = 0 ) override; STDMETHODIMP DisplayStageStats( IN BSTR usdStagePath ) override; static HRESULT WINAPI UpdateRegistry(_In_ BOOL bRegister) throw(); private: }; OBJECT_ENTRY_AUTO( __uuidof(UsdSdkTools), CUsdSdkToolsImpl ) ================================================ FILE: UsdSdkToolsServer/UsdSdkToolsImpl.rgs ================================================ HKCR { NoRemove CLSID { ForceRemove %CLSID_USDSDKTOOLS% = s 'Activision USD SDK Tools Server' { LocalServer32 = s '%MODULE%' val AppID = s '%APPID%' } } } ================================================ FILE: UsdSdkToolsServer/UsdSdkToolsLocalServer.idl ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import "oaidl.idl"; import "ocidl.idl"; typedef [uuid(B397354A-F5D9-4835-B584-9524749F7B63), helpstring("USD Format")] enum eUsdFormat { [helpstring("Same as input file")] USD_FORMAT_INPUT, [helpstring("ASCII")] USD_FORMAT_USDA, [helpstring("Crate")] USD_FORMAT_USDC, } eUsdFormat; typedef [uuid(266D173D-4142-4CA1-BF25-EC9BC61FDE6A), helpstring("USDZ Package Type")] enum eUsdPackageType { [helpstring("Default USDZ package.")] USD_PACKAGE_DEFAULT, [helpstring("Apple ARKit USDZ package.")] USD_FORMAT_APPLE_ARKIT } eUsdPackageType; [ uuid(F68344A7-0343-4064-8DA9-7A2ECF6C2D2A), object, nonextensible, oleautomation, helpstring("IUsdSdkTools interface"), dual ] interface IUsdSdkTools : IDispatch { [helpstring("Converts between the various USD file formats.")] HRESULT Cat( [in] BSTR usdStagePathInput, [in] BSTR usdStagePathOuput, [in, defaultvalue(USD_FORMAT_INPUT)] eUsdFormat formatOutput, [in, defaultvalue(0)] VARIANT_BOOL flatten); [helpstring("Launches a text editor for a given USD stage.")] HRESULT Edit( [in] BSTR usdStagePath, [in, defaultvalue(0)] VARIANT_BOOL forcewrite); [helpstring("Converts a USD stage to a USD package.")] HRESULT Package( [in] BSTR usdStagePathInput, [in] BSTR usdStagePathOuput, [in, defaultvalue(USD_PACKAGE_DEFAULT)] eUsdPackageType packageType, [in, defaultvalue(0)] VARIANT_BOOL verbose ); [helpstring("Displays stats about the USD stage.")] HRESULT DisplayStageStats( [in] BSTR usdStagePath ); } [ uuid(7704E595-537E-41A0-AF52-53EA2941A773), helpstring("UsdSdkTools Type Library"), version(1.0), ] library UsdSdkToolsLib { [ uuid(5F016739-AF12-4899-B710-3FB5C242A11D), helpstring("UsdSdkTools Server implementation") ] coclass UsdSdkTools { [default] interface IUsdSdkTools; } }; ================================================ FILE: UsdSdkToolsServer/UsdSdkToolsLocalServer.rc ================================================ // Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "1 TYPELIB ""UsdSdkToolsLocalServer.tlb""\r\n" "\r\n" "#define ATVI_VERSION_DESCRIPTION ""Activision USD SDK Tools Server""\r\n" "#include ""atviversion.rc2""\r\n" "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // REGISTRY // IDR_REGISTRY_MODULE REGISTRY "UsdSdkToolsLocalServerModule.rgs" IDR_REGISTRY_USDTOOLSIMPL REGISTRY "UsdSdkToolsImpl.rgs" ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ICON_USD ICON "shared\\usd.ico" #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // 1 TYPELIB "UsdSdkToolsLocalServer.tlb" #define ATVI_VERSION_DESCRIPTION "Activision USD SDK Tools Server" #include "atviversion.rc2" ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: UsdSdkToolsServer/UsdSdkToolsLocalServer.vcxproj ================================================ Debug x64 Release x64 16.0 Win32Proj {EA717BDA-3304-439B-BEC8-408D9CE9F3FB} UsdSdkToolsLocalServer 10.0.14393.0 Application true v141 false Unicode Application false v141 false Unicode RegistryView.Registry32 RegistryView.Registry64 $(PythonVersion)-32 $(PythonVersion) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $(PythonHome)python.exe $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) _d $([System.IO.Path]::GetDirectoryName($(PythonExe)))\python$(PythonDebugSuffix).exe $(PythonExe) false $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ true false $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ true Level3 true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true true true Level3 true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true true true Level4 true true true _WINDOWS;_DEBUG;%(PreprocessorDefinitions) false Use Disabled MultiThreadedDebugDLL $(SolutionDir);$(PythonHome)include;%(AdditionalIncludeDirectories) Disabled Windows false false true $(PythonHome)libs;%(AdditionalLibraryDirectories) Pathcch.lib;%(AdditionalDependencies) $(OutDir);$(SolutionDir);%(AdditionalIncludeDirectories) %(Filename)_i.c false true 0 All $(OutDir)$(ProjectName).tlb %(Command) Level4 true true true _WINDOWS;NDEBUG;%(PreprocessorDefinitions) false Use $(SolutionDir);$(PythonHome)include;%(AdditionalIncludeDirectories) MaxSpeed AnySuitable Windows false false true $(PythonHome)libs;%(AdditionalLibraryDirectories) Pathcch.lib;%(AdditionalDependencies) $(OutDir);$(SolutionDir);%(AdditionalIncludeDirectories) %(Filename)_i.c false true 0 All $(OutDir)$(ProjectName).tlb %(Command) Create Create NotUsing NotUsing {f12e597b-b731-4f5a-bec3-980d20159320} ================================================ FILE: UsdSdkToolsServer/UsdSdkToolsLocalServer.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {a27a5032-5dc7-4c59-b490-e65c0cc5fee0} Header Files Header Files Header Files Shared Shared Header Files Header Files Shared Source Files Source Files Shared Source Files Source Files Resource Files Resource Files Source Files Resource Files Shared Resource Files ================================================ FILE: UsdSdkToolsServer/UsdSdkToolsLocalServerModule.rgs ================================================ HKCU { NoRemove AppID { '%APPID%' = s 'UsdSdkToolsLocalServer' 'UsdSdkToolsLocalServer.exe' { val AppID = s '%APPID%' } } } ================================================ FILE: UsdSdkToolsServer/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by UsdSdkToolsLocalServer.rc // #define IDR_REGISTRY_MODULE 101 #define IDR_REGISTRY_USDTOOLSIMPL 102 #define IDI_ICONUSD 106 #define IDI_ICON_USD 106 #define IDR_PYTHON_PREVIEWHANLDER 107 #define IDR_REGISTRY_THUMBNAILIMPL 108 #define IDR_REGISTRY_USDTHUMBNAILIMPL 108 #define IDD_DIALOG1 109 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 111 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1004 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: UsdSdkToolsServer/stdafx.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" ================================================ FILE: UsdSdkToolsServer/stdafx.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #ifndef STRICT #define STRICT #endif #include #define _WIN32_WINNT 0x0A00 #include #define _ATL_APARTMENT_THREADED #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit #define ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW // Use the C++ standard templated min/max #define NOMINMAX #define NOBITMAP // Include if you need this #define NOMCX // Include if you need this #define NOSERVICE #include #include #pragma warning( push ) #pragma warning( disable : 4244 4305 5033 4100 4201 4245 4127 ) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #pragma warning( pop ) #include #include #include #include #include #include #include #include #include #include #include ================================================ FILE: UsdShellExtension/ArResolverShellExtension.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "ArResolverShellExtension.h" // NOTE // /Zc:inline- is set for this file in the vcxproj // Enabling /Zc:inline strips out USD plug-in registration // https://developercommunity.visualstudio.com/t/zcinline-removes-extern-symbols-inside-anonymous-n/914943 PXR_NAMESPACE_OPEN_SCOPE AR_DEFINE_RESOLVER(ArResolverShellExtension, ArResolver) std::shared_ptr ArResolverShellExtension::OpenAsset(const std::string& resolvedPath) { // Deny writes. // The shell extension is used by many processes and threads at the same time. // fopen on Windows will allow writes with reads FILE* f = _wfsopen( ATL::CA2W( resolvedPath.c_str(), CP_UTF8 ), L"rb", _SH_SECURE ); if (!f) { return nullptr; } return std::shared_ptr(new ArFilesystemAsset(f)); } PXR_NAMESPACE_CLOSE_SCOPE ================================================ FILE: UsdShellExtension/ArResolverShellExtension.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once PXR_NAMESPACE_OPEN_SCOPE class ArResolverShellExtension : public ArDefaultResolver { public: std::shared_ptr OpenAsset( const std::string &resolvedPath ) override; }; PXR_NAMESPACE_CLOSE_SCOPE ================================================ FILE: UsdShellExtension/Module.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "Module.h" #include "resource.h" #include "shared/EventViewerMessages.h" #include "shared/EventViewerLog.h" #include "shared/environment.h" #include #include HMODULE g_hInstance; CShellExtModule g_AtlModule; BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch ( ul_reason_for_call ) { case DLL_PROCESS_ATTACH: g_hInstance = hModule; break; } return g_AtlModule.DllMain( ul_reason_for_call, lpReserved ); } static bool s_bSilent = true; static bool s_bVerify = true; static std::vector TranslatePathsToList(LPCTSTR paths) { std::vector pathList; CString sPaths(paths); CString sToken; int pos = 0; sToken = sPaths.Tokenize(_T(";"), pos); if ( !sToken.IsEmpty() ) { while ( !sToken.IsEmpty() ) { pathList.push_back( sToken ); sToken = sPaths.Tokenize( _T( ";" ), pos ); } } else { pathList.push_back( paths ); } return pathList; } static bool GetPythonInstallationPath( LPTSTR sBuffer, DWORD nBufferSizeInChars ) { std::vector ConfigFileList = BuildConfigFileList( g_hInstance ); CStringW sPythonPath; GetPrivateProfileStringAndExpandEnvironmentStrings( L"PYTHON", L"PATH", L"", sPythonPath, ConfigFileList ); wcscpy_s( sBuffer, nBufferSizeInChars, sPythonPath ); if ( sBuffer[0] == '\0' ) { #if PY_MAJOR_VERSION >= 3 CString sPythonRegKeyInstallPath; sPythonRegKeyInstallPath.Format( _T( "SOFTWARE\\Python\\PythonCore\\%hs\\InstallPath" ), _CRT_STRINGIZE(PYTHONVERSION) ); LSTATUS ls; CRegKey regPythonInstallPath; ls = regPythonInstallPath.Open( HKEY_CURRENT_USER, sPythonRegKeyInstallPath, KEY_READ ); if ( ls != ERROR_SUCCESS ) return false; ULONG nChars = nBufferSizeInChars; ls = regPythonInstallPath.QueryStringValue( _T(""), sBuffer, &nChars ); if ( ls != ERROR_SUCCESS ) return false; #elif (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION == 7) _tcscpy_s(sBuffer, nBufferSizeInChars, _T("C:\\Python27\\")); #endif } else { std::vector pathList = TranslatePathsToList( sBuffer ); wcscpy_s( sBuffer, nBufferSizeInChars, pathList[0] ); } return true; } static bool VerifyPythonInstallation() { TCHAR sPython_Path[2048]; GetPythonInstallationPath( sPython_Path, ARRAYSIZE( sPython_Path ) ); #if PY_MAJOR_VERSION >= 3 ::PathCchAppend( sPython_Path, ARRAYSIZE(sPython_Path), _T( PYTHONDLL ) ); if ( ::GetFileAttributesW( sPython_Path ) == INVALID_FILE_ATTRIBUTES ) return false; #else DWORD nAttrib = ::GetFileAttributesW( sPython_Path ); if ( nAttrib == INVALID_FILE_ATTRIBUTES || (nAttrib & FILE_ATTRIBUTE_DIRECTORY) == 0 ) return false; #endif return true; } static bool VerifyPyOpenGLInstallation() { TCHAR sPython_Path[2048]; GetPythonInstallationPath( sPython_Path, ARRAYSIZE( sPython_Path ) ); ::PathCchAppend( sPython_Path, ARRAYSIZE(sPython_Path), L"Lib" ); ::PathCchAppend( sPython_Path, ARRAYSIZE(sPython_Path), L"site-packages" ); ::PathCchAppend( sPython_Path, ARRAYSIZE(sPython_Path), L"OpenGL" ); if ( ::GetFileAttributesW( sPython_Path ) == INVALID_FILE_ATTRIBUTES ) return false; return true; } static bool VerifyPySideInstallation() { TCHAR sPython_Path[2048]; GetPythonInstallationPath( sPython_Path, ARRAYSIZE( sPython_Path ) ); ::PathCchAppend( sPython_Path, ARRAYSIZE(sPython_Path), L"Lib" ); ::PathCchAppend( sPython_Path, ARRAYSIZE(sPython_Path), L"site-packages" ); ::PathCchAppend( sPython_Path, ARRAYSIZE(sPython_Path), L"PySide" ); if ( ::GetFileAttributesW( sPython_Path ) == INVALID_FILE_ATTRIBUTES ) return false; return true; } static bool VerifyPySide2Installation() { TCHAR sPython_Path[2048]; GetPythonInstallationPath( sPython_Path, ARRAYSIZE( sPython_Path ) ); ::PathCchAppend( sPython_Path, ARRAYSIZE(sPython_Path), L"Lib" ); ::PathCchAppend( sPython_Path, ARRAYSIZE(sPython_Path), L"site-packages" ); ::PathCchAppend( sPython_Path, ARRAYSIZE(sPython_Path), L"PySide2" ); if ( ::GetFileAttributesW( sPython_Path ) == INVALID_FILE_ATTRIBUTES ) return false; return true; } static HRESULT RegisterPropDescFile( LPCTSTR sFileName, UINT nResourceId ) { HRSRC hrscPd = ::FindResource( g_hInstance, MAKEINTRESOURCE( nResourceId ), _T("XML") ); if ( hrscPd == nullptr ) return E_INVALIDARG; HGLOBAL hPd = ::LoadResource( g_hInstance, hrscPd ); if ( hPd == nullptr ) return E_INVALIDARG; void* pXMLData = ::LockResource( hPd ); if ( pXMLData == nullptr ) return E_INVALIDARG; DWORD nSize = SizeofResource( g_hInstance, hrscPd ); CStringA sPropDesc; sPropDesc.SetString( reinterpret_cast(pXMLData), nSize ); TCHAR sPath[MAX_PATH]; ::GetModuleFileName( g_hInstance, sPath, ARRAYSIZE( sPath ) ); sPropDesc.Replace( "%MODULE%", ATL::CW2A( sPath, CP_UTF8 ) ); sPropDesc.Replace( "%LANGMODULE%", ATL::CW2A( sPath, CP_UTF8 ) ); sPropDesc.Replace( "%IDS_USD_PROPGROUP_USD_LABEL%", _CRT_STRINGIZE( IDS_USD_PROPGROUP_USD_LABEL ) ); sPropDesc.Replace( "%IDS_USD_DOCUMENTATION_LABEL%", _CRT_STRINGIZE( IDS_USD_DOCUMENTATION_LABEL ) ); sPropDesc.Replace( "%IDS_USD_DOCUMENTATION_INVITATIONTEXT%", _CRT_STRINGIZE( IDS_USD_DOCUMENTATION_INVITATIONTEXT ) ); sPropDesc.Replace( "%IDS_USD_DOCUMENTATION_MNEMONICS%", _CRT_STRINGIZE( IDS_USD_DOCUMENTATION_MNEMONICS ) ); sPropDesc.Replace( "%IDS_USD_CUSTOMLAYERDATA_LABEL%", _CRT_STRINGIZE( IDS_USD_CUSTOMLAYERDATA_LABEL ) ); sPropDesc.Replace( "%IDS_USD_CUSTOMLAYERDATA_MNEMONICS%", _CRT_STRINGIZE( IDS_USD_CUSTOMLAYERDATA_MNEMONICS ) ); ::PathCchRemoveFileSpec( sPath, ARRAYSIZE( sPath ) ); ::PathCchAppend( sPath, ARRAYSIZE( sPath ), sFileName ); std::ofstream fileOut( sPath, std::ofstream::out | std::ofstream::trunc | std::ofstream::binary ); if (!fileOut.is_open()) return E_FAIL; fileOut << sPropDesc; fileOut.close(); HRESULT hr; hr = PSRegisterPropertySchema( sPath ); return hr; } static HRESULT UnregisterPropDescFile( LPCTSTR sFileName ) { TCHAR sPath[MAX_PATH]; ::GetModuleFileName( g_hInstance, sPath, ARRAYSIZE( sPath ) ); ::PathCchRemoveFileSpec( sPath, ARRAYSIZE( sPath ) ); ::PathCchAppend( sPath, ARRAYSIZE( sPath ), sFileName ); HRESULT hr; hr = PSUnregisterPropertySchema( sPath ); return hr; } static HRESULT InstallEventSource() { TCHAR sPath[MAX_PATH]; ::GetModuleFileName( g_hInstance, sPath, ARRAYSIZE( sPath ) ); LSTATUS ls; CRegKey regEventLog; ls = regEventLog.Create( HKEY_LOCAL_MACHINE, _T( "System\\CurrentControlSet\\Services\\Eventlog\\Application\\" ) _T( EVENTLOG_SOURCE ) ); if ( ls != ERROR_SUCCESS ) return E_FAIL; DWORD TypesSupported = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; regEventLog.SetDWORDValue( _T( "TypesSupported" ), TypesSupported ); regEventLog.SetStringValue( _T( "EventMessageFile" ), sPath ); regEventLog.SetStringValue( _T( "CategoryMessageFile" ), sPath ); regEventLog.SetDWORDValue( _T( "CategoryCount" ), CATEGORY_COUNT ); return S_OK; } static HRESULT UninstallEventSource() { LSTATUS ls; CRegKey regEventLog; ls = regEventLog.Open( HKEY_LOCAL_MACHINE, _T( "System\\CurrentControlSet\\Services\\Eventlog\\Application" ) ); if ( ls != ERROR_SUCCESS ) return E_FAIL; ls = regEventLog.RecurseDeleteKey( _T( EVENTLOG_SOURCE ) ); if ( ls != ERROR_SUCCESS ) return E_FAIL; return S_OK; } // Called to register/install this shell extension. // Typically called from regsvr32.exe STDAPI DllRegisterServer() { HRESULT hr; if ( s_bVerify ) { if ( !VerifyPythonInstallation() ) { if ( s_bSilent == false ) { ::MessageBox( nullptr, _T( "Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " is not installed on this system. It is required to run this shell extension.\n\n" ) _T( "Download and install Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " from python.org" ), _T( "Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " Not Installed" ), MB_ICONERROR ); } return E_PYTHON_NOT_INSTALLED; } if ( !VerifyPyOpenGLInstallation() ) { if ( s_bSilent == false ) { ::MessageBox( nullptr, _T( "Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " pyOpenGL is not installed on this system. It is required to run this shell extension.\n\n" ) _T( "Run the following command from a Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " command prompt.\n\n" ) _T( "pip install pyOpenGL" ), _T( "Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " pyOpenGL Not Installed" ), MB_ICONERROR ); } return E_PYOPENGL_NOT_INSTALLED; } #if PY_MAJOR_VERSION >= 3 if ( !VerifyPySide2Installation() ) { if ( s_bSilent == false ) { ::MessageBox( nullptr, _T( "Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " pySide2 is not installed on this system. It is required to run this shell extension.\n\n" ) _T( "Run the following command from a Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " command prompt.\n\n" ) _T( "pip install pySide2" ), _T( "Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " pySide2 Not Installed" ), MB_ICONERROR ); } return E_PYSIDE2_NOT_INSTALLED; } #else if ( !VerifyPySideInstallation() ) { if ( s_bSilent == false ) { ::MessageBox( nullptr, _T( "Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " pySide is not installed on this system. It is required to run this shell extension.\n\n" ) _T( "Run the following command from a Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " command prompt.\n\n" ) _T( "pip install pySide" ), _T( "Python " ) _T( _CRT_STRINGIZE(PYTHONVERSION) ) _T( " pySide Not Installed" ), MB_ICONERROR ); } return E_PYSIDE2_NOT_INSTALLED; } #endif } hr = RegisterPropDescFile(_T("UsdPropertyKeys.propdesc"), IDR_XML_PROPDESC_USD); if ( FAILED( hr ) ) { if ( s_bSilent == false ) { CString sError; sError.Format( _T( "Failed to install UsdPropertyKeys.propdesc.\n\n" ) _T( "Error: 0x%.8X" ), hr ); ::MessageBox( nullptr, sError, _T( "PSRegisterPropertySchema Failed" ), MB_ICONERROR ); } return hr; } hr = InstallEventSource(); if ( FAILED( hr ) ) { return hr; } hr = g_AtlModule.DllRegisterServer( FALSE ); if ( FAILED( hr ) ) { return hr; } hr = g_AtlModule.UpdateRegistry( TRUE ); if ( FAILED( hr ) ) { return hr; } // notify the shell that we have updated handlers SHChangeNotify( SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL ); return S_OK; } // Called to unregister/uninstall this shell extension. // Typically called from regsvr32.exe /u STDAPI DllUnregisterServer() { g_AtlModule.DllUnregisterServer( FALSE ); g_AtlModule.UpdateRegistry( FALSE ); UnregisterPropDescFile( _T( "UsdPropertyKeys.propdesc" ) ); UninstallEventSource(); // notify the shell that we have updated handlers SHChangeNotify( SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL ); return S_OK; } // Called to return an instance of a COM class we registered STDAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, void **ppv ) { HRESULT hr = g_AtlModule.DllGetClassObject( rclsid, riid, ppv ); return hr; } // Called to determine if the DLL can be unloaded // True if all COM references are at 0 STDAPI DllCanUnloadNow() { return g_AtlModule.DllCanUnloadNow(); } STDAPI DllInstall( BOOL bInstall, PCWSTR pszCmdLine ) { CoInitialize( nullptr ); CCommandLineArgs args; args.argv = ::CommandLineToArgvW( pszCmdLine, &args.argc ); s_bSilent = false; for ( int arg = 0; arg < args.argc; ++arg ) { if ( _wcsicmp( args.argv[arg], L"-silent" ) == 0 ) s_bSilent = true; else if ( _wcsicmp( args.argv[arg], L"-s" ) == 0 ) s_bSilent = true; else if ( _wcsicmp( args.argv[arg], L"/silent" ) == 0 ) s_bSilent = true; else if ( _wcsicmp( args.argv[arg], L"/s" ) == 0 ) s_bSilent = true; else if ( _wcsicmp( args.argv[arg], L"-force" ) == 0 ) s_bVerify = false; else if ( _wcsicmp( args.argv[arg], L"-f" ) == 0 ) s_bVerify = false; else if ( _wcsicmp( args.argv[arg], L"/force" ) == 0 ) s_bVerify = false; else if ( _wcsicmp( args.argv[arg], L"/f" ) == 0 ) s_bVerify = false; } if ( bInstall ) return DllRegisterServer(); return DllUnregisterServer(); } HRESULT WINAPI CShellExtModule::UpdateRegistry( _In_ BOOL bRegister ) throw() { ATL::_ATL_REGMAP_ENTRY regMapEntries[] = { { L"IDS_FILE_USD", _CRT_WIDE(_CRT_STRINGIZE(IDS_FILE_USD)) }, { L"IDS_FILE_USDA", _CRT_WIDE(_CRT_STRINGIZE(IDS_FILE_USDA)) }, { L"IDS_FILE_USDC", _CRT_WIDE(_CRT_STRINGIZE(IDS_FILE_USDC)) }, { L"IDS_FILE_USDZ", _CRT_WIDE(_CRT_STRINGIZE(IDS_FILE_USDZ)) }, { L"IDI_ICON_USD", _CRT_WIDE(_CRT_STRINGIZE(IDI_ICON_USD)) }, { L"IDS_SHELL_VIEW", _CRT_WIDE(_CRT_STRINGIZE(IDS_SHELL_VIEW)) }, { L"IDS_SHELL_EDIT", _CRT_WIDE(_CRT_STRINGIZE(IDS_SHELL_EDIT)) }, { L"IDS_SHELL_CRATE", _CRT_WIDE(_CRT_STRINGIZE(IDS_SHELL_CRATE)) }, { L"IDS_SHELL_UNCRATE", _CRT_WIDE(_CRT_STRINGIZE(IDS_SHELL_UNCRATE)) }, { L"IDS_SHELL_FLATTEN", _CRT_WIDE(_CRT_STRINGIZE(IDS_SHELL_FLATTEN)) }, { L"IDS_SHELL_REFRESHTHUMBNAIL", _CRT_WIDE(_CRT_STRINGIZE(IDS_SHELL_REFRESHTHUMBNAIL)) }, { L"IDS_SHELL_STATS", _CRT_WIDE(_CRT_STRINGIZE(IDS_SHELL_STATS)) }, { nullptr, nullptr } }; return g_AtlModule.UpdateRegistryFromResource(IDR_REGISTRY_MODULE, bRegister, regMapEntries); } ================================================ FILE: UsdShellExtension/Module.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "ShellExt_h.h" #include "resource.h" // Using an ATL module here because it removes a lot of the // boiler-plate COM work that we would have to implement ourselves. class CShellExtModule : public CAtlDllModuleT { public: DECLARE_LIBID( LIBID_UsdShellExtensionLib ) static HRESULT WINAPI UpdateRegistry(_In_ BOOL bRegister) throw(); }; extern CShellExtModule g_AtlModule; extern HMODULE g_hInstance; #define E_PYTHON_NOT_INSTALLED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0200) #define E_PYOPENGL_NOT_INSTALLED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0201) #define E_PYSIDE2_NOT_INSTALLED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0202) class CCommandLineArgs { public: ~CCommandLineArgs() { if ( argv ) LocalFree( argv ); } int argc = 0; LPWSTR *argv = nullptr; }; ================================================ FILE: UsdShellExtension/ShellExecute.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "Module.h" #pragma warning(push) #pragma warning(disable:4192 4278 4471) #import "UsdPythonToolsLocalServer.tlb" raw_interfaces_only #import "UsdSdkToolsLocalServer.tlb" raw_interfaces_only #pragma warning(pop) static bool GetRendererFromConfig( LPCTSTR system, CComBSTR &outBstr ) { TCHAR sModulePath[MAX_PATH]; ::GetModuleFileName( g_hInstance, sModulePath, ARRAYSIZE( sModulePath ) ); ::PathCchRenameExtension( sModulePath, ARRAYSIZE( sModulePath ), L"cfg" ); TCHAR sRenderer[128]; sRenderer[0] = '\0'; ::GetPrivateProfileString( _T( "RENDERER" ), system, _T( "" ), sRenderer, ARRAYSIZE( sRenderer ), sModulePath ); if ( sRenderer[0] == '\0' ) return false; outBstr = sRenderer; return true; } extern "C" __declspec(dllexport) void CALLBACK OpenInUsdViewW( HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow ) { UNREFERENCED_PARAMETER( hwnd ); UNREFERENCED_PARAMETER( hinst ); UNREFERENCED_PARAMETER( nCmdShow ); CoInitialize( nullptr ); HRESULT hr; CCommandLineArgs args; args.argv = ::CommandLineToArgvW( lpszCmdLine, &args.argc ); if ( args.argc < 1 ) return; if ( ::GetFileAttributesW( args.argv[0] ) == INVALID_FILE_ATTRIBUTES ) return; CComBSTR bstrRenderer; bool bRendererIsValid = GetRendererFromConfig( _T( "VIEW" ), bstrRenderer ); CComPtr pUsdPythonTools; hr = pUsdPythonTools.CoCreateInstance( __uuidof(UsdPythonToolsLib::UsdPythonTools) ); if ( FAILED( hr ) ) return; hr = pUsdPythonTools->View( CComBSTR(args.argv[0]), bRendererIsValid ? bstrRenderer : nullptr ); if ( FAILED( hr ) ) return; } extern "C" __declspec(dllexport) void CALLBACK CrateWithUsdCatW( HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow ) { UNREFERENCED_PARAMETER( hwnd ); UNREFERENCED_PARAMETER( hinst ); UNREFERENCED_PARAMETER( nCmdShow ); CoInitialize( nullptr ); HRESULT hr; CCommandLineArgs args; args.argv = ::CommandLineToArgvW( lpszCmdLine, &args.argc ); if ( args.argc < 1 ) return; if ( ::GetFileAttributesW( args.argv[0] ) == INVALID_FILE_ATTRIBUTES ) return; CComPtr pUSDTools; hr = pUSDTools.CoCreateInstance( __uuidof(UsdSdkToolsLib::UsdSdkTools) ); if ( FAILED( hr ) ) return; wchar_t sOutputFile[512]; wcscpy_s( sOutputFile, args.argv[0] ); PathCchRenameExtension( sOutputFile, ARRAYSIZE( sOutputFile ), L"usdc" ); hr = pUSDTools->Cat( CComBSTR(args.argv[0]), CComBSTR(sOutputFile), UsdSdkToolsLib::USD_FORMAT_USDC, VARIANT_FALSE ); if ( FAILED( hr ) ) { ::MessageBox( hwnd, _T( "USD Crate Error" ), _T( "USD Crate Error" ), MB_ICONERROR ); return; } } extern "C" __declspec(dllexport) void CALLBACK UncrateWithUsdCatW( HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow ) { UNREFERENCED_PARAMETER( hwnd ); UNREFERENCED_PARAMETER( hinst ); UNREFERENCED_PARAMETER( nCmdShow ); CoInitialize( nullptr ); HRESULT hr; CCommandLineArgs args; args.argv = ::CommandLineToArgvW( lpszCmdLine, &args.argc ); if ( args.argc < 1 ) return; if ( ::GetFileAttributesW( args.argv[0] ) == INVALID_FILE_ATTRIBUTES ) return; CComPtr pUSDTools; hr = pUSDTools.CoCreateInstance( __uuidof(UsdSdkToolsLib::UsdSdkTools) ); if ( FAILED( hr ) ) return; wchar_t sOutputFile[512]; wcscpy_s( sOutputFile, args.argv[0] ); PathCchRenameExtension( sOutputFile, ARRAYSIZE( sOutputFile ), L"usda" ); hr = pUSDTools->Cat( CComBSTR(args.argv[0]), CComBSTR(sOutputFile), UsdSdkToolsLib::USD_FORMAT_USDA, VARIANT_FALSE ); if ( FAILED( hr ) ) { ::MessageBox( hwnd, _T( "USD Uncrate Error" ), _T( "USD Uncrate Error" ), MB_ICONERROR ); return; } } extern "C" __declspec(dllexport) void CALLBACK FlattenWithUsdCatW( HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow ) { UNREFERENCED_PARAMETER( hwnd ); UNREFERENCED_PARAMETER( hinst ); UNREFERENCED_PARAMETER( nCmdShow ); CoInitialize( nullptr ); HRESULT hr; CCommandLineArgs args; args.argv = ::CommandLineToArgvW( lpszCmdLine, &args.argc ); if ( args.argc < 1 ) return; if ( ::GetFileAttributesW( args.argv[0] ) == INVALID_FILE_ATTRIBUTES ) return; CComPtr pUSDTools; hr = pUSDTools.CoCreateInstance( __uuidof(UsdSdkToolsLib::UsdSdkTools) ); if ( FAILED( hr ) ) return; hr = pUSDTools->Cat( CComBSTR(args.argv[0]), CComBSTR(args.argv[0]), UsdSdkToolsLib::USD_FORMAT_INPUT, VARIANT_TRUE ); if ( FAILED( hr ) ) { ::MessageBox( hwnd, _T( "USD Flatten Error" ), _T( "USD Flatten Error" ), MB_ICONERROR ); return; } } extern "C" __declspec(dllexport) void CALLBACK EditInUsdEditW( HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow ) { UNREFERENCED_PARAMETER( hwnd ); UNREFERENCED_PARAMETER( hinst ); UNREFERENCED_PARAMETER( nCmdShow ); CoInitialize( nullptr ); HRESULT hr; CCommandLineArgs args; args.argv = ::CommandLineToArgvW( lpszCmdLine, &args.argc ); if ( args.argc < 1 ) return; if ( ::GetFileAttributesW( args.argv[0] ) == INVALID_FILE_ATTRIBUTES ) return; CComPtr pUSDTools; hr = pUSDTools.CoCreateInstance( __uuidof(UsdSdkToolsLib::UsdSdkTools) ); if ( FAILED( hr ) ) return; hr = pUSDTools->Edit( CComBSTR(args.argv[0]), VARIANT_FALSE ); if ( FAILED( hr ) ) { ::MessageBox( hwnd, _T( "USD Edit Error" ), _T( "USD Edit Error" ), MB_ICONERROR ); return; } } extern "C" __declspec(dllexport) void CALLBACK RefreshThumbnailW( HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow ) { UNREFERENCED_PARAMETER( hwnd ); UNREFERENCED_PARAMETER( hinst ); UNREFERENCED_PARAMETER( nCmdShow ); CoInitialize( nullptr ); HRESULT hr; CCommandLineArgs args; args.argv = ::CommandLineToArgvW( lpszCmdLine, &args.argc ); if ( args.argc < 1 ) return; if ( ::GetFileAttributesW( args.argv[0] ) == INVALID_FILE_ATTRIBUTES ) return; CComPtr pShellItem; hr = ::SHCreateItemFromParsingName( args.argv[0], nullptr, IID_PPV_ARGS( &pShellItem.p ) ); if ( FAILED( hr ) ) return; CComPtr pThumbnailCache; hr = pThumbnailCache.CoCreateInstance( CLSID_LocalThumbnailCache ); if ( FAILED( hr ) ) return; // According to this old thread, force extraction of any size of thumbnail // should invalidate the entire cache for that IShellItem. // https://microsoft.public.platformsdk.shell.narkive.com/ABNbF5AQ/how-to-update-thumbnails-on-vista CComPtr pSharedBitmap; hr = pThumbnailCache->GetThumbnail( pShellItem, 256, WTS_FORCEEXTRACTION, &pSharedBitmap.p, nullptr, nullptr ); // Notify the shell that the item has changed. ::SHChangeNotify( SHCNE_UPDATEITEM, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, args.argv[0], nullptr ); } extern "C" __declspec(dllexport) void CALLBACK PackageDefaultW( HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow ) { UNREFERENCED_PARAMETER( hwnd ); UNREFERENCED_PARAMETER( hinst ); UNREFERENCED_PARAMETER( nCmdShow ); CoInitialize( nullptr ); HRESULT hr; CCommandLineArgs args; args.argv = ::CommandLineToArgvW( lpszCmdLine, &args.argc ); if ( args.argc < 1 ) return; if ( ::GetFileAttributesW( args.argv[0] ) == INVALID_FILE_ATTRIBUTES ) return; CComPtr pUSDTools; hr = pUSDTools.CoCreateInstance( __uuidof(UsdSdkToolsLib::UsdSdkTools) ); if ( FAILED( hr ) ) return; wchar_t sOutputFile[512]; wcscpy_s( sOutputFile, args.argv[0] ); PathCchRenameExtension( sOutputFile, ARRAYSIZE( sOutputFile ), L"usdz" ); hr = pUSDTools->Package( CComBSTR(args.argv[0]), CComBSTR(sOutputFile), UsdSdkToolsLib::USD_PACKAGE_DEFAULT, VARIANT_TRUE ); if ( FAILED( hr ) ) { ::MessageBox( hwnd, _T( "USD Package Error" ), _T( "USD Package Error" ), MB_ICONERROR ); return; } } extern "C" __declspec(dllexport) void CALLBACK PackageARKitW( HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow ) { UNREFERENCED_PARAMETER( hwnd ); UNREFERENCED_PARAMETER( hinst ); UNREFERENCED_PARAMETER( nCmdShow ); CoInitialize( nullptr ); HRESULT hr; CCommandLineArgs args; args.argv = ::CommandLineToArgvW( lpszCmdLine, &args.argc ); if ( args.argc < 1 ) return; if ( ::GetFileAttributesW( args.argv[0] ) == INVALID_FILE_ATTRIBUTES ) return; CComPtr pUSDTools; hr = pUSDTools.CoCreateInstance( __uuidof(UsdSdkToolsLib::UsdSdkTools) ); if ( FAILED( hr ) ) return; wchar_t sOutputFile[512]; wcscpy_s( sOutputFile, args.argv[0] ); PathCchRenameExtension( sOutputFile, ARRAYSIZE( sOutputFile ), L"usdz" ); hr = pUSDTools->Package( CComBSTR(args.argv[0]), CComBSTR(sOutputFile), UsdSdkToolsLib::USD_FORMAT_APPLE_ARKIT, VARIANT_TRUE ); if ( FAILED( hr ) ) { ::MessageBox( hwnd, _T( "USD Package Error" ), _T( "USD Package Error" ), MB_ICONERROR ); return; } } extern "C" __declspec(dllexport) void CALLBACK StageStatsW( HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow ) { UNREFERENCED_PARAMETER( hwnd ); UNREFERENCED_PARAMETER( hinst ); UNREFERENCED_PARAMETER( nCmdShow ); CoInitialize( nullptr ); HRESULT hr; CCommandLineArgs args; args.argv = ::CommandLineToArgvW( lpszCmdLine, &args.argc ); if ( args.argc < 1 ) return; if ( ::GetFileAttributesW( args.argv[0] ) == INVALID_FILE_ATTRIBUTES ) return; CComPtr pUSDTools; hr = pUSDTools.CoCreateInstance( __uuidof(UsdSdkToolsLib::UsdSdkTools) ); if ( FAILED( hr ) ) return; hr = pUSDTools->DisplayStageStats( CComBSTR(args.argv[0]) ); if ( FAILED( hr ) ) { ::MessageBox( hwnd, _T( "USD Stage Stats Error" ), _T( "USD Stage Stats Error" ), MB_ICONERROR ); return; } } ================================================ FILE: UsdShellExtension/ShellExt.def ================================================ EXPORTS DllRegisterServer PRIVATE DllUnregisterServer PRIVATE DllGetClassObject PRIVATE DllCanUnloadNow PRIVATE DllInstall PRIVATE ================================================ FILE: UsdShellExtension/ShellExt.idl ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import "oaidl.idl"; import "ocidl.idl"; import "ShObjIdl.idl"; import "thumbcache.idl"; [ uuid(B71120F9-A3EA-4153-8C32-C906CCE1F6F2), version(1.0), ] library UsdShellExtensionLib { [ uuid(0BCB74E0-5B61-4F24-BAB3-96CC76FE3672) ] coclass UsdContextMenu { [default] interface IContextMenu; }; [ uuid(2DEB1AB8-DECA-42C2-B576-3116D9CA8FA8), helpstring("USD IPreviewHandler implementation") ] coclass ShellPreviewHandler { [default] interface IPreviewHandler; } [ uuid(2877CB72-1427-43B0-A2B4-9CB1B2BA8C53), helpstring("USD IThumbnailProvider implementation") ] coclass ShellThumbnailProvider { [default] interface IThumbnailProvider; } [ uuid(5CE761D0-72AA-4484-B2BF-2A0EBF3ACC0C), helpstring("USD IPropertyStore implementation") ] coclass ShellPropertyStore { [default] interface IPropertyStore; } }; ================================================ FILE: UsdShellExtension/ShellExt.rc ================================================ // Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // Neutral (Default) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUD) LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT #pragma code_page(1252) #include "EventViewerMessages.rc" ///////////////////////////////////////////////////////////////////////////// // // REGISTRY // IDR_REGISTRY_SHELLPREVIEWHANDLERIMPL REGISTRY "ShellPreviewHandlerImpl.rgs" IDR_REGISTRY_SHELLTHUMBNAILPROVIDERIMPL REGISTRY "ShellThumbnailProviderImpl.rgs" IDR_REGISTRY_MODULE REGISTRY "ShellExtModule.rgs" IDR_REGISTRY_SHELLPROPERTYSTOREIMPL REGISTRY "ShellPropertyStoreImpl.rgs" ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ICON_USD ICON "usd.ico" ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_LOADSCREEN DIALOGEX 0, 0, 231, 130 STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN IDD_LOADSCREEN, DIALOG BEGIN LEFTMARGIN, 7 TOPMARGIN, 7 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // AFX_DIALOG_LAYOUT // IDD_LOADSCREEN AFX_DIALOG_LAYOUT BEGIN 0 END ///////////////////////////////////////////////////////////////////////////// // // PNG // IDB_LOADSCREEN PNG "USDLogoLrgWithAlpha.png" IDB_LOGO PNG "logo.png" ///////////////////////////////////////////////////////////////////////////// // // XML // IDR_XML_PROPDESC_USD XML "UsdPropertyKeys.propdesc" #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "1 TYPELIB ""UsdShellExtension.tlb""\r\n" "\r\n" "#define ATVI_VERSION_DESCRIPTION ""Activision USD Shell Extension""\r\n" "#include ""atviversion.rc2""\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE BEGIN IDS_USD_DOCUMENTATION_LABEL "Documentation" IDS_USD_DOCUMENTATION_INVITATIONTEXT "Add documentation" IDS_USD_DOCUMENTATION_MNEMONICS "usddocumentation|usddocs|usddoc" IDS_USD_PROPGROUP_USD_LABEL "Universal Scene Description" END STRINGTABLE BEGIN IDS_FILE_USD "Universal Scene Description" IDS_FILE_USDA "Universal Scene Description ASCII" IDS_FILE_USDC "Universal Scene Description Crate" IDS_FILE_USDZ "Universal Scene Description Package" IDS_SHELL_VIEW "&View" IDS_SHELL_EDIT "&Edit" END STRINGTABLE BEGIN IDS_SHELL_CRATE "&Crate" IDS_SHELL_UNCRATE "&Uncrate" IDS_SHELL_FLATTEN "&Flatten" IDS_SHELL_REFRESHTHUMBNAIL "&Refresh Thumbnail" IDS_SHELL_STATS "&Stats" IDS_USD_CUSTOMLAYERDATA_LABEL "Custom layer data" IDS_USD_CUSTOMLAYERDATA_MNEMONICS "usdcustomlayerdata|usdlayerdata" END #endif // Neutral (Default) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // 1 TYPELIB "UsdShellExtension.tlb" #define ATVI_VERSION_DESCRIPTION "Activision USD Shell Extension" #include "atviversion.rc2" ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: UsdShellExtension/ShellExtModule.rgs ================================================ HKCR { NoRemove ATVI.USD = s 'Activision Universal Scene Description' { ForceRemove val FriendlyTypeName = s '@%MODULE%,-%IDS_FILE_USD%' NoRemove shell { ForceRemove open = s '@%MODULE%,-%IDS_SHELL_VIEW%' { command = s 'rundll32.exe "%MODULE%",OpenInUsdView "%%1"' } ForceRemove edit = s '@%MODULE%,-%IDS_SHELL_EDIT%' { command = s 'rundll32.exe "%MODULE%",EditInUsdEdit "%%1"' } ForceRemove compress = s '@%MODULE%,-%IDS_SHELL_CRATE%' { command = s 'rundll32.exe "%MODULE%",CrateWithUsdCat "%%1"' } ForceRemove uncompress = s '@%MODULE%,-%IDS_SHELL_UNCRATE%' { command = s 'rundll32.exe "%MODULE%",UncrateWithUsdCat "%%1"' } ForceRemove flatten = s '@%MODULE%,-%IDS_SHELL_FLATTEN%' { command = s 'rundll32.exe "%MODULE%",FlattenWithUsdCat "%%1"' } ForceRemove thumbnail = s '@%MODULE%,-%IDS_SHELL_REFRESHTHUMBNAIL%' { command = s 'rundll32.exe "%MODULE%",RefreshThumbnail "%%1"' } ForceRemove stats = s '@%MODULE%,-%IDS_SHELL_STATS%' { command = s 'rundll32.exe "%MODULE%",StageStats "%%1"' } ForceRemove package { ForceRemove val ExtendedSubCommandsKey = s 'ATVI.USD\shell\package' ForceRemove val MUIVerb = s 'Package' ForceRemove Shell { ForceRemove Default { ForceRemove val MUIVerb = s 'Default' ForceRemove command = s 'rundll32.exe "%MODULE%",PackageDefault "%%1"' } ForceRemove ARKit { ForceRemove val MUIVerb = s 'Apple ARKit' ForceRemove command = s 'rundll32.exe "%MODULE%",PackageARKit "%%1"' } } } } ForceRemove DefaultIcon = s '%MODULE%,-%IDI_ICON_USD%' } NoRemove .usd { val PerceivedType = s 'document' NoRemove OpenWithProgids { ForceRemove val ATVI.USD = s 'Activision Universal Scene Description' } } NoRemove ATVI.USDA = s 'Activision Universal Scene Description ASCII' { ForceRemove val FriendlyTypeName = s '@%MODULE%,-%IDS_FILE_USDA%' NoRemove shell { ForceRemove open = s '@%MODULE%,-%IDS_SHELL_VIEW%' { command = s 'rundll32.exe "%MODULE%",OpenInUsdView "%%1"' } ForceRemove edit = s '@%MODULE%,-%IDS_SHELL_EDIT%' { command = s 'rundll32.exe "%MODULE%",EditInUsdEdit "%%1"' } ForceRemove compress = s '@%MODULE%,-%IDS_SHELL_CRATE%' { command = s 'rundll32.exe "%MODULE%",CrateWithUsdCat "%%1"' } ForceRemove flatten = s '@%MODULE%,-%IDS_SHELL_FLATTEN%' { command = s 'rundll32.exe "%MODULE%",FlattenWithUsdCat "%%1"' } ForceRemove thumbnail = s '@%MODULE%,-%IDS_SHELL_REFRESHTHUMBNAIL%' { command = s 'rundll32.exe "%MODULE%",RefreshThumbnail "%%1"' } ForceRemove stats = s '@%MODULE%,-%IDS_SHELL_STATS%' { command = s 'rundll32.exe "%MODULE%",StageStats "%%1"' } ForceRemove package { ForceRemove val ExtendedSubCommandsKey = s 'ATVI.USDA\shell\package' ForceRemove val MUIVerb = s 'Package' ForceRemove Shell { ForceRemove Default { ForceRemove val MUIVerb = s 'Default' ForceRemove command = s 'rundll32.exe "%MODULE%",PackageDefault "%%1"' } ForceRemove ARKit { ForceRemove val MUIVerb = s 'Apple ARKit' ForceRemove command = s 'rundll32.exe "%MODULE%",PackageARKit "%%1"' } } } } ForceRemove DefaultIcon = s '%MODULE%,-%IDI_ICON_USD%' } NoRemove .usda { val PerceivedType = s 'document' NoRemove OpenWithProgids { ForceRemove val ATVI.USDA = s 'Activision Universal Scene Description ASCII' } } NoRemove ATVI.USDC = s 'Activision Universal Scene Description Crate' { ForceRemove val FriendlyTypeName = s '@%MODULE%,-%IDS_FILE_USDC%' NoRemove shell { ForceRemove open = s '@%MODULE%,-%IDS_SHELL_VIEW%' { command = s 'rundll32.exe "%MODULE%",OpenInUsdView "%%1"' } ForceRemove edit = s '@%MODULE%,-%IDS_SHELL_EDIT%' { command = s 'rundll32.exe "%MODULE%",EditInUsdEdit "%%1"' } ForceRemove uncompress = s '@%MODULE%,-%IDS_SHELL_UNCRATE%' { command = s 'rundll32.exe "%MODULE%",UncrateWithUsdCat "%%1"' } ForceRemove flatten = s '@%MODULE%,-%IDS_SHELL_FLATTEN%' { command = s 'rundll32.exe "%MODULE%",FlattenWithUsdCat "%%1"' } ForceRemove thumbnail = s '@%MODULE%,-%IDS_SHELL_REFRESHTHUMBNAIL%' { command = s 'rundll32.exe "%MODULE%",RefreshThumbnail "%%1"' } ForceRemove stats = s '@%MODULE%,-%IDS_SHELL_STATS%' { command = s 'rundll32.exe "%MODULE%",StageStats "%%1"' } ForceRemove package { ForceRemove val ExtendedSubCommandsKey = s 'ATVI.USDC\shell\package' ForceRemove val MUIVerb = s 'Package' ForceRemove Shell { ForceRemove Default { ForceRemove val MUIVerb = s 'Default' ForceRemove command = s 'rundll32.exe "%MODULE%",PackageDefault "%%1"' } ForceRemove ARKit { ForceRemove val MUIVerb = s 'Apple ARKit' ForceRemove command = s 'rundll32.exe "%MODULE%",PackageARKit "%%1"' } } } } ForceRemove DefaultIcon = s '%MODULE%,-%IDI_ICON_USD%' } NoRemove .usdc { val PerceivedType = s 'document' NoRemove OpenWithProgids { ForceRemove val ATVI.USDC = s 'Activision Universal Scene Description Crate' } } NoRemove ATVI.USDZ = s 'Activision Universal Scene Description Package' { ForceRemove val FriendlyTypeName = s '@%MODULE%,-%IDS_FILE_USDZ%' NoRemove shell { ForceRemove open = s '@%MODULE%,-%IDS_SHELL_VIEW%' { command = s 'rundll32.exe "%MODULE%",OpenInUsdView "%%1"' } ForceRemove thumbnail = s '@%MODULE%,-%IDS_SHELL_REFRESHTHUMBNAIL%' { command = s 'rundll32.exe "%MODULE%",RefreshThumbnail "%%1"' } ForceRemove stats = s '@%MODULE%,-%IDS_SHELL_STATS%' { command = s 'rundll32.exe "%MODULE%",StageStats "%%1"' } } ForceRemove DefaultIcon = s '%MODULE%,-%IDI_ICON_USD%' } NoRemove .usdz { val PerceivedType = s 'document' NoRemove OpenWithProgids { ForceRemove val ATVI.USDZ = s 'Activision Universal Scene Description Package' } } } ================================================ FILE: UsdShellExtension/ShellPreviewHandlerImpl.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "ShellPreviewHandlerImpl.h" #include "Module.h" #include "resource.h" #pragma warning(push) #pragma warning(disable:4192 4278) #import "UsdPreviewLocalServer.tlb" raw_interfaces_only #pragma warning(pop) static RECT UpdateRectForDPI(HWND hwnd, const RECT& rcWnd) { #if 0 int iDpiProcess = static_cast(::GetSystemDpiForProcess( ::GetCurrentProcess() )); int iDpiWindow = static_cast(::GetDpiForWindow( hwnd )); RECT rcDpi; rcDpi.left = MulDiv(rcWnd.left, iDpiProcess, iDpiWindow); rcDpi.top = MulDiv(rcWnd.top, iDpiProcess, iDpiWindow); rcDpi.right = MulDiv(rcWnd.right, iDpiProcess, iDpiWindow); rcDpi.bottom = MulDiv(rcWnd.bottom, iDpiProcess, iDpiWindow); CStringA sDebug; sDebug.Format( "DPI: p:%d w:%d, {%d, %d, %d, %d} -> {%d, %d, %d, %d}\n", iDpiProcess, iDpiWindow, rcWnd.left, rcWnd.top, rcWnd.right - rcWnd.left, rcWnd.bottom - rcWnd.top, rcDpi.left, rcDpi.top, rcDpi.right - rcDpi.left, rcDpi.bottom - rcDpi.top ); OutputDebugStringA( sDebug ); return rcDpi; #else UNREFERENCED_PARAMETER( hwnd ); return rcWnd; #endif } HRESULT CShellPreviewHandlerImpl::CreateLocalServer() { HRESULT hr; hr = m_pPreviewHandler.CoCreateInstance(__uuidof(USDPreview::USDPreviewHandler)); if ( FAILED( hr ) ) return hr; CComQIPtr pInitializeWithFile = m_pPreviewHandler.p; m_pInitializeWithFile = pInitializeWithFile; if ( m_pInitializeWithFile == nullptr ) return E_NOINTERFACE; CComQIPtr pObjectWithSite = m_pPreviewHandler.p; m_pObjectWithSite = pObjectWithSite; if ( m_pObjectWithSite == nullptr ) return E_NOINTERFACE; CComQIPtr pOleWindow = m_pPreviewHandler.p; m_pOleWindow = pOleWindow; if ( m_pOleWindow == nullptr ) return E_NOINTERFACE; CComQIPtr pPreviewHandlerVisuals = m_pPreviewHandler.p; m_pPreviewHandlerVisuals = pPreviewHandlerVisuals; if ( m_pPreviewHandlerVisuals == nullptr ) return E_NOINTERFACE; return S_OK; } void CShellPreviewHandlerImpl::DestroyLocalServer() { m_pInitializeWithFile = nullptr; m_pObjectWithSite = nullptr; m_pOleWindow = nullptr; m_pPreviewHandler = nullptr; m_pPreviewHandlerVisuals = nullptr; } HRESULT CShellPreviewHandlerImpl::FinalConstruct() { return __super::FinalConstruct(); } void CShellPreviewHandlerImpl::FinalRelease() { DestroyLocalServer(); __super::FinalRelease(); } // IInitializeWithFile STDMETHODIMP CShellPreviewHandlerImpl::Initialize(__RPC__in_string LPCWSTR pszFilePath, DWORD grfMode) { HRESULT hr; hr = CreateLocalServer(); if ( FAILED( hr ) ) return hr; if ( m_pInitializeWithFile == nullptr ) return E_FAIL; hr = m_pInitializeWithFile->Initialize( pszFilePath, grfMode ); if ( FAILED( hr ) ) return hr; m_clrBackground = ::GetSysColor( COLOR_WINDOW ); m_clrText = ::GetSysColor( COLOR_WINDOWTEXT ); return hr; } // IObjectWithSite STDMETHODIMP CShellPreviewHandlerImpl::SetSite(__RPC__in_opt IUnknown* pUnkSite) { if ( m_pObjectWithSite == nullptr ) return E_FAIL; HRESULT hr; hr = m_pObjectWithSite->SetSite( pUnkSite ); if ( FAILED( hr ) ) return hr; return hr; } STDMETHODIMP CShellPreviewHandlerImpl::GetSite(__RPC__in REFIID riid, __RPC__deref_out_opt void** ppvSite) { if ( m_pObjectWithSite == nullptr ) return E_FAIL; HRESULT hr; hr = m_pObjectWithSite->GetSite( riid, ppvSite ); if ( FAILED( hr ) ) return hr; return hr; } // IOleWindow STDMETHODIMP CShellPreviewHandlerImpl::GetWindow(__RPC__deref_out_opt HWND* phwnd) { if ( m_pOleWindow == nullptr ) return E_FAIL; HRESULT hr; hr = m_pOleWindow->GetWindow( phwnd ); if ( FAILED( hr ) ) return hr; return hr; } STDMETHODIMP CShellPreviewHandlerImpl::ContextSensitiveHelp(BOOL fEnterMode) { if ( m_pOleWindow == nullptr ) return E_FAIL; HRESULT hr; hr = m_pOleWindow->ContextSensitiveHelp( fEnterMode ); if ( FAILED( hr ) ) return hr; return hr; } // IPreviewHandler STDMETHODIMP CShellPreviewHandlerImpl::SetWindow(__RPC__in HWND hwnd, __RPC__in const RECT* prc) { if ( prc == nullptr ) return E_POINTER; CAutoDpiAware dpi( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); m_hWnd = hwnd; m_rcWndRaw = *prc; m_rcWndDpiAware = UpdateRectForDPI( m_hWnd, m_rcWndRaw ); if ( m_pPreviewHandler == nullptr ) return E_FAIL; if ( m_bLoadScreenCreated ) { m_LoadScreenDlg.SetParent( m_hWnd ); m_LoadScreenDlg.SetWindowPos( nullptr, &m_rcWndDpiAware, 0 ); } HRESULT hr; hr = m_pPreviewHandler->SetWindow( m_LoadScreenDlg, &m_rcWndRaw ); if ( FAILED( hr ) ) return hr; return hr; } STDMETHODIMP CShellPreviewHandlerImpl::SetRect(__RPC__in const RECT* prc) { if ( prc == nullptr ) return E_POINTER; CAutoDpiAware dpi( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); m_rcWndRaw = *prc; m_rcWndDpiAware = UpdateRectForDPI( m_hWnd, m_rcWndRaw ); if ( m_pPreviewHandler == nullptr ) return E_FAIL; if (m_bLoadScreenCreated) m_LoadScreenDlg.SetWindowPos( nullptr, &m_rcWndDpiAware, 0 ); HRESULT hr; hr = m_pPreviewHandler->SetRect( &m_rcWndRaw ); if ( FAILED( hr ) ) return hr; return hr; } STDMETHODIMP CShellPreviewHandlerImpl::DoPreview() { if ( m_pPreviewHandler == nullptr ) return E_FAIL; CAutoDpiAware dpi( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); m_LoadScreenDlg.SetBackgroundColor( m_clrBackground ); m_LoadScreenDlg.Create( m_hWnd ); m_LoadScreenDlg.SetWindowPos( nullptr, &m_rcWndDpiAware, 0 ); m_bLoadScreenCreated = true; HRESULT hr; hr = m_pPreviewHandler->SetWindow( m_LoadScreenDlg, &m_rcWndRaw ); if ( FAILED( hr ) ) return hr; hr = m_pPreviewHandler->DoPreview(); if ( FAILED( hr ) ) return hr; return hr; } STDMETHODIMP CShellPreviewHandlerImpl::Unload() { if ( m_pPreviewHandler == nullptr ) return E_FAIL; m_LoadScreenDlg.DestroyWindow(); m_bLoadScreenCreated = false; HRESULT hr; hr = m_pPreviewHandler->Unload(); DestroyLocalServer(); return hr; } STDMETHODIMP CShellPreviewHandlerImpl::SetFocus() { if ( m_pPreviewHandler == nullptr ) return E_FAIL; HRESULT hr; hr = m_pPreviewHandler->SetFocus(); if ( FAILED( hr ) ) return hr; return hr; } STDMETHODIMP CShellPreviewHandlerImpl::QueryFocus(__RPC__deref_out_opt HWND* phwnd) { if ( m_pPreviewHandler == nullptr ) return E_FAIL; HRESULT hr; hr = m_pPreviewHandler->QueryFocus(phwnd); if ( FAILED( hr ) ) return hr; return hr; } STDMETHODIMP CShellPreviewHandlerImpl::TranslateAccelerator(__RPC__in MSG* pmsg) { if ( m_pPreviewHandler == nullptr ) return E_FAIL; HRESULT hr; hr = m_pPreviewHandler->TranslateAccelerator(pmsg); if ( FAILED( hr ) ) return hr; return hr; } STDMETHODIMP CShellPreviewHandlerImpl::SetBackgroundColor( COLORREF color ) { if ( m_pPreviewHandlerVisuals == nullptr ) return E_FAIL; HRESULT hr; hr = m_pPreviewHandlerVisuals->SetBackgroundColor(color); if ( FAILED( hr ) ) return hr; m_clrBackground = color; m_LoadScreenDlg.SetBackgroundColor( m_clrBackground ); return S_OK; } STDMETHODIMP CShellPreviewHandlerImpl::SetFont( __RPC__in const LOGFONTW *plf ) { if ( m_pPreviewHandlerVisuals == nullptr ) return E_FAIL; HRESULT hr; hr = m_pPreviewHandlerVisuals->SetFont(plf); if ( FAILED( hr ) ) return hr; return S_OK; } STDMETHODIMP CShellPreviewHandlerImpl::SetTextColor( COLORREF color ) { if ( m_pPreviewHandlerVisuals == nullptr ) return E_FAIL; HRESULT hr; hr = m_pPreviewHandlerVisuals->SetTextColor(color); if ( FAILED( hr ) ) return hr; m_clrText = color; return S_OK; } HRESULT WINAPI CShellPreviewHandlerImpl::UpdateRegistry(_In_ BOOL bRegister) throw() { ATL::_ATL_REGMAP_ENTRY regMapEntries[] = { { L"CLSID_SHELLPREVIEWHANDLER", L"{2DEB1AB8-DECA-42C2-B576-3116D9CA8FA8}" }, { nullptr, nullptr } }; return g_AtlModule.UpdateRegistryFromResource(IDR_REGISTRY_SHELLPREVIEWHANDLERIMPL, bRegister, regMapEntries); } ================================================ FILE: UsdShellExtension/ShellPreviewHandlerImpl.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "ShellExt_h.h" #include "UsdLoadScreenDlg.h" #include "resource.h" class ATL_NO_VTABLE CShellPreviewHandlerImpl : public CComObjectRootEx, public CComCoClass, public IInitializeWithFile, public IObjectWithSite, public IOleWindow, public IPreviewHandler, public IPreviewHandlerVisuals { public: DECLARE_NOT_AGGREGATABLE(CShellPreviewHandlerImpl) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CShellPreviewHandlerImpl) COM_INTERFACE_ENTRY(IInitializeWithFile) COM_INTERFACE_ENTRY(IObjectWithSite) COM_INTERFACE_ENTRY(IOleWindow) COM_INTERFACE_ENTRY(IPreviewHandler) COM_INTERFACE_ENTRY(IPreviewHandlerVisuals) END_COM_MAP() HRESULT FinalConstruct(); void FinalRelease(); // IInitializeWithFile STDMETHODIMP Initialize( __RPC__in_string LPCWSTR pszFilePath, DWORD grfMode ) override; // IObjectWithSite STDMETHODIMP SetSite(__RPC__in_opt IUnknown* pUnkSite) override; STDMETHODIMP GetSite(__RPC__in REFIID riid, __RPC__deref_out_opt void** ppvSite) override; // IOleWindow STDMETHODIMP GetWindow(__RPC__deref_out_opt HWND* phwnd) override; STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) override; // IPreviewHandler STDMETHODIMP SetWindow( __RPC__in HWND hwnd, __RPC__in const RECT* prc) override; STDMETHODIMP SetRect( __RPC__in const RECT* prc ) override; STDMETHODIMP DoPreview() override; STDMETHODIMP Unload() override; STDMETHODIMP SetFocus() override; STDMETHODIMP QueryFocus( __RPC__deref_out_opt HWND* phwnd) override; STDMETHODIMP TranslateAccelerator(__RPC__in MSG* pmsg) override; // IPreviewHandlerVisuals STDMETHODIMP SetBackgroundColor(COLORREF color) override; STDMETHODIMP SetFont(__RPC__in const LOGFONTW *plf) override; STDMETHODIMP SetTextColor(COLORREF color) override; static HRESULT WINAPI UpdateRegistry(_In_ BOOL bRegister) throw(); private: HRESULT CreateLocalServer(); void DestroyLocalServer(); CComPtr m_pInitializeWithFile; CComPtr m_pObjectWithSite; CComPtr m_pOleWindow; CComPtr m_pPreviewHandler; CComPtr m_pPreviewHandlerVisuals; HWND m_hWnd = nullptr; // raw dpi-unaware rect RECT m_rcWndRaw = {}; // window rect adjusted for dpi RECT m_rcWndDpiAware = {}; COLORREF m_clrBackground; COLORREF m_clrText; CUsdLoadScreenDlg m_LoadScreenDlg; bool m_bLoadScreenCreated = false; }; OBJECT_ENTRY_AUTO(__uuidof(ShellPreviewHandler), CShellPreviewHandlerImpl) ================================================ FILE: UsdShellExtension/ShellPreviewHandlerImpl.rgs ================================================ HKCR { NoRemove ATVI.USD { NoRemove shellex { ForceRemove {8895b1c6-b41f-4c1c-a562-0d564250836f} = s '%CLSID_SHELLPREVIEWHANDLER%' } } NoRemove ATVI.USDA { NoRemove shellex { ForceRemove {8895b1c6-b41f-4c1c-a562-0d564250836f} = s '%CLSID_SHELLPREVIEWHANDLER%' } } NoRemove ATVI.USDC { NoRemove shellex { ForceRemove {8895b1c6-b41f-4c1c-a562-0d564250836f} = s '%CLSID_SHELLPREVIEWHANDLER%' } } NoRemove ATVI.USDZ { NoRemove shellex { ForceRemove {8895b1c6-b41f-4c1c-a562-0d564250836f} = s '%CLSID_SHELLPREVIEWHANDLER%' } } NoRemove CLSID { ForceRemove %CLSID_SHELLPREVIEWHANDLER% = s 'Activision USD Preview Handler' { ForceRemove InProcServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' } val DisplayName = s 'Activision USD Preview Handler' val AppID = s '{6d2b5079-2f0b-48dd-ab7f-97cec514d30b}' val DisableProcessIsolation = d '1' val DisableLowILProcessIsolation = d '1' val Icon = s '%MODULE%,-113' } } } HKLM { NoRemove Software { NoRemove Microsoft { NoRemove Windows { NoRemove CurrentVersion { NoRemove PreviewHandlers { ForceRemove val %CLSID_SHELLPREVIEWHANDLER% = s 'Activision USD Preview Handler' } NoRemove 'Shell Extensions' { NoRemove Approved { ForceRemove val %CLSID_SHELLPREVIEWHANDLER% = s 'Activision USD Preview Handler' } } } } } } } HKCU { NoRemove Software { NoRemove Microsoft { NoRemove Windows { NoRemove CurrentVersion { NoRemove PreviewHandlers { ForceRemove val %CLSID_SHELLPREVIEWHANDLER% = s 'Activision USD Preview Handler' } NoRemove 'Shell Extensions' { NoRemove Approved { ForceRemove val %CLSID_SHELLPREVIEWHANDLER% = s 'Activision USD Preview Handler' } } } } } } } ================================================ FILE: UsdShellExtension/ShellPropertyStoreImpl.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "ShellPropertyStoreImpl.h" #include "Module.h" #include "resource.h" #include "UsdMetadata.h" #include "UsdPropertyKeys.h" #include "ArResolverShellExtension.h" static void RegisterUsdPlugins() { static bool sUsdPluginsRegistered = false; static std::mutex sUsdPluginsRegisteredLock; std::lock_guard guard( sUsdPluginsRegisteredLock ); // Plugins should be registered only once per session. if( sUsdPluginsRegistered ) return; sUsdPluginsRegistered = true; TCHAR sModulePath[MAX_PATH]; GetModuleFileName( g_hInstance, sModulePath, ARRAYSIZE( sModulePath ) ); std::vector pathsToPlugInfo; // add the folder that contains the shell extension PathCchRemoveFileSpec( sModulePath, ARRAYSIZE( sModulePath ) ); pathsToPlugInfo.push_back( static_cast(ATL::CW2A(sModulePath, CP_UTF8)) ); // add the bare-bones usd plugins PathCchAppend( sModulePath, ARRAYSIZE( sModulePath ), L"usd" ); pathsToPlugInfo.push_back( static_cast(ATL::CW2A(sModulePath, CP_UTF8)) ); pxr::PlugRegistry::GetInstance().RegisterPlugins( pathsToPlugInfo ); pxr::ArSetPreferredResolver(pxr::TfType::GetCanonicalTypeName(typeid(pxr::ArResolverShellExtension))); } HRESULT CShellPropertyStoreImpl::FinalConstruct() { return __super::FinalConstruct(); } void CShellPropertyStoreImpl::FinalRelease() { __super::FinalRelease(); } // IInitializeWithFile STDMETHODIMP CShellPropertyStoreImpl::Initialize(__RPC__in_string LPCWSTR pszFilePath, DWORD grfMode) { if ( pszFilePath == nullptr ) return E_POINTER; m_usdStagePath = pszFilePath; m_grfMode = grfMode; DWORD nAttribs = GetFileAttributesW( pszFilePath ); if ( nAttribs == INVALID_FILE_ATTRIBUTES ) return E_INVALIDARG; // Avoid opening files that are reparse points. // TedFS stubs are such files. An open here would cause a resolve. if ( nAttribs & FILE_ATTRIBUTE_REPARSE_POINT ) return E_FAIL; HRESULT hr; hr = PSCreateMemoryPropertyStore(IID_PPV_ARGS(&m_pPropertyStoreCache.p)); if ( FAILED( hr ) ) return hr; RegisterUsdPlugins(); std::string pszFilePathA = static_cast(ATL::CW2A( m_usdStagePath, CP_UTF8 )); // open the file for just metadata // this is a fast read-only load pxr::SdfLayerRefPtr rootLayer = pxr::SdfLayer::OpenAsAnonymous( pszFilePathA, true ); if ( rootLayer == nullptr ) { return E_FAIL; } m_bIsPackage = rootLayer->GetFileFormat()->IsPackage(); pxr::VtDictionary customLayerData = rootLayer->GetCustomLayerData(); hr = ReadUsdMetadata( rootLayer, customLayerData, m_pPropertyStoreCache ); if ( FAILED( hr ) ) { return hr; } return hr; } // IPropertyStore STDMETHODIMP CShellPropertyStoreImpl::Commit() { HRESULT hr = E_FAIL; if ( IsReadOnly() || IsPackage() ) return STG_E_ACCESSDENIED; if ( m_pPropertyStoreCache == nullptr ) return E_UNEXPECTED; RegisterUsdPlugins(); std::string pszFilePathA = static_cast(ATL::CW2A( m_usdStagePath, CP_UTF8 )); pxr::SdfLayerRefPtr rootLayer = pxr::SdfLayer::FindOrOpen( pszFilePathA ); if ( rootLayer == nullptr ) return E_FAIL; // save the file back out bool bIsDirty = false; pxr::VtDictionary customLayerData = rootLayer->GetCustomLayerData(); hr = WriteUsdMetadata( rootLayer, customLayerData, m_pPropertyStoreCache, bIsDirty ); if ( FAILED( hr ) ) return hr; // check if anything changed if ( bIsDirty == false ) return S_OK; // save our updated metadata rootLayer->SetCustomLayerData( customLayerData ); CStringW usdTempStagePath = m_usdStagePath; usdTempStagePath += L".tmp"; if ( !rootLayer->Export( static_cast(ATL::CW2A( usdTempStagePath, CP_UTF8 )) ) ) return E_FAIL; rootLayer = nullptr; if ( !::ReplaceFileW( m_usdStagePath, usdTempStagePath, nullptr, REPLACEFILE_IGNORE_MERGE_ERRORS|REPLACEFILE_IGNORE_ACL_ERRORS, nullptr, nullptr ) ) return E_FAIL; return S_OK; } STDMETHODIMP CShellPropertyStoreImpl::GetCount( __RPC__out DWORD *cProps ) { if ( cProps == nullptr ) return E_POINTER; HRESULT hr = E_UNEXPECTED; if ( m_pPropertyStoreCache ) hr = m_pPropertyStoreCache->GetCount( cProps ); return hr; } STDMETHODIMP CShellPropertyStoreImpl::GetAt( DWORD iProp, __RPC__out PROPERTYKEY *pkey ) { if ( pkey == nullptr ) return E_POINTER; HRESULT hr = E_UNEXPECTED; if ( m_pPropertyStoreCache ) hr = m_pPropertyStoreCache->GetAt( iProp, pkey ); return hr; } STDMETHODIMP CShellPropertyStoreImpl::GetValue( __RPC__in REFPROPERTYKEY key, __RPC__out PROPVARIANT *pv ) { if ( pv == nullptr ) return E_POINTER; HRESULT hr = E_UNEXPECTED; if ( m_pPropertyStoreCache ) hr = m_pPropertyStoreCache->GetValue( key, pv ); return hr; } STDMETHODIMP CShellPropertyStoreImpl::SetValue( __RPC__in REFPROPERTYKEY key, __RPC__in REFPROPVARIANT propvar ) { if ( IsReadOnly() || IsPackage() ) return STG_E_ACCESSDENIED; HRESULT hr = E_UNEXPECTED; if ( m_pPropertyStoreCache && IsPropertyWritable(key) == S_OK ) hr = m_pPropertyStoreCache->SetValueAndState( key, &propvar, PSC_DIRTY ); return hr; } // IPropertyStoreCapabilities STDMETHODIMP CShellPropertyStoreImpl::IsPropertyWritable( __RPC__in REFPROPERTYKEY key ) { if ( IsPackage() ) return S_FALSE; return IsMetadataPropertyWritable( key ); } HRESULT WINAPI CShellPropertyStoreImpl::UpdateRegistry(_In_ BOOL bRegister) throw() { const wchar_t pPropertyDescription[] = L"val InfoTip = s 'prop:System.ItemType;System.Size;System.DateModified'\n" L"val FullDetails = s 'prop:System.PropGroup.FileSystem;System.ItemNameDisplay;System.ItemType;System.ItemFolderPathDisplay;System.Size;System.ItemDate;System.DateCreated;System.DateModified;System.DateAccessed;System.FileAttributes;USD.PropGroup.USD;System.Comment;USD.Documentation;USD.CustomLayerData;USD.PropGroup.Activision'\n" L"val PreviewDetails = s 'prop:USD.PropGroup.USD;System.Comment;USD.Documentation;USD.PropGroup.Activision'\n" L"val PreviewTitle = s 'prop:System.FileName;System.ItemType'\n"; ATL::_ATL_REGMAP_ENTRY regMapEntries[] = { { L"CLSID_SHELLPROPERTYSTORE", L"{5CE761D0-72AA-4484-B2BF-2A0EBF3ACC0C}" }, { L"PROPERTYDESCRIPTIONS", pPropertyDescription }, { nullptr, nullptr } }; return g_AtlModule.UpdateRegistryFromResource(IDR_REGISTRY_SHELLPROPERTYSTOREIMPL, bRegister, regMapEntries); } ================================================ FILE: UsdShellExtension/ShellPropertyStoreImpl.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "ShellExt_h.h" #include "resource.h" class ATL_NO_VTABLE CShellPropertyStoreImpl : public CComObjectRootEx, public CComCoClass, public IInitializeWithFile, public IPropertyStore, public IPropertyStoreCapabilities { public: DECLARE_NOT_AGGREGATABLE(CShellPropertyStoreImpl) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CShellPropertyStoreImpl) COM_INTERFACE_ENTRY(IInitializeWithFile) COM_INTERFACE_ENTRY(IPropertyStore) COM_INTERFACE_ENTRY(IPropertyStoreCapabilities) END_COM_MAP() HRESULT FinalConstruct(); void FinalRelease(); // IInitializeWithFile STDMETHODIMP Initialize( __RPC__in_string LPCWSTR pszFilePath, DWORD grfMode ) override; // IPropertyStore STDMETHODIMP GetCount( __RPC__out DWORD *cProps ) override; STDMETHODIMP GetAt( DWORD iProp, __RPC__out PROPERTYKEY *pkey ) override; STDMETHODIMP GetValue( __RPC__in REFPROPERTYKEY key, __RPC__out PROPVARIANT *pv ) override; STDMETHODIMP SetValue( __RPC__in REFPROPERTYKEY key, __RPC__in REFPROPVARIANT propvar ) override; STDMETHODIMP Commit() override; // IPropertyStoreCapabilities STDMETHODIMP IsPropertyWritable( __RPC__in REFPROPERTYKEY key) override; static HRESULT WINAPI UpdateRegistry(_In_ BOOL bRegister) throw(); private: bool IsPackage() const { return m_bIsPackage; } bool IsReadOnly() const { return (m_grfMode & STGM_READWRITE) == 0; } CStringW m_usdStagePath; DWORD m_grfMode = 0; bool m_bIsPackage = false; CComPtr m_pPropertyStoreCache; }; OBJECT_ENTRY_AUTO(__uuidof(ShellPropertyStore), CShellPropertyStoreImpl) ================================================ FILE: UsdShellExtension/ShellPropertyStoreImpl.rgs ================================================ HKCR { NoRemove ATVI.USD { %PROPERTYDESCRIPTIONS% } NoRemove ATVI.USDA { %PROPERTYDESCRIPTIONS% } NoRemove ATVI.USDC { %PROPERTYDESCRIPTIONS% } NoRemove ATVI.USDZ { %PROPERTYDESCRIPTIONS% } NoRemove CLSID { ForceRemove %CLSID_SHELLPROPERTYSTORE% = s 'Activision USD Property Store' { ForceRemove InProcServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' } val DisplayName = s 'Activision USD Property Store' val DisableProcessIsolation = d '1' } } } HKLM { NoRemove Software { NoRemove Microsoft { NoRemove Windows { NoRemove CurrentVersion { NoRemove PropertySystem { NoRemove PropertyHandlers { ForceRemove .usd = s '%CLSID_SHELLPROPERTYSTORE%' ForceRemove .usda = s '%CLSID_SHELLPROPERTYSTORE%' ForceRemove .usdc = s '%CLSID_SHELLPROPERTYSTORE%' ForceRemove .usdz = s '%CLSID_SHELLPROPERTYSTORE%' } } NoRemove 'Shell Extensions' { NoRemove Approved { ForceRemove val %CLSID_SHELLPROPERTYSTORE% = s 'Activision USD Property Store' } } } } } } } ================================================ FILE: UsdShellExtension/ShellThumbnailProviderImpl.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "ShellThumbnailProviderImpl.h" #include "Module.h" #include "resource.h" #import "UsdPythonToolsLocalServer.tlb" raw_interfaces_only HRESULT CShellThumbnailProviderImpl::FinalConstruct() { return __super::FinalConstruct(); } void CShellThumbnailProviderImpl::FinalRelease() { __super::FinalRelease(); } static bool GetRendererFromConfig( CComBSTR &outBstr ) { TCHAR sModulePath[MAX_PATH]; ::GetModuleFileName( g_hInstance, sModulePath, ARRAYSIZE( sModulePath ) ); ::PathCchRenameExtension( sModulePath, ARRAYSIZE( sModulePath ), L"cfg" ); TCHAR sRenderer[128]; sRenderer[0] = '\0'; ::GetPrivateProfileString( _T( "RENDERER" ), _T( "THUMBNAIL" ), _T( "" ), sRenderer, ARRAYSIZE( sRenderer ), sModulePath ); if ( sRenderer[0] == '\0' ) return false; outBstr = sRenderer; return true; } // IInitializeWithFile STDMETHODIMP CShellThumbnailProviderImpl::Initialize(__RPC__in_string LPCWSTR pszFilePath, DWORD grfMode) { UNREFERENCED_PARAMETER( grfMode ); if ( pszFilePath == nullptr ) return E_POINTER; m_usdStagePath = pszFilePath; return S_OK; } // IThumbnailProvider STDMETHODIMP CShellThumbnailProviderImpl::GetThumbnail( UINT cx, __RPC__deref_out_opt HBITMAP *phbmp, __RPC__out WTS_ALPHATYPE *pdwAlpha) { if ( phbmp == nullptr ) return E_POINTER; HRESULT hr; CComPtr pUSDTools; hr = pUSDTools.CoCreateInstance( __uuidof(UsdPythonToolsLib::UsdPythonTools) ); if ( FAILED( hr ) ) return hr; CComBSTR bstrRenderer; bool bRendererIsSet = GetRendererFromConfig( bstrRenderer ); BSTR sThumbnailImage = nullptr; hr = pUSDTools->Record( CComBSTR(m_usdStagePath), cx, bRendererIsSet ? bstrRenderer : nullptr, &sThumbnailImage ); if ( FAILED( hr ) ) return hr; CComBSTR bstrThumbnailImage; bstrThumbnailImage.Attach( sThumbnailImage ); CImage imgBmp; hr = imgBmp.Load( bstrThumbnailImage ); if ( FAILED( hr ) ) return hr; *phbmp = imgBmp.Detach(); if ( pdwAlpha ) *pdwAlpha = WTSAT_ARGB; return S_OK; } HRESULT WINAPI CShellThumbnailProviderImpl::UpdateRegistry(_In_ BOOL bRegister) throw() { ATL::_ATL_REGMAP_ENTRY regMapEntries[] = { { L"CLSID_SHELLTHUMBNAILPROVIDER", L"{2877CB72-1427-43B0-A2B4-9CB1B2BA8C53}" }, { nullptr, nullptr } }; return g_AtlModule.UpdateRegistryFromResource(IDR_REGISTRY_SHELLTHUMBNAILPROVIDERIMPL, bRegister, regMapEntries); } ================================================ FILE: UsdShellExtension/ShellThumbnailProviderImpl.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "ShellExt_h.h" #include "resource.h" class ATL_NO_VTABLE CShellThumbnailProviderImpl : public CComObjectRootEx, public CComCoClass, public IInitializeWithFile, public IThumbnailProvider { public: DECLARE_NOT_AGGREGATABLE(CShellThumbnailProviderImpl) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CShellThumbnailProviderImpl) COM_INTERFACE_ENTRY(IInitializeWithFile) COM_INTERFACE_ENTRY(IThumbnailProvider) END_COM_MAP() HRESULT FinalConstruct(); void FinalRelease(); // IInitializeWithFile STDMETHODIMP Initialize( __RPC__in_string LPCWSTR pszFilePath, DWORD grfMode ) override; // IThumbnailProvider STDMETHODIMP GetThumbnail( UINT cx, __RPC__deref_out_opt HBITMAP *phbmp, __RPC__out WTS_ALPHATYPE *pdwAlpha) override; static HRESULT WINAPI UpdateRegistry(_In_ BOOL bRegister) throw(); private: CStringW m_usdStagePath; }; OBJECT_ENTRY_AUTO(__uuidof(ShellThumbnailProvider), CShellThumbnailProviderImpl) ================================================ FILE: UsdShellExtension/ShellThumbnailProviderImpl.rgs ================================================ HKCR { NoRemove ATVI.USD { NoRemove shellex { ForceRemove {e357fccd-a995-4576-b01f-234630154e96} = s '%CLSID_SHELLTHUMBNAILPROVIDER%' } ForceRemove DefaultIcon = s '%MODULE%,-113' } NoRemove ATVI.USDA { NoRemove shellex { ForceRemove {e357fccd-a995-4576-b01f-234630154e96} = s '%CLSID_SHELLTHUMBNAILPROVIDER%' } ForceRemove DefaultIcon = s '%MODULE%,-113' } NoRemove ATVI.USDC { NoRemove shellex { ForceRemove {e357fccd-a995-4576-b01f-234630154e96} = s '%CLSID_SHELLTHUMBNAILPROVIDER%' } ForceRemove DefaultIcon = s '%MODULE%,-113' } NoRemove ATVI.USDZ { NoRemove shellex { ForceRemove {e357fccd-a995-4576-b01f-234630154e96} = s '%CLSID_SHELLTHUMBNAILPROVIDER%' } ForceRemove DefaultIcon = s '%MODULE%,-113' } NoRemove CLSID { ForceRemove %CLSID_SHELLTHUMBNAILPROVIDER% = s 'Activision USD Thumbnail Provider' { ForceRemove InProcServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' } val DisplayName = s 'Activision USD Thumbnail Provider' val DisableProcessIsolation = d '1' val DisableLowILProcessIsolation = d '1' } } } HKLM { NoRemove Software { NoRemove Microsoft { NoRemove Windows { NoRemove CurrentVersion { NoRemove 'Shell Extensions' { NoRemove Approved { ForceRemove val %CLSID_SHELLTHUMBNAILPROVIDER% = s 'Activision USD Thumbnail Provider' } } } } } } } HKCU { NoRemove Software { NoRemove Microsoft { NoRemove Windows { NoRemove CurrentVersion { NoRemove 'Shell Extensions' { NoRemove Approved { ForceRemove val %CLSID_SHELLTHUMBNAILPROVIDER% = s 'Activision USD Thumbnail Provider' } } } } } } } ================================================ FILE: UsdShellExtension/UWPProgressBar.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "UWPProgressBar.h" static float GetPerformanceFrequency() { LARGE_INTEGER li; QueryPerformanceFrequency( &li ); return (float)li.QuadPart; } static float GetTimeInterval() { static float s_fFreq = GetPerformanceFrequency(); return s_fFreq; } static float GetTimePrecise() { LARGE_INTEGER li; QueryPerformanceCounter( &li ); return (float)li.QuadPart / (GetTimeInterval() / 1000.0f); } void CUWPProgressBar::Init() { m_LastUpdateTime = GetTimePrecise(); m_ptProgressBarDot[0].Y = -10.0f; m_ptProgressBarDot[0].X = 0; for ( int i = 1; i < ARRAYSIZE( m_ptProgressBarDot ); ++i ) { m_ptProgressBarDot[i].Y = m_ptProgressBarDot[i - 1].Y - 0.5f; m_ptProgressBarDot[i].X = 0.0f; } } void CUWPProgressBar::UpdateProgressBar() { float tCurrent = GetTimePrecise(); float fDelta = (float)(tCurrent - m_LastUpdateTime); m_LastUpdateTime = tCurrent; fDelta /= 100.0f; for ( Gdiplus::PointF &pt : m_ptProgressBarDot ) { pt.Y += fDelta; // x = (y^3 / 32) + y // the resulting ranges are: // x: [-30,+30] // y: [-10,+10] pt.X = ((pt.Y * pt.Y * pt.Y) / 32.0f) + pt.Y; // if we are past our range, go back to -10.0f if ( pt.Y > 10.0f ) pt.Y -= 20.0f; } } void CUWPProgressBar::DrawProgressBar( HWND hWnd, Gdiplus::Graphics &gfx, Gdiplus::RectF &rcArea, Gdiplus::Color &backgroundColor ) { float fDpiWindow = static_cast(::GetDpiForWindow( hWnd )); float fDpiScale = fDpiWindow / USER_DEFAULT_SCREEN_DPI; Gdiplus::SolidBrush brush( backgroundColor ); gfx.FillRectangle( &brush, rcArea ); Gdiplus::SizeF dot; dot.Width = kfProgressBarDotSize; dot.Height = kfProgressBarDotSize; // DPI adjust dot.Width *= fDpiScale; dot.Height *= fDpiScale; for ( Gdiplus::PointF &pt : m_ptProgressBarDot ) { // dots do not look good in a width below 720 or so float fScaledWidth = std::max( 720.0f, (float)rcArea.Width ); // pt.X [-30.0f, 30.0f] float scaledX = (((pt.X + 30.0f) * fScaledWidth) / 60.0f); scaledX += ((float)rcArea.Width - fScaledWidth) / 2.0f; if ( scaledX < 0 || (scaledX + dot.Width) >= rcArea.Width ) continue; Gdiplus::RectF rcDot( rcArea.X + scaledX, rcArea.Y + ((rcArea.Height - dot.Height) / 2.0f), dot.Width, dot.Height ); Gdiplus::Color clrDot; BYTE bAlpha = (BYTE)(((100.0f - fabsf( pt.X )) / 100.0f) * 255.0f); //clrDot.SetValue( Gdiplus::Color::MakeARGB(bAlpha, 52, 198, 243) ); clrDot.SetValue( Gdiplus::Color::MakeARGB( bAlpha, 200, 200, 200 ) ); Gdiplus::SolidBrush brushDot( clrDot ); gfx.FillEllipse( &brushDot, rcDot ); } } void CUWPProgressBar::SetBackgroundColor( COLORREF color, bool bWindowsExplorerUsingLightTheme ) { UNREFERENCED_PARAMETER( color ); m_bWindowsExplorerUsingLightTheme = bWindowsExplorerUsingLightTheme; } ================================================ FILE: UsdShellExtension/UWPProgressBar.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once // This class attempts to replicate the UWP XAML progress bar class CUWPProgressBar { public: void Init(); void UpdateProgressBar(); void DrawProgressBar( HWND hWnd, Gdiplus::Graphics &gfx, Gdiplus::RectF &rcDst, Gdiplus::Color &backgroundColor ); void SetBackgroundColor( COLORREF color, bool bWindowsExplorerUsingLightTheme ); private: static constexpr size_t knProgressBarDotCount = 5; static constexpr float kfProgressBarDotSize = 4.0f; Gdiplus::PointF m_ptProgressBarDot[knProgressBarDotCount]; float m_LastUpdateTime = 0; bool m_bWindowsExplorerUsingLightTheme = true; }; ================================================ FILE: UsdShellExtension/UsdLoadScreenDlg.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "UsdLoadScreenDlg.h" #include "Module.h" #include "resource.h" #include static constexpr UINT s_TimerIdProgress = 100; static Gdiplus::Image *LoadImageFromResourcePNG( UINT nId ) { HRSRC hrscPng = ::FindResource( g_hInstance, MAKEINTRESOURCE( nId ), _T( "PNG" ) ); if ( hrscPng != nullptr ) { HGLOBAL hPng = ::LoadResource( g_hInstance, hrscPng ); if ( hPng != nullptr ) { void *pImageData = ::LockResource( hPng ); if ( pImageData != nullptr ) { DWORD nSize = ::SizeofResource( g_hInstance, hrscPng ); CComPtr pImageStream; pImageStream.p = ::SHCreateMemStream( reinterpret_cast(pImageData), nSize ); Gdiplus::Image *img = Gdiplus::Image::FromStream( pImageStream ); return img; } } } return nullptr; } LRESULT CUsdLoadScreenDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ) { UNREFERENCED_PARAMETER( uMsg ); UNREFERENCED_PARAMETER( wParam ); UNREFERENCED_PARAMETER( lParam ); UNREFERENCED_PARAMETER( bHandled ); SetWindowText( _T( "UsdLoadScreenDlg" ) ); Gdiplus::GdiplusStartupInputEx gdiplusStartupInput; Gdiplus::GdiplusStartup( &m_gdiplusToken, &gdiplusStartupInput, nullptr ); m_pImgLoadScreen = LoadImageFromResourcePNG( IDB_LOADSCREEN ); m_pImgLogo = LoadImageFromResourcePNG( IDB_LOGO ); RECT rcClient; GetClientRect( &rcClient ); m_ProgressBar.Init(); CreateBackBuffer( rcClient.right - rcClient.left, rcClient.bottom - rcClient.top ); if ( m_pGfx ) Draw( *m_pGfx ); SetTimer( s_TimerIdProgress, 1, nullptr ); return 0; } LRESULT CUsdLoadScreenDlg::OnPaint( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ) { UNREFERENCED_PARAMETER( uMsg ); UNREFERENCED_PARAMETER( wParam ); UNREFERENCED_PARAMETER( lParam ); UNREFERENCED_PARAMETER( bHandled ); PAINTSTRUCT ps; HDC hDCFrontBuffer = BeginPaint( &ps ); if ( !m_imgBackBuffer.IsNull() ) { POINT ptSrc = { ps.rcPaint.left, ps.rcPaint.top }; m_imgBackBuffer.BitBlt( hDCFrontBuffer, ps.rcPaint, ptSrc, SRCCOPY ); } EndPaint( &ps ); return 0; } LRESULT CUsdLoadScreenDlg::OnEraseBkgnd( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ) { UNREFERENCED_PARAMETER( uMsg ); UNREFERENCED_PARAMETER( wParam ); UNREFERENCED_PARAMETER( lParam ); UNREFERENCED_PARAMETER( bHandled ); return (LRESULT)::GetStockObject( NULL_BRUSH ); } LRESULT CUsdLoadScreenDlg::OnSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ) { UNREFERENCED_PARAMETER( uMsg ); UNREFERENCED_PARAMETER( wParam ); UNREFERENCED_PARAMETER( bHandled ); UINT width = LOWORD( lParam ); UINT height = HIWORD( lParam ); CreateBackBuffer( width, height ); if ( m_pGfx ) Draw( *m_pGfx ); Invalidate( FALSE ); return 0; } LRESULT CUsdLoadScreenDlg::OnCtlColorDlg( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ) { UNREFERENCED_PARAMETER( uMsg ); UNREFERENCED_PARAMETER( wParam ); UNREFERENCED_PARAMETER( lParam ); UNREFERENCED_PARAMETER( bHandled ); return (LRESULT)::GetStockObject( NULL_BRUSH ); } LRESULT CUsdLoadScreenDlg::OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ) { UNREFERENCED_PARAMETER( uMsg ); UNREFERENCED_PARAMETER( lParam ); UNREFERENCED_PARAMETER( bHandled ); switch ( wParam ) { case s_TimerIdProgress: if ( m_pGfx && m_hWnd ) { m_ProgressBar.UpdateProgressBar(); m_ProgressBar.DrawProgressBar( m_hWnd, *m_pGfx, m_rcProgressArea, m_Background ); InvalidateProgressBar( m_rcProgressArea ); } break; } return 0; } void CUsdLoadScreenDlg::SetBackgroundColor( COLORREF color ) { if ( m_hBackground ) { ::DeleteObject( m_hBackground ); m_hBackground = nullptr; } m_bWindowsExplorerUsingLightTheme = true; CRegKey regDarkMode; LRESULT lr = regDarkMode.Open( HKEY_CURRENT_USER, _T( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize" ), KEY_READ ); if ( lr == ERROR_SUCCESS ) { DWORD nSystemUsesLightTheme = 0; lr = regDarkMode.QueryDWORDValue( _T( "SystemUsesLightTheme" ), nSystemUsesLightTheme ); if ( lr == ERROR_SUCCESS ) { m_bWindowsExplorerUsingLightTheme = (nSystemUsesLightTheme != 0); } } // Colors hard-coded to Windows 10 2003 Explorer if ( m_bWindowsExplorerUsingLightTheme == false ) color = RGB( 32, 32, 32 ); m_Background.SetFromCOLORREF( color ); m_hBackground = ::CreateSolidBrush( color ); m_ProgressBar.SetBackgroundColor( color, m_bWindowsExplorerUsingLightTheme ); if ( m_pGfx ) { Draw( *m_pGfx ); Invalidate( FALSE ); } } void CUsdLoadScreenDlg::OnFinalMessage( _In_ HWND hWnd ) { UNREFERENCED_PARAMETER( hWnd ); if ( m_hBackground ) { ::DeleteObject( m_hBackground ); m_hBackground = nullptr; } delete m_pImgLoadScreen; m_pImgLoadScreen = nullptr; if ( m_pGfx ) { delete m_pGfx; m_pGfx = nullptr; } if ( m_hDCBackbuffer ) { m_imgBackBuffer.ReleaseDC(); m_hDCBackbuffer = nullptr; } m_imgBackBuffer.Destroy(); Gdiplus::GdiplusShutdown( m_gdiplusToken ); } void CUsdLoadScreenDlg::CreateBackBuffer( UINT width, UINT height ) { if ( m_pGfx ) { delete m_pGfx; m_pGfx = nullptr; } if ( m_hDCBackbuffer ) { m_imgBackBuffer.ReleaseDC(); m_hDCBackbuffer = nullptr; } m_imgBackBuffer.Destroy(); if ( width == 0 || height == 0 ) return; m_imgBackBuffer.Create( width, height, 32, 0 ); m_hDCBackbuffer = m_imgBackBuffer.GetDC(); m_pGfx = Gdiplus::Graphics::FromHDC( m_hDCBackbuffer ); m_pGfx->SetCompositingMode( Gdiplus::CompositingModeSourceOver ); m_pGfx->SetCompositingQuality( Gdiplus::CompositingQualityGammaCorrected ); m_pGfx->SetInterpolationMode( Gdiplus::InterpolationModeHighQualityBicubic ); m_pGfx->SetSmoothingMode( Gdiplus::SmoothingModeAntiAlias ); } void CUsdLoadScreenDlg::Draw( Gdiplus::Graphics &gfx ) { if ( m_imgBackBuffer.IsNull() ) return; Gdiplus::SolidBrush brush( m_Background ); gfx.FillRectangle( &brush, 0, 0, static_cast(m_imgBackBuffer.GetWidth()), static_cast(m_imgBackBuffer.GetHeight()) ); float fDpiWindow = static_cast(::GetDpiForWindow( m_hWnd )); float fDpiScale = fDpiWindow / USER_DEFAULT_SCREEN_DPI; if ( m_pImgLoadScreen != nullptr ) { Gdiplus::SizeF margins; margins.Width = 50.0f; margins.Height = 50.0f; Gdiplus::SizeF sizeWindow; sizeWindow.Width = std::max( 0.0f, m_imgBackBuffer.GetWidth() - (margins.Width * 2) ); sizeWindow.Height = std::max( 0.0f, m_imgBackBuffer.GetHeight() - (margins.Height * 2) ); // initialize the size of the image we draw to the ideal size Gdiplus::SizeF sizeImageOriginal; sizeImageOriginal.Width = static_cast(m_pImgLoadScreen->GetWidth()); sizeImageOriginal.Height = static_cast(m_pImgLoadScreen->GetHeight()); // DPI adjust Gdiplus::SizeF sizeImageOriginalDpi = sizeImageOriginal; sizeImageOriginalDpi.Width *= fDpiScale; sizeImageOriginalDpi.Height *= fDpiScale; Gdiplus::SizeF sizeImageResized = sizeImageOriginalDpi; if ( sizeImageOriginalDpi.Width > sizeWindow.Width ) { float fAspectRatio = sizeImageOriginalDpi.Height / sizeImageOriginalDpi.Width; Gdiplus::SizeF sizeNew; sizeNew.Width = sizeWindow.Width; sizeNew.Height = sizeWindow.Width * fAspectRatio; if ( sizeNew.Width < sizeImageResized.Width || sizeNew.Height < sizeImageResized.Height ) sizeImageResized = sizeNew; } if ( sizeImageOriginalDpi.Height > sizeWindow.Height ) { float fAspectRatio = sizeImageOriginalDpi.Width / sizeImageOriginalDpi.Height; Gdiplus::SizeF sizeNew; sizeNew.Height = sizeWindow.Height; sizeNew.Width = sizeWindow.Height * fAspectRatio; if ( sizeNew.Width < sizeImageResized.Width || sizeNew.Height < sizeImageResized.Height ) sizeImageResized = sizeNew; } Gdiplus::RectF rcSrc( 0, 0, sizeImageOriginal.Width, sizeImageOriginal.Height ); Gdiplus::RectF rcDst( ((sizeWindow.Width - sizeImageResized.Width) / 2.0f) + margins.Width, ((sizeWindow.Height - sizeImageResized.Height) / 2.0f) + margins.Height, sizeImageResized.Width, sizeImageResized.Height ); gfx.DrawImage( m_pImgLoadScreen, rcDst, rcSrc, Gdiplus::UnitPixel ); m_rcProgressArea = Gdiplus::RectF( 2.0f, rcDst.GetBottom(), static_cast(m_imgBackBuffer.GetWidth() - 4), margins.Height ); m_ProgressBar.DrawProgressBar( m_hWnd, gfx, m_rcProgressArea, m_Background ); } if ( m_pImgLogo != nullptr ) { Gdiplus::SizeF margins; margins.Width = 10.0f; margins.Height = 10.0f; Gdiplus::SizeF sizeWindow; sizeWindow.Width = std::max( 0.0f, m_imgBackBuffer.GetWidth() - (margins.Width * 2) ); sizeWindow.Height = std::max( 0.0f, m_imgBackBuffer.GetHeight() - (margins.Height * 2) ); // initialize the size of the image we draw to the ideal size Gdiplus::SizeF sizeImageOriginal; sizeImageOriginal.Width = static_cast(m_pImgLogo->GetWidth()); sizeImageOriginal.Height = static_cast(m_pImgLogo->GetHeight()); Gdiplus::SizeF sizeImageResized = sizeImageOriginal; sizeImageResized.Width /= 6.0f; sizeImageResized.Height /= 6.0f; // DPI adjust sizeImageResized.Width *= fDpiScale; sizeImageResized.Height *= fDpiScale; Gdiplus::RectF rcSrc( 0, 0, sizeImageOriginal.Width, sizeImageOriginal.Height ); Gdiplus::RectF rcDst( sizeWindow.Width - sizeImageResized.Width, sizeWindow.Height - sizeImageResized.Height, sizeImageResized.Width, sizeImageResized.Height ); // do not draw if there is no room if ( m_rcProgressArea.GetBottom() < rcDst.GetTop() ) { // invert colors for the light theme const float alpha = 0.25f; Gdiplus::ColorMatrix matrixLightTheme = { -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, alpha, 0, 0, 0, 0, 0, 1 }; Gdiplus::ColorMatrix matrixDarkTheme = { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, alpha, 0, 0, 0, 0, 0, 1 }; Gdiplus::ImageAttributes attrib; attrib.SetColorMatrix( m_bWindowsExplorerUsingLightTheme ? &matrixLightTheme : &matrixDarkTheme ); gfx.DrawImage( m_pImgLogo, rcDst, rcSrc, Gdiplus::UnitPixel, &attrib ); } } } void CUsdLoadScreenDlg::InvalidateProgressBar( Gdiplus::RectF &rcArea ) { RECT rc; rc.left = static_cast(rcArea.GetLeft()); rc.top = static_cast(rcArea.GetTop()); rc.right = static_cast(rcArea.GetRight()); rc.bottom = static_cast(rcArea.GetBottom()); InvalidateRect( &rc, FALSE ); } ================================================ FILE: UsdShellExtension/UsdLoadScreenDlg.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "resource.h" #include "UWPProgressBar.h" class CUsdLoadScreenDlg : public CDialogImpl { public: enum { IDD = IDD_LOADSCREEN }; void SetBackgroundColor( COLORREF color ); private: void OnFinalMessage( _In_ HWND hWnd ) override; void CreateBackBuffer( UINT width, UINT height ); void Draw( Gdiplus::Graphics &gfx ); void InvalidateProgressBar( Gdiplus::RectF &rcArea ); BEGIN_MSG_MAP( CUsdLoadScreenDlg ) MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog ) MESSAGE_HANDLER( WM_PAINT, OnPaint ) MESSAGE_HANDLER( WM_ERASEBKGND, OnEraseBkgnd ) MESSAGE_HANDLER( WM_SIZE, OnSize ) MESSAGE_HANDLER( WM_CTLCOLORDLG, OnCtlColorDlg ) MESSAGE_HANDLER( WM_TIMER, OnTimer ) END_MSG_MAP() LRESULT OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ); LRESULT OnPaint( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ); LRESULT OnEraseBkgnd( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ); LRESULT OnSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ); LRESULT OnCtlColorDlg( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ); LRESULT OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled ); CUWPProgressBar m_ProgressBar; CImage m_imgBackBuffer; HBRUSH m_hBackground = nullptr; ULONG_PTR m_gdiplusToken = 0; Gdiplus::Image *m_pImgLoadScreen = nullptr; Gdiplus::Image *m_pImgLogo = nullptr; Gdiplus::Color m_Background; HDC m_hDCBackbuffer = nullptr; Gdiplus::Graphics *m_pGfx = nullptr; Gdiplus::RectF m_rcProgressArea; bool m_bWindowsExplorerUsingLightTheme = true; }; class CAutoDpiAware { public: CAutoDpiAware(DPI_AWARENESS_CONTEXT ctx) { m_PreviousContext = ::GetThreadDpiAwarenessContext(); ::SetThreadDpiAwarenessContext( ctx ); } ~CAutoDpiAware() { ::SetThreadDpiAwarenessContext( m_PreviousContext ); } private: DPI_AWARENESS_CONTEXT m_PreviousContext; }; ================================================ FILE: UsdShellExtension/UsdMetadata.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "UsdMetadata.h" #include "UsdPropertyKeys.h" static std::string DictionaryToString(const pxr::VtDictionary &dict, std::string prefix = "") { // Exports all values on separate lines // Format: dict.key=value std::string result; for ( const std::pair& stat : dict ) { if ( stat.second.GetTypeid() == typeid(pxr::VtDictionary) ) { pxr::VtDictionary nestedDict = stat.second.Get(); std::string nestedPrefix = prefix; if ( !nestedPrefix.empty() ) nestedPrefix += "."; nestedPrefix += stat.first; result += DictionaryToString( nestedDict, nestedPrefix ); } else { std::string name = prefix; if ( !name.empty() ) name += "."; name += stat.first; std::stringstream ss; if ( stat.second.GetTypeid() == typeid(size_t) ) ss << name << "=" << stat.second.Get() << std::endl; else if ( stat.second.GetTypeid() == typeid(double) ) ss << name << "=" << stat.second.Get() << std::endl; else if ( stat.second.GetTypeid() == typeid(std::string) ) ss << name << "=" << stat.second << std::endl; else ss << name << "=" << "[UNKNOWN TYPE]" << std::endl; result += ss.str(); } } return result; } HRESULT ReadUsdMetadata( const pxr::SdfLayerRefPtr &rootLayer, const pxr::VtDictionary &customLayerData, IPropertyStoreCache* pPropertyStoreCache ) { HRESULT hr; std::string sComment = rootLayer->GetComment(); hr = StoreStringValue( pPropertyStoreCache, PKEY_Comment, sComment.c_str() ); std::string sDocumentation = rootLayer->GetDocumentation(); hr = StoreStringValue( pPropertyStoreCache, PKEY_USD_DOCUMENTATION, sDocumentation.c_str() ); std::string sCustomLayerData = DictionaryToString( customLayerData ); hr = StoreStringValue( pPropertyStoreCache, PKEY_USD_CUSTOMLAYERDATA, sCustomLayerData.c_str() ); return S_OK; } HRESULT WriteUsdMetadata( pxr::SdfLayerRefPtr &rootLayer, pxr::VtDictionary &customLayerData, IPropertyStoreCache *pPropertyStoreCache, bool &bIsDirty ) { UNREFERENCED_PARAMETER( customLayerData ); HRESULT hr; PSC_STATE state; hr = pPropertyStoreCache->GetState( PKEY_Comment, &state); if ( SUCCEEDED( hr ) && state == PSC_DIRTY ) { std::string sValue; hr = GetValueAsUTF8( pPropertyStoreCache, PKEY_Comment, sValue ); if ( SUCCEEDED( hr ) ) { rootLayer->SetComment( sValue ); bIsDirty = true; } } hr = pPropertyStoreCache->GetState( PKEY_USD_DOCUMENTATION, &state); if ( SUCCEEDED( hr ) && state == PSC_DIRTY ) { std::string sValue; hr = GetValueAsUTF8( pPropertyStoreCache, PKEY_USD_DOCUMENTATION, sValue ); if ( SUCCEEDED( hr ) ) { rootLayer->SetDocumentation( sValue ); bIsDirty = true; } } return S_OK; } HRESULT IsMetadataPropertyWritable( REFPROPERTYKEY key ) { if ( IsEqualPropertyKey( key, PKEY_Comment ) /*|| IsEqualPropertyKey( key, PKEY_USD_DOCUMENTATION )*/ ) return S_OK; return S_FALSE; } ================================================ FILE: UsdShellExtension/UsdMetadata.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once HRESULT ReadUsdMetadata( const pxr::SdfLayerRefPtr &rootLayer, const pxr::VtDictionary &customLayerData, IPropertyStoreCache *pPropertyStoreCache ); HRESULT WriteUsdMetadata( pxr::SdfLayerRefPtr &rootLayer, pxr::VtDictionary &customLayerData, IPropertyStoreCache *pPropertyStoreCache, bool &bIsDirty ); HRESULT IsMetadataPropertyWritable( REFPROPERTYKEY key ); inline HRESULT StoreStringValue( IPropertyStoreCache *pPropertyStoreCache, REFPROPERTYKEY key, LPCWSTR sValue ) { HRESULT hr; PROPVARIANT propvar = {}; hr = InitPropVariantFromString( sValue, &propvar ); if ( SUCCEEDED( hr ) ) { hr = PSCoerceToCanonicalValue( key, &propvar ); if ( SUCCEEDED( hr ) ) { hr = pPropertyStoreCache->SetValueAndState( key, &propvar, PSC_NORMAL ); } PropVariantClear( &propvar ); } return hr; } inline HRESULT StoreStringValue( IPropertyStoreCache *pPropertyStoreCache, REFPROPERTYKEY key, LPCSTR sValue ) { return StoreStringValue( pPropertyStoreCache, key, ATL::CA2W( sValue, CP_UTF8 ) ); } inline HRESULT StoreUInt64Value( IPropertyStoreCache *pPropertyStoreCache, REFPROPERTYKEY key, uint64_t nValue ) { HRESULT hr; PROPVARIANT propvar = {}; hr = InitPropVariantFromUInt64( nValue, &propvar ); if ( SUCCEEDED( hr ) ) { hr = pPropertyStoreCache->SetValueAndState( key, &propvar, PSC_NORMAL ); PropVariantClear( &propvar ); } return hr; } inline HRESULT StoreDateValue( IPropertyStoreCache *pPropertyStoreCache, REFPROPERTYKEY key, const FILETIME *pft ) { HRESULT hr; PROPVARIANT propvar = {}; hr = InitPropVariantFromFileTime( pft, &propvar ); if ( SUCCEEDED( hr ) ) { hr = pPropertyStoreCache->SetValueAndState( key, &propvar, PSC_NORMAL ); PropVariantClear( &propvar ); } return hr; } inline HRESULT GetValueAsUTF8( IPropertyStoreCache *pPropertyStoreCache, REFPROPERTYKEY key, std::string &value ) { HRESULT hr; PROPVARIANT propVariant; hr = pPropertyStoreCache->GetValue( key, &propVariant ); if ( SUCCEEDED( hr ) ) { LPCWSTR sUTF16Value = PropVariantToStringWithDefault( propVariant, L"" ); value = ATL::CW2A( sUTF16Value, CP_UTF8 ); return hr; } return hr; } ================================================ FILE: UsdShellExtension/UsdPropertyKeys.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #define INITGUID #include // {3B7AB16C-C876-461C-BBA5-2F1182A834D1} DEFINE_PROPERTYKEY(PKEY_USD_PROPGROUP, 0x3b7ab16c, 0xc876, 0x461c, 0xbb, 0xa5, 0x2f, 0x11, 0x82, 0xa8, 0x34, 0xd1, PID_FIRST_USABLE + 0); // {3CEF792B-F66F-42E1-A59D-7BE261E682AE} DEFINE_PROPERTYKEY(PKEY_USD_DOCUMENTATION, 0x3cef792b, 0xf66f, 0x42e1, 0xa5, 0x9d, 0x7b, 0xe2, 0x61, 0xe6, 0x82, 0xae, PID_FIRST_USABLE + 1); // {89379215-052D-429D-9A74-6D220E41C86D} DEFINE_PROPERTYKEY(PKEY_USD_CUSTOMLAYERDATA, 0x89379215, 0x52d, 0x429d, 0x9a, 0x74, 0x6d, 0x22, 0xe, 0x41, 0xc8, 0x6d, PID_FIRST_USABLE + 2); #undef INITGUID ================================================ FILE: UsdShellExtension/UsdPropertyKeys.propdesc ================================================ ================================================ FILE: UsdShellExtension/UsdShellExtension-monolithic.manifest ================================================ ================================================ FILE: UsdShellExtension/UsdShellExtension-shared.manifest ================================================ ================================================ FILE: UsdShellExtension/UsdShellExtension.vcxproj ================================================ Release x64 Debug x64 NotUsing NotUsing /Zc:inline- %(AdditionalOptions) NotUsing NotUsing Create stdafx.h Create stdafx.h {f12e597b-b731-4f5a-bec3-980d20159320} 16.0 Win32Proj {9974380d-c9c6-4cf4-8aa2-7d564eb8c4e8} UsdShellExtension 10.0.14393.0 DynamicLibrary false v141 false Unicode DynamicLibrary true v141 false Unicode RegistryView.Registry32 RegistryView.Registry64 $(PythonVersion)-32 $(PythonVersion) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $(PythonHome)python.exe $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) _d $([System.IO.Path]::GetDirectoryName($(PythonExe)))\python$(PythonDebugSuffix).exe $(PythonExe) false $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ false $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ Level4 true true NDEBUG;USDSHELLEXTENSION_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) false $(SolutionDir);$(PythonHome)include;$(OutDir);%(AdditionalIncludeDirectories) Use true AnySuitable MaxSpeed Windows false false true Gdiplus.lib;Shcore.lib;Propsys.lib;Pathcch.lib;%(AdditionalDependencies) ShellExt.def $(PythonHome)libs;%(AdditionalLibraryDirectories) $(OutDir);$(SolutionDir);$(ProjectDir)..\shared;%(AdditionalIncludeDirectories) $(OutDir)$(ProjectName).tlb xcopy "$(ProjectDir)plugInfo.json" "$(TargetDir)" /I /Y /F /R xcopy "$(ProjectDir)register.bat" "$(TargetDir)" /I /Y /F /R xcopy "$(ProjectDir)unregister.bat" "$(TargetDir)" /I /Y /F /R xcopy "$(ProjectDir)UsdShellExtension.ini" "$(TargetDir)" /I /Y /D /R xcopy "$(SolutionDir)NOTICE.txt" "$(TargetDir)" /I /Y /D /R xcopy "$(SolutionDir)LICENSE.txt" "$(TargetDir)" /I /Y /D /R %(Command) Level4 true true true _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) false $(SolutionDir);$(PythonHome)include;$(OutDir);%(AdditionalIncludeDirectories) Disabled Disabled Use Windows true true true Gdiplus.lib;Shcore.lib;Propsys.lib;Pathcch.lib;%(AdditionalDependencies) ShellExt.def $(PythonHome)libs;%(AdditionalLibraryDirectories) $(OutDir);$(SolutionDir);$(ProjectDir)..\shared;%(AdditionalIncludeDirectories) $(OutDir)$(ProjectName).tlb xcopy "$(ProjectDir)plugInfo.json" "$(TargetDir)" /I /Y /F /R xcopy "$(ProjectDir)register.bat" "$(TargetDir)" /I /Y /F /R xcopy "$(ProjectDir)unregister.bat" "$(TargetDir)" /I /Y /F /R xcopy "$(ProjectDir)UsdShellExtension.ini" "$(TargetDir)" /I /Y /D /R xcopy "$(SolutionDir)NOTICE.txt" "$(TargetDir)" /I /Y /D /R xcopy "$(SolutionDir)LICENSE.txt" "$(TargetDir)" /I /Y /D /R %(Command) ================================================ FILE: UsdShellExtension/UsdShellExtension.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {d9bfe0ff-29ed-458b-8cd8-ec1eae4c9c07} {ee807d35-c06f-4914-b5d4-32a300dc72d8} Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Shared Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Shared Source Files Resource Files Resource Files Resource Files Resource Files Resource Files Files Files Files Files Source Files Resource Files Resource Files Resource Files Resource Files ================================================ FILE: UsdShellExtension/plugInfo.json ================================================ { "Plugins": [ { "Info": { "Types": { "ArResolverShellExtension" : { "bases": ["ArResolver"] } } }, "LibraryPath": "UsdShellExtension.dll", "Name": "ArResolverShellExtension", "Type": "library" } ] } ================================================ FILE: UsdShellExtension/register.bat ================================================ REM This batch needs to be executed as administrator! @echo off cd /D %~dp0 set /a success = 1 echo UsdPreviewLocalServer.exe /RegServer start /wait UsdPreviewLocalServer.exe /RegServer if %ERRORLEVEL% NEQ 0 ( echo UsdPreviewLocalServer.exe failed to register! set /a success = 0 ) echo UsdPythonToolsLocalServer.exe /RegServer start /wait UsdPythonToolsLocalServer.exe /RegServer if %ERRORLEVEL% NEQ 0 ( echo UsdPythonToolsLocalServer.exe failed to register! set /a success = 0 ) echo UsdSdkToolsLocalServer.exe /RegServer start /wait UsdSdkToolsLocalServer.exe /RegServer if %ERRORLEVEL% NEQ 0 ( echo UsdSdkToolsLocalServer.exe failed to register! set /a success = 0 ) echo regsvr32.exe /n /i UsdShellExtension.dll regsvr32.exe /n /i UsdShellExtension.dll if %success% NEQ 1 ( pause exit /b 1 ) ================================================ FILE: UsdShellExtension/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by ShellExt.rc // #define IDR_REGISTRY_SHELLPREVIEWHANDLERIMPL 112 #define IDI_ICON_USD 113 #define IDR_REGISTRY_SHELLTHUMBNAILPROVIDERIMPL 114 #define IDR_REGISTRY_MODULE 115 #define IDD_LOADSCREEN 116 #define IDB_LOADSCREEN 118 #define IDR_REGISTRY_SHELLPROPERTYSTOREIMPL 119 #define IDS_USD_DOCUMENTATION_LABEL 123 #define IDR_XML_PROPDESC_USD 124 #define IDS_USD_DOCUMENTATION_INVITATIONTEXT 124 #define IDS_USD_DOCUMENTATION_MNEMONICS 125 #define IDB_LOGO 125 #define IDS_USD_PROPGROUP_USD_LABEL 126 #define IDS_FILE_USD 138 #define IDS_FILE_USDA 139 #define IDS_FILE_USDC 140 #define IDS_FILE_USDZ 141 #define IDS_SHELL_VIEW 142 #define IDS_SHELL_EDIT 143 #define IDS_SHELL_CRATE 144 #define IDS_SHELL_UNCRATE 145 #define IDS_SHELL_FLATTEN 146 #define IDS_SHELL_REFRESHTHUMBNAIL 147 #define IDS_SHELL_STATS 148 #define IDS_USD_CUSTOMLAYERDATA_LABEL 149 #define IDS_USD_CUSTOMLAYERDATA_MNEMONICS 150 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 126 #define _APS_NEXT_COMMAND_VALUE 40011 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: UsdShellExtension/stdafx.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" ================================================ FILE: UsdShellExtension/stdafx.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #define WIN32_LEAN_AND_MEAN #define NOBITMAP #define NOMCX #define NOSERVICE #define NOMINMAX #define GDIPVER 0x0110 #include #define _WIN32_WINNT 0x0A00 #include #include #include #include #pragma warning( push ) #pragma warning( disable : 4244 4305 5033 4100 4201 4245 4127 ) #include #include #include #include #include #include #include #include #include #include #include #include #pragma warning( pop ) #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ================================================ FILE: UsdShellExtension/unregister.bat ================================================ REM This batch needs to be executed as administrator! @echo off cd /D %~dp0 set /a success = 1 echo UsdPreviewLocalServer.exe /UnregServer start /wait UsdPreviewLocalServer.exe /UnregServer if %ERRORLEVEL% NEQ 0 ( echo UsdPreviewLocalServer.exe failed to unregister! set /a success = 0 ) echo UsdPythonToolsLocalServer.exe /UnregServer start /wait UsdPythonToolsLocalServer.exe /UnregServer if %ERRORLEVEL% NEQ 0 ( echo UsdPythonToolsLocalServer.exe failed to unregister! set /a success = 0 ) echo UsdSdkToolsLocalServer.exe /UnregServer start /wait UsdSdkToolsLocalServer.exe /UnregServer if %ERRORLEVEL% NEQ 0 ( echo UsdSdkToolsLocalServer.exe failed to unregister! set /a success = 0 ) echo regsvr32.exe /u UsdShellExtension.dll regsvr32.exe /u UsdShellExtension.dll if %success% NEQ 1 ( pause exit /b 1 ) ================================================ FILE: UsdShellExtension.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.28307.1209 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UsdPreviewHandlerPython", "UsdPreviewHandlerPython\UsdPreviewHandlerPython.vcxproj", "{248F687E-4028-4243-87B8-2312F57BE8A5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UsdPreviewLocalServer", "UsdPreviewHandlerServer\UsdPreviewLocalServer.vcxproj", "{279AFA6D-6E35-4798-BA63-8A7E15D11185}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UsdShellExtension", "UsdShellExtension\UsdShellExtension.vcxproj", "{9974380D-C9C6-4CF4-8AA2-7D564EB8C4E8}" ProjectSection(ProjectDependencies) = postProject {279AFA6D-6E35-4798-BA63-8A7E15D11185} = {279AFA6D-6E35-4798-BA63-8A7E15D11185} {248F687E-4028-4243-87B8-2312F57BE8A5} = {248F687E-4028-4243-87B8-2312F57BE8A5} {EA717BDA-3304-439B-BEC8-408D9CE9F3FB} = {EA717BDA-3304-439B-BEC8-408D9CE9F3FB} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UsdSdkToolsLocalServer", "UsdSdkToolsServer\UsdSdkToolsLocalServer.vcxproj", "{EA717BDA-3304-439B-BEC8-408D9CE9F3FB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UsdPythonToolsLocalServer", "UsdPythonToolsServer\UsdPythonToolsLocalServer.vcxproj", "{6AD79C79-3A9D-4C39-B028-C45072541C28}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F2EEFD0F-82FF-4404-94E5-CD2F3837BDA9}" ProjectSection(SolutionItems) = preProject atviversion.h = atviversion.h BUILDING.md = BUILDING.md README.md = README.md EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UsdShellExtensionInstaller", "UsdShellExtensionInstaller\UsdShellExtensionInstaller.vcxproj", "{1390252A-71E2-4C4E-B874-301909F40CBA}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Property Sheets", "Property Sheets", "{8889FDB0-64A4-4AB7-A539-D3328F0846E9}" ProjectSection(SolutionItems) = preProject atviversion.props = atviversion.props boost.props = boost.props nsis.props = nsis.props python.props = python.props usd-monolithic.props = usd-monolithic.props usd-shared.props = usd-shared.props usd.props = usd.props EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EventViewerMessages", "shared\EventViewerMessages.vcxproj", "{F12E597B-B731-4F5A-BEC3-980D20159320}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {248F687E-4028-4243-87B8-2312F57BE8A5}.Debug|x64.ActiveCfg = Debug|x64 {248F687E-4028-4243-87B8-2312F57BE8A5}.Debug|x64.Build.0 = Debug|x64 {248F687E-4028-4243-87B8-2312F57BE8A5}.Release|x64.ActiveCfg = Release|x64 {248F687E-4028-4243-87B8-2312F57BE8A5}.Release|x64.Build.0 = Release|x64 {279AFA6D-6E35-4798-BA63-8A7E15D11185}.Debug|x64.ActiveCfg = Debug|x64 {279AFA6D-6E35-4798-BA63-8A7E15D11185}.Debug|x64.Build.0 = Debug|x64 {279AFA6D-6E35-4798-BA63-8A7E15D11185}.Release|x64.ActiveCfg = Release|x64 {279AFA6D-6E35-4798-BA63-8A7E15D11185}.Release|x64.Build.0 = Release|x64 {9974380D-C9C6-4CF4-8AA2-7D564EB8C4E8}.Debug|x64.ActiveCfg = Debug|x64 {9974380D-C9C6-4CF4-8AA2-7D564EB8C4E8}.Debug|x64.Build.0 = Debug|x64 {9974380D-C9C6-4CF4-8AA2-7D564EB8C4E8}.Release|x64.ActiveCfg = Release|x64 {9974380D-C9C6-4CF4-8AA2-7D564EB8C4E8}.Release|x64.Build.0 = Release|x64 {EA717BDA-3304-439B-BEC8-408D9CE9F3FB}.Debug|x64.ActiveCfg = Debug|x64 {EA717BDA-3304-439B-BEC8-408D9CE9F3FB}.Debug|x64.Build.0 = Debug|x64 {EA717BDA-3304-439B-BEC8-408D9CE9F3FB}.Release|x64.ActiveCfg = Release|x64 {EA717BDA-3304-439B-BEC8-408D9CE9F3FB}.Release|x64.Build.0 = Release|x64 {6AD79C79-3A9D-4C39-B028-C45072541C28}.Debug|x64.ActiveCfg = Debug|x64 {6AD79C79-3A9D-4C39-B028-C45072541C28}.Debug|x64.Build.0 = Debug|x64 {6AD79C79-3A9D-4C39-B028-C45072541C28}.Release|x64.ActiveCfg = Release|x64 {6AD79C79-3A9D-4C39-B028-C45072541C28}.Release|x64.Build.0 = Release|x64 {1390252A-71E2-4C4E-B874-301909F40CBA}.Debug|x64.ActiveCfg = Debug|x64 {1390252A-71E2-4C4E-B874-301909F40CBA}.Release|x64.ActiveCfg = Release|x64 {F12E597B-B731-4F5A-BEC3-980D20159320}.Debug|x64.ActiveCfg = Debug|x64 {F12E597B-B731-4F5A-BEC3-980D20159320}.Debug|x64.Build.0 = Debug|x64 {F12E597B-B731-4F5A-BEC3-980D20159320}.Release|x64.ActiveCfg = Release|x64 {F12E597B-B731-4F5A-BEC3-980D20159320}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E4AEC1C0-464E-4B29-B0FA-8841731E8735} EndGlobalSection EndGlobal ================================================ FILE: UsdShellExtensionInstaller/CmdLineArgs.nsh ================================================ !include FileFunc.nsh ;-------------------------------- Var CmdLineUsdPath Var CmdLineUsdPythonPath Var CmdLineUsdPxrPluginPathName Var CmdLinePythonPath Var CmdLinePythonPythonPath Var CmdLineRendererPreview Var CmdLineRendererThumbnail Var CmdLineRendererView ;-------------------------------- Function ParseCommandLine ${GetParameters} $R0 ClearErrors ${GetOptions} $R0 /USD_PATH= $CmdLineUsdPath ${GetOptions} $R0 /USD_PYTHONPATH= $CmdLineUsdPythonPath ${GetOptions} $R0 /USD_PXRPLUGINPATHNAME= $CmdLineUsdPxrPluginPathName ${GetOptions} $R0 /PYTHON_PATH= $CmdLinePythonPath ${GetOptions} $R0 /PYTHON_PYTHONPATH= $CmdLinePythonPythonPath ${GetOptions} $R0 /RENDERER_PREVIEW= $CmdLineRendererPreview ${GetOptions} $R0 /RENDERER_THUMBNAIL= $CmdLineRendererThumbnail ${GetOptions} $R0 /RENDERER_VIEW= $CmdLineRendererView FunctionEnd ================================================ FILE: UsdShellExtensionInstaller/RestartManager.nsh ================================================ ;-------------------------------- !define MAX_PATH 260 !define CCH_RM_SESSION_KEY 33 !define RmForceShutdown 0x1 !define RmShutdownOnlyRegistered 0x10 ;-------------------------------- Var RmExplorerSession Var RmApplicationSession Var RmWindowsSearchSession ;-------------------------------- !macro ShutdownExplorer UN Function ${UN}ShutdownExplorer SetDetailsPrint textonly DetailPrint "Shutting down Windows Explorer..." SetDetailsPrint listonly System::StrAlloc ${CCH_RM_SESSION_KEY} Pop $0 System::Call 'Rstrtmgr::RmStartSession(*i .R1, i 0, p $0) i.R0' System::Free $0 StrCpy $RmExplorerSession $R1 DetailPrint "Shutting down Windows Explorer" StrCpy $0 "$WINDIR\explorer.exe" System::Call '*(w r0)p.R1 ?2' System::Call 'Rstrtmgr::RmRegisterResources(i $RmExplorerSession, i 1, p R1, i 0, p n, i 0, p n) i.R0' System::Call 'Rstrtmgr::RmShutdown(i $RmExplorerSession, i 0, p n) i.R0' FunctionEnd !macroend !insertmacro ShutdownExplorer "" !insertmacro ShutdownExplorer "un." ;-------------------------------- !macro RestartExplorer UN Function ${UN}RestartExplorer SetDetailsPrint textonly DetailPrint "Restarting Windows Explorer..." SetDetailsPrint listonly DetailPrint "Restarting Windows Explorer" System::Call 'Rstrtmgr::RmRestart(i $RmExplorerSession, i 0, p n) i.R0' System::Call 'Rstrtmgr::RmEndSession(i $RmExplorerSession) i.R0' FunctionEnd !macroend !insertmacro RestartExplorer "" !insertmacro RestartExplorer "un." ;-------------------------------- !macro ShutdownWindowsSearch UN Function ${UN}ShutdownWindowsSearch SetDetailsPrint textonly DetailPrint "Shutting down Windows Search..." SetDetailsPrint listonly System::StrAlloc ${CCH_RM_SESSION_KEY} Pop $0 System::Call 'Rstrtmgr::RmStartSession(*i .R1, i 0, p $0) i.R0' System::Free $0 StrCpy $RmWindowsSearchSession $R1 DetailPrint "Shutting down Windows Search" StrCpy $0 "wsearch" System::Call '*(w r0)p.R1 ?2' System::Call 'Rstrtmgr::RmRegisterResources(i $RmWindowsSearchSession, i 0, p n, i 0, p n, i 1, p R1) i.R0' System::Call 'Rstrtmgr::RmShutdown(i $RmWindowsSearchSession, i 0, p n) i.R0' FunctionEnd !macroend !insertmacro ShutdownWindowsSearch "" !insertmacro ShutdownWindowsSearch "un." ;-------------------------------- !macro RestartWindowsSearch UN Function ${UN}RestartWindowsSearch SetDetailsPrint textonly DetailPrint "Restarting Windows Search..." SetDetailsPrint listonly DetailPrint "Restarting Windows Search" System::Call 'Rstrtmgr::RmRestart(i $RmWindowsSearchSession, i 0, p n) i.R0' System::Call 'Rstrtmgr::RmEndSession(i $RmWindowsSearchSession) i.R0' FunctionEnd !macroend !insertmacro RestartWindowsSearch "" !insertmacro RestartWindowsSearch "un." ;-------------------------------- !macro ShutdownApplications UN Function ${UN}ShutdownApplications SetDetailsPrint textonly DetailPrint "Shutting down applications..." SetDetailsPrint listonly System::StrAlloc ${CCH_RM_SESSION_KEY} Pop $0 System::Call 'Rstrtmgr::RmStartSession(*i .R1, i 0, p $0) i.R0' System::Free $0 StrCpy $RmApplicationSession $R1 StrCpy $0 "$INSTDIR\UsdShellExtension.dll" StrCpy $1 "$INSTDIR\tbb.dll" StrCpy $2 "$INSTDIR\tbbmalloc.dll" StrCpy $3 "$INSTDIR\${BOOSTDLL}" StrCpy $4 "$INSTDIR\${PYTHONDLL}" StrCpy $5 "$INSTDIR\usd_ms.dll" StrCpy $6 "$INSTDIR\UsdPreviewHandler.pyd" System::Call '*(w r0, w r1, w r2, w r3, w r4, w r5, w r6)p.R1 ?2' System::Call 'Rstrtmgr::RmRegisterResources(i $RmApplicationSession, i 6, p R1, i 0, p n, i 1, p R2) i.R0' DetailPrint "Shutting down applications using the USD Shell Extension" ; only shutdown applications that can restart System::Call 'Rstrtmgr::RmShutdown(i $RmApplicationSession, i ${RmShutdownOnlyRegistered}, p n) i.R0' FunctionEnd !macroend !insertmacro ShutdownApplications "" !insertmacro ShutdownApplications "un." ;-------------------------------- !macro RestartApplications UN Function ${UN}RestartApplications SetDetailsPrint textonly DetailPrint "Restarting Applications..." SetDetailsPrint listonly DetailPrint "Restarting applications that were using the Shell Extension" System::Call 'Rstrtmgr::RmRestart(i $RmApplicationSession, i 0, p n) i.R0' System::Call 'Rstrtmgr::RmEndSession(i $RmApplicationSession) i.R0' FunctionEnd !macroend !insertmacro RestartApplications "" !insertmacro RestartApplications "un." ;-------------------------------- !macro ShutdownCOMServers UN Function ${UN}ShutdownCOMServers SetDetailsPrint textonly DetailPrint "Shutting down COM servers..." SetDetailsPrint listonly System::StrAlloc ${CCH_RM_SESSION_KEY} Pop $0 System::Call 'Rstrtmgr::RmStartSession(*i .R9, i 0, p $0) i.R0' System::Free $0 StrCpy $0 "$INSTDIR\UsdPreviewLocalServer.exe" StrCpy $1 "$INSTDIR\UsdPythonToolsLocalServer.exe" StrCpy $2 "$INSTDIR\UsdSdkToolsLocalServer.exe" System::Call '*(w r0, w r1, w r2)p.R1 ?2' System::Call 'Rstrtmgr::RmRegisterResources(i R9, i 3, p R1, i 0, p n, i 0, p n) i.R0' System::Call 'Rstrtmgr::RmShutdown(i R9, i ${RmForceShutdown}, p n) i.R0' System::Call 'Rstrtmgr::RmEndSession(i R9) i.R0' FunctionEnd !macroend !insertmacro ShutdownCOMServers "" !insertmacro ShutdownCOMServers "un." ================================================ FILE: UsdShellExtensionInstaller/ShellLinkSetRunAs.nsh ================================================ !include LogicLib.nsh !ifndef IPersistFile !define IPersistFile {0000010b-0000-0000-c000-000000000046} !endif !ifndef CLSID_ShellLink !define CLSID_ShellLink {00021401-0000-0000-C000-000000000046} !define IID_IShellLinkA {000214EE-0000-0000-C000-000000000046} !define IID_IShellLinkW {000214F9-0000-0000-C000-000000000046} !define IShellLinkDataList {45e2b4ae-b1c3-11d0-b92f-00a0c90312e1} !ifdef NSIS_UNICODE !define IID_IShellLink ${IID_IShellLinkW} !else !define IID_IShellLink ${IID_IShellLinkA} !endif !endif Function ShellLinkSetRunAs System::Store S pop $9 System::Call "ole32::CoCreateInstance(g'${CLSID_ShellLink}',i0,i1,g'${IID_IShellLink}',*i.r1)i.r0" ${If} $0 = 0 System::Call "$1->0(g'${IPersistFile}',*i.r2)i.r0" ;QI ${If} $0 = 0 System::Call "$2->5(w '$9',i 0)i.r0" ;Load ${If} $0 = 0 System::Call "$1->0(g'${IShellLinkDataList}',*i.r3)i.r0" ;QI ${If} $0 = 0 System::Call "$3->6(*i.r4)i.r0" ;GetFlags ${If} $0 = 0 System::Call "$3->7(i $4|0x2000)i.r0" ;SetFlags ;SLDF_RUNAS_USER ${If} $0 = 0 System::Call "$2->6(w '$9',i1)i.r0" ;Save ${EndIf} ${EndIf} System::Call "$3->2()" ;Release ${EndIf} System::Call "$2->2()" ;Release ${EndIf} ${EndIf} System::Call "$1->2()" ;Release ${EndIf} push $0 System::Store L FunctionEnd !macro ShellLinkSetRunAs link push `${link}` Call ShellLinkSetRunAs !macroend ================================================ FILE: UsdShellExtensionInstaller/UsdConfigPage.nsh ================================================ ;-------------------------------- ; UsdConfigPage !define /ifndef WS_BORDER 0x00800000 !define USDCONFIGCONFIGPATH_STYLE ${DEFAULT_STYLES}|${WS_BORDER}|${ES_AUTOHSCROLL} !define USDCONFIGCONFIGPATH_EXSTYLE 0;${WS_EX_STATICEDGE} Var hWndUsdConfigDlg Var hWndUsdConfigLabelAll Var hWndUsdConfigLabelCurrent Var hWndUsdConfigConfigPathAll Var hWndUsdConfigConfigPathCurrent Var hWndUsdConfigButtonShowAll Var hWndUsdConfigButtonShowCurrent Function USDConfigPage !insertmacro MUI_HEADER_TEXT "USD Shell Extension Configuration File" "" nsDialogs::Create 1018 Pop $hWndUsdConfigDlg ${If} $hWndUsdConfigDlg == error Abort ${EndIf} ${NSD_CreateLabel} 0 0 100% 40u "This file contains the configuration for the USD Shell Extension. \ The configuration can be modified at any time and the changes will be reflected immeditately.$\r$\n$\r$\n\ The local user configuration file will override the all users configuration file." SetShellVarContext all ${NSD_CreateLabel} 0 50u 100% 10u "All Users" Pop $hWndUsdConfigLabelAll nsDialogs::CreateControl "${__NSD_Text_CLASS}" "${USDCONFIGCONFIGPATH_STYLE}" "${USDCONFIGCONFIGPATH_EXSTYLE}" 0 60u 100% 12u "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" Pop $hWndUsdConfigConfigPathAll ${NSD_Edit_SetReadOnly} $hWndUsdConfigConfigPathAll 1 ${NSD_CreateButton} -100u 75u 100u 15u "Show in Explorer" Pop $hWndUsdConfigButtonShowAll ${NSD_OnClick} $hWndUsdConfigButtonShowAll USDConfigPageShowAllClick SetShellVarContext current ${NSD_CreateLabel} 0 95u 100% 10u "Local User" Pop $hWndUsdConfigLabelCurrent nsDialogs::CreateControl "${__NSD_Text_CLASS}" "${USDCONFIGCONFIGPATH_STYLE}" "${USDCONFIGCONFIGPATH_EXSTYLE}" 0 105u 100% 12u "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" Pop $hWndUsdConfigConfigPathCurrent ${NSD_Edit_SetReadOnly} $hWndUsdConfigConfigPathCurrent 1 ${NSD_CreateButton} -100u 120u 100u 15u "Show in Explorer" Pop $hWndUsdConfigButtonShowCurrent ${NSD_OnClick} $hWndUsdConfigButtonShowCurrent USDConfigPageShowCurrentClick ;CreateFont $0 "$(^Font)" "8" "700"; size 8 weight 700 makes it bold ;SendMessage $hWndUsdConfigLabelCurrent ${WM_SETFONT} $0 0 ;SendMessage $hWndUsdConfigLabelAll ${WM_SETFONT} $0 0 nsDialogs::Show FunctionEnd Function USDConfigPageLeave FunctionEnd Function USDConfigPageShowAllClick SetShellVarContext all ExecWait 'explorer.exe /n,/select,"$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini"' FunctionEnd Function USDConfigPageShowCurrentClick SetShellVarContext current ExecWait 'explorer.exe /n,/select,"$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini"' FunctionEnd ================================================ FILE: UsdShellExtensionInstaller/UsdConfigUtils.nsh ================================================ Function ReadConfigFile pop $0 ; file pop $1 ; section pop $2 ; key pop $3 ; value System::StrAlloc 1024 Pop $R1 System::Call 'Kernel32::GetPrivateProfileStringW(w r1, w r2, t "", p R1, i 1024, w r0)' ; we can only store a max of 1024 characters in NSIS registers System::Call "*$R1(&t1024 .s)" System::Free $R1 FunctionEnd !macro ReadConfigFile file section key value push `${value}` push `${key}` push `${section}` push `${file}` Call ReadConfigFile !macroend Function WriteConfigFile pop $0 ; file pop $1 ; section pop $2 ; key pop $3 ; value System::Call 'Kernel32::WritePrivateProfileStringW(w r1, w r2, w r3, w r0)' FunctionEnd !macro WriteConfigFile file section key value push `${value}` push `${key}` push `${section}` push `${file}` Call WriteConfigFile !macroend Function PatchConfigFile pop $0 ; file pop $1 ; section pop $2 ; key pop $3 ; value ; a string that someone isn't going to enter by hand StrCpy $R0 "{3D3157AE-140F-49B9-9283-57051DB19E37}" System::StrAlloc 8192 Pop $R1 System::Call 'Kernel32::GetPrivateProfileStringW(w r1, w r2, w R0, p R1, i 8192, w r0)' ; copy the returned string into $R2 ; we can only store a max of 1024 characters in NSIS registers System::Call "*$R1(&t1024 .R2)" System::Free $R1 ${If} $R2 == "{3D3157AE-140F-49B9-9283-57051DB19E37}" System::Call 'Kernel32::WritePrivateProfileStringW(w r1, w r2, w r3, w r0)' ${EndIf} FunctionEnd !macro PatchConfigFile file section key value push `${value}` push `${key}` push `${section}` push `${file}` Call PatchConfigFile !macroend ================================================ FILE: UsdShellExtensionInstaller/UsdPathPage.nsh ================================================ ;-------------------------------- ; UsdPathPage Var hWndUsdPathDlg Var hWndUsdPathEditPath Var hWndUsdPathEditPythonPath Var hWndUsdPathEditPxrPluginPath Var hWndUsdPathButtonBuild ;Var hWndUsdPathConfigPath Function USDPathPage !insertmacro MUI_HEADER_TEXT "USD Libraries and Tools" "Please set the following USD environment variables." nsDialogs::Create 1018 Pop $hWndUsdPathDlg ${If} $hWndUsdPathDlg == error Abort ${EndIf} SetShellVarContext all ${NSD_CreateLabel} 0 0 100% 10u "PATH" !insertmacro ReadConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PATH" "" Pop $R0 ${NSD_CreateText} 0 10u 100% 12u $R0 Pop $hWndUsdPathEditPath ${NSD_CreateLabel} 0 28u 100% 10u "PYTHONPATH" !insertmacro ReadConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PYTHONPATH" "" Pop $R0 ${NSD_CreateText} 0 38u 100% 12u $R0 Pop $hWndUsdPathEditPythonPath ${NSD_CreateLabel} 0 56u 100% 10u "PXR_PLUGINPATH_NAME" !insertmacro ReadConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PXR_PLUGINPATH_NAME" "" Pop $R0 ${NSD_CreateText} 0 66u 100% 12u $R0 Pop $hWndUsdPathEditPxrPluginPath ${NSD_CreateButton} -140u 90u 140u 15u "Set using root USD folder" Pop $hWndUsdPathButtonBuild ${NSD_OnClick} $hWndUsdPathButtonBuild USDPathPageBuildClick ;${NSD_CreateLabel} 0 -30u 100% 10u "Configuration File" ;${NSD_CreateText} 0 -18u 100% 12u "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" ;Pop $hWndUsdPathConfigPath ;${NSD_Edit_SetReadOnly} $hWndUsdPathConfigPath 1 nsDialogs::Show FunctionEnd Function USDPathPageLeave SetShellVarContext all ${NSD_GetText} $hWndUsdPathEditPath $0 !insertmacro WriteConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PATH" $0 ${NSD_GetText} $hWndUsdPathEditPythonPath $0 !insertmacro WriteConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PYTHONPATH" $0 ${NSD_GetText} $hWndUsdPathEditPxrPluginPath $0 !insertmacro WriteConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PXR_PLUGINPATH_NAME" $0 FunctionEnd Function USDPathPageBuildClick nsDialogs::SelectFolderDialog "Select root folder of USD installation" Pop $R0 ${If} $R0 != error ${NSD_SetText} $hWndUsdPathEditPath "$R0\bin\;$R0\lib\" ${NSD_SetText} $hWndUsdPathEditPythonPath "$R0\lib\python" ${NSD_SetText} $hWndUsdPathEditPxrPluginPath "" ${EndIf} FunctionEnd ================================================ FILE: UsdShellExtensionInstaller/UsdShellExtensionInstaller.nsi ================================================ ; Copyright 2021 Activision Publishing, Inc. ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ;-------------------------------- ;Includes !include "MUI2.nsh" !include "Library.nsh" !include "logiclib.nsh" !include "x64.nsh" !define LIBRARY_X64 !define /ifndef OUT_FILE "setup.exe" !define /ifndef VER_MAJOR 0 !define /ifndef VER_MINOR 00 !define /ifndef VER_REVISION 00 !define /ifndef VER_BUILD 00 !define /ifndef VER_PRODUCTNAME "" !define /ifndef VER_COMPANYNAME "" !define /ifndef VER_COPYRIGHT "" !define /ifndef VERSION "${VER_MAJOR}.${VER_MINOR}" !define /ifndef USD_VERSION "Unknown Version" !define /ifndef PYTHON_VERSION "Unknown Version" ; The name of the installer Name "${VER_PRODUCTNAME}" ; The file to write OutFile "${OUT_FILE}" ; Request application privileges for Windows Vista and higher RequestExecutionLevel admin ; Build Unicode installer Unicode True ;SetCompress off SetCompressor LZMA ; The default installation directory InstallDir $PROGRAMFILES64\Activision\UsdShellExtension ; Registry key to check for directory (so if you install again, it will ; overwrite the old one automatically) InstallDirRegKey HKLM "Software\Activision\UsdShellExtension" "Install_Dir" !define MUI_BGCOLOR "FFFFFF" !define MUI_ICON "..\..\..\..\shared\usd.ico" !define MUI_UNICON "..\..\..\..\shared\usd.ico" !define MUI_WELCOMEFINISHPAGE_BITMAP "..\..\..\..\shared\installerWelcome.bmp" !define MUI_WELCOMEFINISHPAGE_BITMAP_STRETCH "NoStretchNoCropNoAlign" !define MUI_UNWELCOMEFINISHPAGE_BITMAP "..\..\..\..\shared\installerWelcome.bmp" !define MUI_UNWELCOMEFINISHPAGE_BITMAP_STRETCH "NoStretchNoCropNoAlign" !define MUI_WELCOMEPAGE_TITLE "${VER_PRODUCTNAME}$\r$\nVersion ${VERSION}" !define MUI_WELCOMEPAGE_TEXT "Setup will guide you through the installation of $(^NameDA).$\r$\n$\r$\nUSD Version: ${USD_VERSION}$\r$\nPython Version: ${PYTHON_VERSION}$\r$\n$\r$\nIt is recommended that you close all other applications before starting Setup. This will make it possible to update relevant system files without having to reboot your computer.$\r$\n$\r$\n$_CLICK" ;-------------------------------- ;Utilities !include "${__FILEDIR__}\UsdConfigUtils.nsh" !include "${__FILEDIR__}\RestartManager.nsh" !include "${__FILEDIR__}\ShellLinkSetRunAs.nsh" !include "${__FILEDIR__}\CmdLineArgs.nsh" ;-------------------------------- ;Interface Settings !define MUI_ABORTWARNING ;-------------------------------- ;Pages !include "${__FILEDIR__}\UsdPathPage.nsh" !include "${__FILEDIR__}\UsdConfigPage.nsh" !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "LICENSE.txt" !insertmacro MUI_PAGE_INSTFILES Page custom USDPathPage USDPathPageLeave Page custom USDConfigPage USDConfigPageLeave !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH ;-------------------------------- ;Languages !insertmacro MUI_LANGUAGE "English" ;-------------------------------- ;Version information !ifdef VER_MAJOR & VER_MINOR & VER_REVISION & VER_BUILD VIProductVersion ${VER_MAJOR}.${VER_MINOR}.${VER_REVISION}.${VER_BUILD} VIAddVersionKey "FileVersion" "${VERSION}" VIAddVersionKey "ProductVersion" "${VERSION}" VIAddVersionKey "FileDescription" "${VER_PRODUCTNAME} Setup" VIAddVersionKey "ProductName" "${VER_PRODUCTNAME}" VIAddVersionKey "LegalCopyright" "${VER_COPYRIGHT}" VIAddVersionKey "CompanyName" "${VER_COMPANYNAME}" !endif SetPluginUnload alwaysoff ;-------------------------------- Function .onInit Call ParseCommandLine FunctionEnd ;-------------------------------- Section "-ShutdownProcesses" ${DisableX64FSRedirection} SetRegView 64 Call ShutdownExplorer Call ShutdownWindowsSearch Call ShutdownApplications Call ShutdownCOMServers SectionEnd ;-------------------------------- Section "-UninstallPrevious" ${DisableX64FSRedirection} SetRegView 64 ReadRegStr $R0 HKLM \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\UsdShellExtension" \ "UninstallString" StrCmp $R0 "" done SetDetailsPrint textonly DetailPrint "Uninstalling previous installation..." SetDetailsPrint listonly DetailPrint "Uninstalling previous installation" ClearErrors ExecWait '$R0 /S _?=$INSTDIR' ;Do not copy the uninstaller to a temp file IfErrors no_remove_uninstaller done ;You can either use Delete /REBOOTOK in the uninstaller or add some code ;here to remove the uninstaller. Use a registry key to check ;whether the user has chosen to uninstall. If you are using an uninstaller ;components page, make sure all sections are uninstalled. no_remove_uninstaller: done: SectionEnd ;-------------------------------- ; The stuff to install Section "Install" ${DisableX64FSRedirection} SetRegView 64 SetDetailsPrint textonly DetailPrint "Installing files..." SetDetailsPrint listonly SetShellVarContext all ${Unless} ${FileExists} "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" SetOutPath "$LOCALAPPDATA\Activision\UsdShellExtension" File UsdShellExtension.ini ${EndUnless} SetShellVarContext current ${Unless} ${FileExists} "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" SetOutPath "$LOCALAPPDATA\Activision\UsdShellExtension" File UsdShellExtension.ini ${EndUnless} SetShellVarContext all SetOutPath "$INSTDIR" File plugInfo.json File LICENSE.txt File NOTICE.txt SetOutPath "$INSTDIR\usd" File /r .\usd\* SetOutPath "$INSTDIR" !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED tbb.dll "$INSTDIR\tbb.dll" $INSTDIR !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED tbbmalloc.dll "$INSTDIR\tbbmalloc.dll" $INSTDIR !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED ${BOOSTDLL} "$INSTDIR\${BOOSTDLL}" $INSTDIR !if /FileExists "${PYTHONDLL}" !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED ${PYTHONDLL} "$INSTDIR\${PYTHONDLL}" $INSTDIR !endif !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED usd_ms.dll "$INSTDIR\usd_ms.dll" $INSTDIR !insertmacro InstallLib DLL NOTSHARED REBOOT_NOTPROTECTED UsdPreviewHandler.pyd "$INSTDIR\UsdPreviewHandler.pyd" $INSTDIR !insertmacro InstallLib REGEXE NOTSHARED REBOOT_NOTPROTECTED UsdPreviewLocalServer.exe "$INSTDIR\UsdPreviewLocalServer.exe" $INSTDIR !insertmacro InstallLib REGEXE NOTSHARED REBOOT_NOTPROTECTED UsdPythonToolsLocalServer.exe "$INSTDIR\UsdPythonToolsLocalServer.exe" $INSTDIR !insertmacro InstallLib REGEXE NOTSHARED REBOOT_NOTPROTECTED UsdSdkToolsLocalServer.exe "$INSTDIR\UsdSdkToolsLocalServer.exe" $INSTDIR !insertmacro InstallLib REGDLL NOTSHARED REBOOT_NOTPROTECTED UsdShellExtension.dll "$INSTDIR\UsdShellExtension.dll" $INSTDIR ; Write the installation path into the registry WriteRegStr HKLM SOFTWARE\Activision\UsdShellExtension "Install_Dir" "$INSTDIR" ; Write the uninstall keys for Windows WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\UsdShellExtension" "DisplayName" "${VER_PRODUCTNAME}" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\UsdShellExtension" "DisplayIcon" "$INSTDIR\UsdShellExtension.dll,0" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\UsdShellExtension" "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\UsdShellExtension" "NoModify" 1 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\UsdShellExtension" "NoRepair" 1 WriteUninstaller "$INSTDIR\uninstall.exe" ; Install start menu items SetShellVarContext current CreateDirectory '$SMPROGRAMS\USD Shell Extension' CreateShortCut '$SMPROGRAMS\USD Shell Extension\USD Shell Extension Configuration (Current User).lnk' '"$SYSDIR\NOTEPAD.EXE"' '"$LOCALAPPDATA\Activision\UsdShellExtension\USDShellExtension.ini"' '$SYSDIR\imageres.dll' 64 SetShellVarContext all CreateDirectory '$SMPROGRAMS\USD Shell Extension' CreateShortCut '$SMPROGRAMS\USD Shell Extension\USD Shell Extension Configuration (All Users).lnk' '"$SYSDIR\NOTEPAD.EXE"' '"$LOCALAPPDATA\Activision\UsdShellExtension\USDShellExtension.ini"' '$SYSDIR\imageres.dll' 64 CreateShortCut '$SMPROGRAMS\USD Shell Extension\Uninstall USD Shell Extension.lnk' '$INSTDIR\uninstall.exe' "" !insertmacro ShellLinkSetRunAs "$SMPROGRAMS\USD Shell Extension\USD Shell Extension Configuration (All Users).lnk" ; Write version info to registry WriteRegStr HKLM "Software\Activision\UsdShellExtension" "Version" "${VER_MAJOR}.${VER_MINOR}.${VER_REVISION}.${VER_BUILD}" WriteRegStr HKLM "Software\Activision\UsdShellExtension" "USD Version" "${USD_VERSION}" WriteRegStr HKLM "Software\Activision\UsdShellExtension" "Python Version" "${PYTHON_VERSION}" WriteRegStr HKLM "Software\Activision\UsdShellExtension" "Installer" "${OUT_FILE}" SectionEnd ;-------------------------------- Section "-RestartProcesses" ${DisableX64FSRedirection} SetRegView 64 Call RestartExplorer Call RestartWindowsSearch Call RestartApplications SectionEnd ;-------------------------------- Function PatchConfigFileAll !insertmacro PatchConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PATH" "" !insertmacro PatchConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PYTHONPATH" "" !insertmacro PatchConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PXR_PLUGINPATH_NAME" "" !insertmacro PatchConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "EDITOR" "" !insertmacro PatchConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "RENDERER" "PREVIEW" "GL" !insertmacro PatchConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "RENDERER" "THUMBNAIL" "GL" !insertmacro PatchConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "RENDERER" "VIEW" "GL" !insertmacro PatchConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "PYTHON" "PATH" "" !insertmacro PatchConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "PYTHON" "PYTHONPATH" "" FunctionEnd ;-------------------------------- Function ForceConfigFileAll SetShellVarContext all ${If} $CmdLineUsdPath != "" !insertmacro WriteConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PATH" $CmdLineUsdPath ${EndIf} ${If} $CmdLineUsdPythonPath != "" !insertmacro WriteConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PYTHONPATH" $CmdLineUsdPythonPath ${EndIf} ${If} $CmdLineUsdPxrPluginPathName != "" !insertmacro WriteConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "USD" "PXR_PLUGINPATH_NAME" $CmdLineUsdPxrPluginPathName ${EndIf} ${If} $CmdLinePythonPath != "" !insertmacro WriteConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "PYTHON" "PATH" $CmdLinePythonPath ${EndIf} ${If} $CmdLinePythonPythonPath != "" !insertmacro WriteConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "PYTHON" "PYTHONPATH" $CmdLinePythonPythonPath ${EndIf} ${If} $CmdLineRendererPreview != "" !insertmacro WriteConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "RENDERER" "PREVIEW" $CmdLineRendererPreview ${EndIf} ${If} $CmdLineRendererThumbnail != "" !insertmacro WriteConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "RENDERER" "THUMBNAIL" $CmdLineRendererThumbnail ${EndIf} ${If} $CmdLineRendererView != "" !insertmacro WriteConfigFile "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" "RENDERER" "VIEW" $CmdLineRendererView ${EndIf} FunctionEnd ;-------------------------------- Section "-UpdateConfigFile" ${DisableX64FSRedirection} SetRegView 64 ; In order to support updates to the config file and allow for us ; to support going back to older versions of the shell extension, ; we will "patch" the existing config file using GetPrivateProfileStringW ; to determine if a value is already set and SetPrivateProfileStringW ; to enter a blank / default value if no value was set. SetDetailsPrint textonly DetailPrint "Updating config file..." SetDetailsPrint listonly SetShellVarContext current Call PatchConfigFileAll SetShellVarContext all Call PatchConfigFileAll ; Force any command line settings into the config file Call ForceConfigFileAll SectionEnd ;-------------------------------- ; Uninstaller ;-------------------------------- Section "-Un.ShutdownProcesses" ${DisableX64FSRedirection} SetRegView 64 Call un.ShutdownExplorer Call un.ShutdownWindowsSearch Call un.ShutdownApplications Call un.ShutdownCOMServers SectionEnd ;-------------------------------- Section "Uninstall" ${DisableX64FSRedirection} SetRegView 64 SetShellVarContext all SetDetailsPrint textonly DetailPrint "Uninstalling files..." SetDetailsPrint listonly !insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\UsdShellExtension.dll" !insertmacro UnInstallLib REGEXE NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\UsdPreviewLocalServer.exe" !insertmacro UnInstallLib REGEXE NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\UsdPythonToolsLocalServer.exe" !insertmacro UnInstallLib REGEXE NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\UsdSdkToolsLocalServer.exe" !insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\tbb.dll" !insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\tbbmalloc.dll" !insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\${BOOSTDLL}" !if /FileExists "${PYTHONDLL}" !insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\${PYTHONDLL}" !endif !insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\usd_ms.dll" !insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\UsdPreviewHandler.pyd" ; Remove registry keys DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\UsdShellExtension" DeleteRegKey HKLM SOFTWARE\Activision\UsdShellExtension ; Remove files and uninstaller ;Delete /REBOOTOK "$LOCALAPPDATA\Activision\UsdShellExtension\UsdShellExtension.ini" Delete /REBOOTOK "$INSTDIR\plugInfo.json" Delete /REBOOTOK "$INSTDIR\LICENSE.txt" Delete /REBOOTOK "$INSTDIR\NOTICE.txt" RMDir /r /REBOOTOK "$INSTDIR\usd" Delete /REBOOTOK "$INSTDIR\UsdPropertyKeys.propdesc" Delete /REBOOTOK "$INSTDIR\uninstall.exe" ; Remove directories RMDir "$INSTDIR" ; Remove start menu items SetShellVarContext current Delete '$SMPROGRAMS\USD Shell Extension\USD Shell Extension Configuration (Current User).lnk' SetShellVarContext all Delete '$SMPROGRAMS\USD Shell Extension\USD Shell Extension Configuration (All Users).lnk' Delete '$SMPROGRAMS\USD Shell Extension\Uninstall USD Shell Extension.lnk' RMDir '$SMPROGRAMS\USD Shell Extension' SectionEnd ;-------------------------------- Section "-Un.RestartProcesses" ${DisableX64FSRedirection} SetRegView 64 Call un.RestartExplorer Call un.RestartWindowsSearch Call un.RestartApplications SectionEnd ================================================ FILE: UsdShellExtensionInstaller/UsdShellExtensionInstaller.vcxproj ================================================ Release x64 Debug x64 16.0 Win32Proj {1390252A-71E2-4C4E-B874-301909F40CBA} UsdShellExtensionInstaller 10.0.14393.0 Utility false v141 false Unicode Utility true v141 false Unicode RegistryView.Registry32 RegistryView.Registry64 $(PythonVersion)-32 $(PythonVersion) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', null, null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstallPath', 'ExecutablePath', null, $(RegistryView))) $(PythonHome)python.exe $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'dev', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_pdb', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) $([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\$(PythonTag)\InstalledFeatures', 'core_d', null, $(RegistryView))) _d $([System.IO.Path]::GetDirectoryName($(PythonExe)))\python$(PythonDebugSuffix).exe $(PythonExe) $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ UsdShellExtension-v$(ATVI_VERSION_MAJOR).$(ATVI_VERSION_MINOR)-u$(USDVERSION)-p$(PythonVersion)-setup.exe $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ UsdShellExtension-v$(ATVI_VERSION_MAJOR).$(ATVI_VERSION_MINOR)-u$(USDVERSION)-p$(PythonVersion)-setup.exe @echo off REM Do nothing @echo off REM Do nothing @echo off REM Do nothing @echo off REM Do nothing Document Building Installer false Building Installer false @echo off cd /D "$(OutputPath)" "$(MAKENSIS)" /NOCD /DOUT_FILE="$(TargetName)" /DPYTHONDLL="$(PythonDLL)" /DBOOSTDLL="$(BOOSTDLL)" /DVER_PRODUCTNAME="$(ATVI_VERSION_PRODUCTNAME)" /DVER_COMPANYNAME="$(ATVI_VERSION_COMPANYNAME)" /DVER_COPYRIGHT="$(ATVI_VERSION_COPYRIGHT)" /DVER_MAJOR="$(ATVI_VERSION_MAJOR)" /DVER_MINOR="$(ATVI_VERSION_MINOR)" /DVER_REVISION="$(ATVI_VERSION_REVISION)" /DVER_BUILD="$(ATVI_VERSION_BUILD)" /DUSD_VERSION="$(USDVERSION)" /DPYTHON_VERSION="$(PythonVersion)" "%(FullPath)" @echo off cd /D "$(OutputPath)" "$(MAKENSIS)" /NOCD /DOUT_FILE="$(TargetName)" /DPYTHONDLL="$(PythonDLL)" /DBOOSTDLL="$(BOOSTDLL)" /DVER_PRODUCTNAME="$(ATVI_VERSION_PRODUCTNAME)" /DVER_COMPANYNAME="$(ATVI_VERSION_COMPANYNAME)" /DVER_COPYRIGHT="$(ATVI_VERSION_COPYRIGHT)" /DVER_MAJOR="$(ATVI_VERSION_MAJOR)" /DVER_MINOR="$(ATVI_VERSION_MINOR)" /DVER_REVISION="$(ATVI_VERSION_REVISION)" /DVER_BUILD="$(ATVI_VERSION_BUILD)" /DUSD_VERSION="$(USDVERSION)" /DPYTHON_VERSION="$(PythonVersion)" "%(FullPath)" $(OutputPath)$(TargetName);AlwaysBuildMe.exe%(Outputs) $(OutputPath)$(TargetName);AlwaysBuildMe.exe%(Outputs) ================================================ FILE: UsdShellExtensionInstaller/UsdShellExtensionInstaller.vcxproj.filters ================================================  ================================================ FILE: atviversion.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ATVI_VERSION_DESCRIPTION # define ATVI_VERSION_DESCRIPTION "" #endif #define __ATVI_VERSION_PRODUCT_STRING_INTERNAL3(s) \ #s #define __ATVI_VERSION_PRODUCT_STRING_INTERNAL2(p, s, b, f) \ __ATVI_VERSION_PRODUCT_STRING_INTERNAL3(p.s.b.f) #define __ATVI_VERSION_PRODUCT_STRING_INTERNAL(p, s, b, f) \ __ATVI_VERSION_PRODUCT_STRING_INTERNAL2(p, s, b, f) #define ATVI_VERSION_PRODUCT_STRING __ATVI_VERSION_PRODUCT_STRING_INTERNAL(ATVI_VERSION_MAJOR, ATVI_VERSION_MINOR, ATVI_VERSION_REVISION, ATVI_VERSION_BUILD) ================================================ FILE: atviversion.props ================================================ 1 09 00 00 Activision USD Shell Extension Activision Publishing, Inc. Copyright (C) 2021 Activision Publishing, Inc. ATVI_VERSION_PRODUCTNAME="$(ATVI_VERSION_PRODUCTNAME)";ATVI_VERSION_COMPANYNAME="$(ATVI_VERSION_COMPANYNAME)";ATVI_VERSION_COPYRIGHT="$(ATVI_VERSION_COPYRIGHT)";ATVI_VERSION_MAJOR="$(ATVI_VERSION_MAJOR)";ATVI_VERSION_MINOR="$(ATVI_VERSION_MINOR)";ATVI_VERSION_REVISION="$(ATVI_VERSION_REVISION)";ATVI_VERSION_BUILD="$(ATVI_VERSION_BUILD)";%(PreprocessorDefinitions) ATVI_VERSION_PRODUCTNAME=\"$(ATVI_VERSION_PRODUCTNAME)\";ATVI_VERSION_COMPANYNAME=\"$(ATVI_VERSION_COMPANYNAME)\";ATVI_VERSION_COPYRIGHT=\"$(ATVI_VERSION_COPYRIGHT)\";ATVI_VERSION_MAJOR="$(ATVI_VERSION_MAJOR)";ATVI_VERSION_MINOR="$(ATVI_VERSION_MINOR)";ATVI_VERSION_REVISION="$(ATVI_VERSION_REVISION)";ATVI_VERSION_BUILD="$(ATVI_VERSION_BUILD)";%(PreprocessorDefinitions) ================================================ FILE: atviversion.rc2 ================================================ #include "atviversion.h" VS_VERSION_INFO VERSIONINFO FILEVERSION ATVI_VERSION_MAJOR,ATVI_VERSION_MINOR,ATVI_VERSION_REVISION,ATVI_VERSION_BUILD PRODUCTVERSION ATVI_VERSION_MAJOR,ATVI_VERSION_MINOR,ATVI_VERSION_REVISION,ATVI_VERSION_BUILD FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904e4" BEGIN VALUE "CompanyName", ATVI_VERSION_COMPANYNAME VALUE "FileDescription", ATVI_VERSION_DESCRIPTION VALUE "FileVersion", ATVI_VERSION_PRODUCT_STRING VALUE "LegalCopyright", ATVI_VERSION_COPYRIGHT VALUE "ProductName", ATVI_VERSION_PRODUCTNAME VALUE "ProductVersion", ATVI_VERSION_PRODUCT_STRING END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END ================================================ FILE: boost.props ================================================ D:\USD-shared-full-p37-debug\lib\ D:\USD-shared-full-p37-debug\include\boost-1_70\ boost_$(PythonFileName)-vc$(PlatformToolsetVersion)-mt-gd-x64-1_70.dll D:\USD-shared-full-p37\lib\ D:\USD-shared-full-p37\include\boost-1_70\ boost_$(PythonFileName)-vc$(PlatformToolsetVersion)-mt-x64-1_70.dll $(BOOSTINCLUDEPATH);%(AdditionalIncludeDirectories) $(BOOSTLIBPATH);%(AdditionalLibraryDirectories) xcopy "$(BOOSTLIBPATH)$(BOOSTDLL)" "$(TargetDir)" /I /Y /F /R %(Command) xcopy "$(BOOSTLIBPATH)$(BOOSTDLL)" "$(TargetDir)" /I /Y /F /R %(Command) ================================================ FILE: docs/DEPLOYMENT.md ================================================ Activision USD Shell Extension - Deployment Guide ================================================= The USD Shell Extension has been written to be deployed in many development environments. Deploying using Setup --------------------- The USD Shell Extension setup can be run in silently and all ini configuration file values can be set on the command line of the setup program using the syntax /SECTION_KEY=VALUE. | Switch | Description | |- |- | | /s | Runs setup in silent mode | | /USD_PATH= | PATH environment variable for USD | | /USD_PYTHONPATH= | PYTHONPATH environment variable for USD | | /USD_PXR_PLUGINPATH_NAME= | PXR_PLUGINPATH_NAME environment variable for USD | | /USD_EDITOR= | Editor used for the Edit command in Windows Explorer | | /RENDERER_PREVIEW= | Hydra renderer used for the Windows Explorer Preview pane | | /RENDERER_THUMBNAIL= | Hydra renderer used for Windows Explorer Thumbnails | | /RENDERER_VIEW= | Hydra renderer used when launching usdview | | /PYTHON_PATH= | Path to the installation of Python | | /PYTHON_PYTHONPATH= | PYTHONPATH environment variable for Python | ``` UsdShellExtension-v1.09-u21.02-p3.7-setup.exe /s /USD_PATH="D:\USD-shared-full\bin\;D:\USD-shared-full\lib\" /USD_PYTHONPATH="D:\USD-shared-full\lib\python" /RENDERER_PREVIEW=Embree ``` Deploying using Loose Files --------------------------- It is possible to deploy the Shell Extension manually. 1. The files installed by setup can be packaged up for deployment without the use of setup. 2. A `UsdShellExtension.ini` configuration file can be placed in the install folder. 3. The github repository contains `register.bat` and `unregister.bat`. The commands in these batch files can be used to install and uninstall the shell extension. **NOTE** Care must be taken to correctly shutdown Windows Explorer and Windows Search when updating the shell extension. | File | |- | | usd\\\*.\* | | boost_pythonXX-vcXXX-mt-x64-1_70.dll | | LICENSE.txt | | NOTICE.txt | | plugInfo.json | | pythonXX.dll | | tbb.dll | | tbbmalloc.dll | | UsdPreviewHandler.pyd | | UsdPreviewLocalServer.exe | | UsdPythonToolsLocalServer.exe | | UsdSdkToolsLocalServer.exe | | UsdShellExtension.dll | | usd_ms.dll | | register.bat | | unregister.bat | ================================================ FILE: docs/DESIGN.md ================================================ Activision USD Shell Extension - Design ======================================= Fundamentals ------------ There are several fundamentals that this shell extension tries to adhere to. * **Performance** The extension must not stall Windows Explorer. * **Stability** The extension must be stable. A crash will take down Window Explorer and/or the entire desktop. UsdShellExtension ----------------- This is a DLL project. It is the core Windows Explorer Shell extension. This DLL is loaded into the Windows Explorer process. As a result, this DLL should not *host* python. | Extension | Description | |- |- | | **IPreviewHandler** | Adds a preview for USD files by running `usdStageView` (a part of `usdView`) in an out-of-process viewport. | | **IThumbnailProvider**| Generates thumbnails for USD files by running `usdRecord` out-of-process. | | **IPropertyStore** | Exposes USD metadata to Windows Explorer and Windows Search. | **IPreviewHandler** The IPreviewHandler runs out-of-process in a Windows provided COM local server called `prevhost.exe`. We run the USD loading screen in `prevhost.exe` but launch the actual preview using our own out of process COM server, `UsdPreviewLocalServer.exe`. The `prevhost.exe` process hosts all Windows preview handler in a single process instance. We use `UsdPreviewLocalServer.exe` to isolate `prevhost.exe`. *UsdPreviewLocalServer.exe* This COM server embeds python and launches an instance of `usdStageView` using a custom python script. It isolates python from any Windows system process. Stalling a COM call in our implementation of IPreviewHandler would still hang Windows Explorer, even though the preview is running out-of-process in `prevhost.exe`. By having our own asynchronous out-of-process server, we could operate asynchronously to Windows Explorer. *UsdPreviewHandlerPython.py* When launching `usdStageView` from `UsdPreviewLocalServer.exe` we use a custom script that uses `UsdPreviewHandlerPython.py` to send and receive events from C++. The first event that is sent is the HWND of the `usdStageView` so that it can be made a child of the preview HWND in Windows Explorer. **IThumbnailProvider** *UsdPythonToolsLocalServer.exe* Thumbnail providers already run on background threads in Windows Explorer. The extraction of a thumbnail can take a significant amount of time. We launch an out-of-process COM server, `UsdPythonToolsLocalServer.exe`, to run the `usdRecord` python script provided by USD SDK. This keeps python out of Windows Explorer. **IPropertyStore** The IPropertyStore interface runs synchronously to the UI in Windows Explorer. It must execute quickly. For this reason the C++ USD SDK is used directly in Windows Explorer. **USD Activation Context** The USD SDK and all of its dependencies are isolated from the rest of Windows Explorer via a Windows Activation Context. This at least guarantees that if any other extension ever loads USD or any of its dependencies into Windows Explorer, we will not clash. **Python USD Plug-in** This DLL serves as a python plug-in. The python plug-in is called ArResolverShellExtension. It is used to allow shared reads across the USD SDK. By default, the USD SDK uses fopen which in MSVC does not allow shared reads. **rundll** This DLL has several rundll entry points. These entry points are executed from Windows Explorer context menus. They are all located in `ShellExecute.cpp`. UsdPreviewLocalServer --------------------- This is COM Local Server executable. This project serves `usdStageView`, the USD preview window, out of process. `usdStageView` is a python script written by Pixar. This project hosts python and executes the script. It communicates with `UsdShellExtension` via COM. If the Preview server crashes. It will not take down Windows Explorer. UsdPreviewHandlerPython ----------------------- This is a python extension module. It is used to communicate between the python preview window and our shell extension. It is hosted by `UsdPreviewLocalServer`. UsdPythonToolsLocalServer ------------------------- This is COM Local Server executable. It is used to host out of process USD python tools. This server is used to capture thumbnails using `usdrecord` and to launch `usdview`. UsdSdkToolsLocalServer ---------------------- This is COM Local Server executable. It is used to host out of process USD C++ tools. This server executes the conversion between USD file formats and generating USD archives. ================================================ FILE: docs/FEATURES.md ================================================ Activision USD Shell Extension ============================== Table of contents ----------------- - [Windows Explorer Thumbnails](#features-thumbnails) - [Windows Explorer Preview](#features-preview) - [Windows Explorer Format Conversion](#features-conversion) - [Windows Explorer Edit](#features-edit) - [Windows Search](#features-search) - [UsdView](#features-usdview)
Windows Explorer Thumbnails --------------------------- Thumbnails are automatically generated for USD file types. Thumbnails are generated by rendering out an image of the USD stage in the background. Thumbnails are cached in the Windows thumbnail cache. Subsequent visits to a folder will display the cached thumbnail. The cached thumbnail will be invalidated when the file is modified or when the user explicitly selects Refresh Thumbnail from the Windows Explorer context menu. ![thumbnails][thumbnails]
Windows Explorer Preview ------------------------ The Windows Explorer Preview pane will display a 3D viewport. This viewport uses UsdStageView of UsdView to render a 3D viewport in Windows Explorer. The viewport exposes all installed Hydra renderers. The default Hydra renderer can be modified in the configuration file. ![preview][preview]
Windows Explorer Format Conversion ---------------------------------- The Windows Explorer context menu can perform conversions on USD files. * Crate Convert a USD file type to USDC Crate Format. * Uncrate Convert a USD file type to USDA ASCII Format. * Package Convert a USD file type to a USDZ Package. * Flatten Flatten a USD file hierarchy to a USD file. ![convert][convert]
Windows Explorer Edit --------------------- The Windows Explorer context menu exposes the ability to edit USD files in place. This includes crated USDC files. The editor application used can be set in the configuration file. ![edit][edit]
Windows Search -------------- USD file metadata is exposed to Windows Search. When USD metadata is indexed by Windows Search it can be searched for quickly. | Metadata | Search Mnemonics | Visible in Explorer | Editable in Explorer | Visible in Properties | | --------------- |-----------------------------------|---------------------|----------------------|-----------------------| | Comments | comment, comments | Yes | Yes | Yes | | Documentation | usddocumentation, usddocs, usddoc | Yes | No | Yes | | CustomLayerData | usdcustomlayerdata, usdlayerdata | No | No | Yes |
![search][search]
UsdView ------- The default action for USD files in Windows Explorer is to open them in UsdView. ![view][view] [thumbnails]:thumbnails.png "Windows Explorer Thumbnails" [preview]:preview.png "Windows Explorer Preview" [convert]:usdcat.png "Windows Explorer Format Conversion" [edit]:edit.png "Windows Explorer Edit" [search]:search.png "Windows Search" [view]:usdview.png "UsdView" ================================================ FILE: docs/INSTALLING.md ================================================ Activision USD Shell Extension - Installation Guide =================================================== This document covers installing the shell extension from precompiled shell extension setup installers. Step 1: USD Build ----------------- A prerequisite to the installing the shell extension is to have a functional build of USD. You can build USD locally from Pixar's GitHub or use per-built libraries such as the ones available at NVIDIA. When building locally, make sure that the USD Python tools are built as well. Pixar's USD Source Repository https://github.com/PixarAnimationStudios/USD/ NVIDIA's USD Pre-built Libraries and Tools https://developer.nvidia.com/usd Step 2: Verify USD install with usdview --------------------------------------- The shell extension uses usdview for the Windows Explorer preview and usdrecord for thumbnails. usdview must be operational outside of the extension. Launch usdview manually out of the USD build and make sure that it is rendering correctly. Step 3: Shell Extension Setup ----------------------------- Match the version of Python used by the USD build with that of the shell extension setup. NVIDIA's pre-built libraries currently use Python 3.6. The shell extension setup contains a USD Libraries and Tools screen. Use the `Set using root USD folder` button to select the location of the USD build from Step 1. **NVIDIA Pre-built Libraries Example** NVIDIA pre-built libraries installation location: `D:\usd-21-05-usd-win64_py36_release` | Entry | Value | |- |- | | **PATH** | D:\usd-21-05-usd-win64_py36_release\bin\;D:\usd-21-05-usd-win64_py36_release\lib\ | | **PYTHONPATH** | D:\usd-21-05-usd-win64_py36_release\lib\python | | **PXR_PLUGINPATH_NAME** | | USD Text Editor --------------- By default, the text editor used by the `Edit` command is `notepad.exe`. This text editor is guaranteed to be installed. A custom text editor can be specified in the `UsdShellExtension.ini` file. **Requirements** The editor *must* support not returning on the command line until the text file is closed in the editor. **Visual Studio Code** Visual Studio Code is a great editor for USDA files that also can perform syntax highlighting. To associate Visual Studio Code with the USD Shell Extension use the following command in the ini file: ``` [USD] EDITOR="C:\Users\pmintus\AppData\Local\Programs\Microsoft VS Code\Code.exe" --wait ``` Troubleshooting --------------- **Python** By default, the shell extension will try to automatically locate a Python install. The Python 3.x installers from python.org will install registry keys that can be used to locate Python. | Python Version | Search Location | |- |- | | 2.7 | C:\Python27 | | 3.6 | HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\3.6\InstallPath | | 3.7 | HKEY_CURRENT_USER\SOFTWARE\Python\PythonCore\3.7\InstallPath | If the Python install is not found at these locations, then it needs to be set explicitly using the `UsdShellExtension.ini` file. ``` [PYTHON] PATH=C:\Python37 ``` **Event Viewer** If the shell extension is not working, then the first place to check for issues is the Windows Event Viewer. Windows Logs | Application The event source will be `Activision USD Shell Extension`. If you are seeing Python errors, then make sure that you can run usdview outside of the shell extension (Step 2). Also make sure that the Python version of the shell extension matches that of the USD build. ![eventviewer][eventviewer] **File Associations** For the shell extension to work it needs to be associated with USD, USDA, USDC, and USDZ file extensions. Setup performs this association. However, manual user associations take precedence over system global associations. If these file extensions have been previously manually associated with a different application, then the shell extension will not work. Make sure that the following file type associations are set to `Activision USD Shell Extension`. This can be changed manually using Windows Settings. Windows Settings | Apps | Default apps | Choose default apps by file type | Extension | App | |- |- | | .usd | Activision USD Shell Extension | | .usda | Activision USD Shell Extension | | .usdc | Activision USD Shell Extension | | .usdz | Activision USD Shell Extension | [eventviewer]:EventViewer.png "Event Viewer" ================================================ FILE: nsis.props ================================================ $(ProgramFiles)\NSIS\makensis.exe ================================================ FILE: python.props ================================================ 3.7 0x03070000 python37 $(PythonFileName).dll $(PythonFileName).dll PYTHONVERSION=$(PythonVersion);PYTHONDLL="$(PythonDLL)";%(PreprocessorDefinitions) xcopy "$(PYTHONHOME)$(PythonDLL)" "$(TargetDir)" /I /Y /F /R %(Command) ================================================ FILE: shared/EventViewerLog.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include "EventViewerMessages.h" #define EVENTLOG_SOURCE "Activision USD Shell Extension" enum class LogEventType { Error = EVENTLOG_ERROR_TYPE, Warning = EVENTLOG_WARNING_TYPE, Information = EVENTLOG_INFORMATION_TYPE, }; inline bool LogEventMessage(WORD category, LPCTSTR sEventMessage, LogEventType type) { bool bSuccess = false; DWORD eventId; switch ( type ) { case LogEventType::Information: eventId = MSG_GENERIC_INFORMATION; break; case LogEventType::Warning: eventId = MSG_GENERIC_WARNING; break; case LogEventType::Error: eventId = MSG_GENERIC_ERROR; break; default: type = LogEventType::Error; eventId = MSG_GENERIC_ERROR; break; } HANDLE hEventSource = ::RegisterEventSource( nullptr, _T(EVENTLOG_SOURCE) ); if ( hEventSource ) { bSuccess = (::ReportEvent( hEventSource, static_cast(type), category, eventId, nullptr, 1, 0, &sEventMessage, nullptr ) != FALSE); ::DeregisterEventSource( hEventSource ); } return bSuccess; } ================================================ FILE: shared/EventViewerMessages.mc ================================================ LanguageNames=(English=0x409:MSG00409) MessageIdTypedef=WORD MessageId=0x1 SymbolicName=GENERIC_CATEGORY Language=English Generic . MessageId=0x2 SymbolicName=SHELLEXTENSION_CATEGORY Language=English USD Shell Extension . MessageId=0x3 SymbolicName=PREVIEWHANDLER_CATEGORY Language=English USD Preview Handler Server . MessageId=0x4 SymbolicName=PYTHONTOOLS_CATEGORY Language=English USD Python Tools Server . MessageId=0x5 SymbolicName=SDKTOOLS_CATEGORY Language=English USD SDK Tools Server . MessageId=0x6 SymbolicName=CATEGORY_COUNT Language=English Number of categories . MessageIdTypedef=DWORD MessageId=0x100 Severity=Error SymbolicName=MSG_GENERIC_SUCCESS Language=English %1 . MessageId=0x101 Severity=Informational SymbolicName=MSG_GENERIC_INFORMATION Language=English %1 . MessageId=0x102 Severity=Warning SymbolicName=MSG_GENERIC_WARNING Language=English %1 . MessageId=0x103 Severity=Error SymbolicName=MSG_GENERIC_ERROR Language=English %1 . ================================================ FILE: shared/EventViewerMessages.vcxproj ================================================ Debug x64 Release x64 15.0 {F12E597B-B731-4F5A-BEC3-980D20159320} USDSharedLib 10.0.14393.0 EventViewerMessages Utility true v141 Unicode Utility false v141 false Unicode $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ $(SolutionDir)bin\$(PlatformToolset)\$(PythonTag)\$(Configuration)\ $(SolutionDir)build\$(PlatformToolset)\$(PythonTag)\$(Configuration)\$(ProjectName)\ Document echo mc %(FullPath) mc %(FullPath) Compiling Messages... %(Filename).rc;%(Filename).h;MSG00409.bin echo mc %(FullPath) mc %(FullPath) Compiling Messages... %(Filename).rc;%(Filename).h;MSG00409.bin ================================================ FILE: shared/EventViewerMessages.vcxproj.filters ================================================  ================================================ FILE: shared/PythonUtil.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include #if PY_MAJOR_VERSION >= 3 using TPyChar = wchar_t; using CW2Py = ATL::CW2CW; #define __Tpy(x) L ## x #else using TPyChar = char; using CW2Py = ATL::CW2A; #define __Tpy(x) x #endif #define _Tpy(x) __Tpy(x) class CPyInterpreter { public: CPyInterpreter() { Py_Initialize(); } ~CPyInterpreter() { Py_Finalize(); } }; class CPyObject { public: constexpr CPyObject() noexcept {} constexpr CPyObject( std::nullptr_t ) noexcept {} constexpr CPyObject( PyObject *pyObject ) noexcept { p = pyObject; } CPyObject( CPyObject &&pyObject ) noexcept { p = pyObject.p; pyObject.p = nullptr; } ~CPyObject() { reset( nullptr ); } PyObject *get() const noexcept { return p; } PyObject *release() noexcept { PyObject *pyObject = p; p = nullptr; return pyObject; } void reset( PyObject *pyObject ) noexcept { if ( p != nullptr ) { Py_DECREF( p ); } p = pyObject; } void reset( std::nullptr_t ) noexcept { if ( p != nullptr ) { Py_DECREF( p ); } p = nullptr; } void swap( CPyObject &other ) noexcept { PyObject *pTemp = other.get(); other.p = p; p = pTemp; } explicit operator bool() const noexcept { return get() != nullptr; } PyObject operator*() const { return *p; } PyObject* operator->() const noexcept { return p; } CPyObject &operator=( CPyObject &&rhs ) noexcept { reset( rhs.p ); rhs.p = nullptr; return *this; } CPyObject &operator=( std::nullptr_t ) noexcept { reset( nullptr ); return *this; } bool operator==(PyObject* pT) const noexcept { return p == pT; } PyObject *p = nullptr; }; #if PY_MAJOR_VERSION < 3 inline const char *PyUnicode_AsUTF8( PyObject *unicode ) { if ( PyUnicode_Check( unicode ) ) { CPyObject bytes( PyUnicode_AsEncodedString( unicode, "UTF-8", "strict" ) ); if ( bytes == nullptr ) return nullptr; const char *s = PyBytes_AS_STRING( bytes.get() ); return s; } else if ( PyBytes_Check( unicode ) ) { const char *s = PyBytes_AS_STRING( unicode ); return s; } return nullptr; } inline wchar_t *PyUnicode_AsWideCharString( PyObject *unicode, Py_ssize_t *size ) { const char *utf8 = PyUnicode_AsUTF8( unicode ); if ( utf8 == nullptr ) return nullptr; int nCharactersNeededWithNullTerminator = ::MultiByteToWideChar( CP_UTF8, 0, utf8, -1, nullptr, 0 ); if ( nCharactersNeededWithNullTerminator <= 1 ) return nullptr; wchar_t* utf16 = reinterpret_cast(PyMem_Malloc( sizeof( wchar_t ) * nCharactersNeededWithNullTerminator )); if ( utf16 == nullptr ) return nullptr; if ( ::MultiByteToWideChar( CP_UTF8, 0, utf8, -1, utf16, nCharactersNeededWithNullTerminator ) <= 0 ) { PyMem_Free( utf16 ); return nullptr; } if ( size ) *size = nCharactersNeededWithNullTerminator - 1; return utf16; } #endif class CPyString : public CPyObject { public: constexpr CPyString() noexcept {} constexpr CPyString( std::nullptr_t ) noexcept {} constexpr CPyString( PyObject *pyObject ) noexcept { p = pyObject; } CPyString( CPyString &&pyObject ) noexcept { p = pyObject.p; pyObject.p = nullptr; } ~CPyString() { reset( nullptr ); } explicit operator bool() const noexcept { return get() != nullptr; } PyObject operator*() const { return *p; } PyObject* operator->() const noexcept { return p; } CPyString &operator=( CPyString &&rhs ) noexcept { reset( rhs.p ); rhs.p = nullptr; return *this; } CPyString &operator=( std::nullptr_t ) noexcept { reset( nullptr ); return *this; } bool operator==(PyObject* pT) const noexcept { return p == pT; } const char *c_str() const noexcept { if ( p == nullptr ) return ""; const char* s = PyUnicode_AsUTF8( p ); if ( s == nullptr ) return ""; return s; } static CPyString FromObject( PyObject *pyObject ) { if ( pyObject == nullptr ) return CPyString(); CPyString result( PyObject_Str( pyObject ) ); return result; } }; class CPyStringW : public CPyObject { public: constexpr CPyStringW() noexcept {} constexpr CPyStringW( std::nullptr_t ) noexcept {} constexpr CPyStringW( PyObject *pyObject ) noexcept { p = pyObject; } CPyStringW( CPyStringW &&pyObject ) noexcept { p = pyObject.p; pyObject.p = nullptr; } ~CPyStringW() { reset( nullptr ); } explicit operator bool() const noexcept { return get() != nullptr; } PyObject operator*() const { return *p; } PyObject* operator->() const noexcept { return p; } CPyStringW &operator=( CPyStringW &&rhs ) noexcept { reset( rhs.p ); rhs.p = nullptr; return *this; } CPyStringW &operator=( std::nullptr_t ) noexcept { reset( nullptr ); return *this; } bool operator==(PyObject* pT) const noexcept { return p == pT; } const wchar_t *c_str() const noexcept { if ( p == nullptr ) return L""; if ( s == nullptr ) s = PyUnicode_AsWideCharString( p, nullptr ); return s; } void reset( PyObject *pyObject ) noexcept { if ( s ) { PyMem_Free ( s ); s = nullptr; } CPyObject::reset( pyObject ); } void reset( std::nullptr_t ) noexcept { if ( s ) { PyMem_Free ( s ); s = nullptr; } CPyObject::reset( nullptr ); } static CPyStringW FromObject( PyObject *pyObject ) { if ( pyObject == nullptr ) return CPyStringW(); CPyStringW result( PyObject_Str( pyObject ) ); return result; } private: mutable wchar_t *s = nullptr; }; inline CStringW StringListToString( PyObject *pyObject ) { CStringW result; if ( pyObject == nullptr ) return result; CPyObject itr = PyObject_GetIter( pyObject ); if( itr == nullptr ) return result; for ( ;; ) { CPyObject item = PyIter_Next( itr.get() ); if ( item == nullptr ) break; CPyStringW str = CPyStringW::FromObject( item.get() ); result += str.c_str(); } return result; } class CPyException : public std::exception { public: CPyException() { if ( PyErr_Occurred() ) { PyErr_Fetch( &m_pType.p, &m_pValue.p, &m_pTraceback.p ); PyErr_NormalizeException( &m_pType.p, &m_pValue.p, &m_pTraceback.p ); m_pTracebackObject = reinterpret_cast(m_pTraceback.get()); m_sValue = CPyString::FromObject( m_pValue.get() ); m_sValueW = CPyStringW::FromObject( m_pValue.get() ); m_sTypeW = CPyStringW::FromObject( m_pType.get() ); } } _NODISCARD virtual char const* what() const override { return m_sValue ? m_sValue.c_str() : "Unknown exception"; } _NODISCARD wchar_t const* whatW() const { return m_sValueW ? m_sValueW.c_str() : L"Unknown exception"; } wchar_t const* typeW() const { return m_sTypeW ? m_sTypeW.c_str() : L"Unknown type"; } const wchar_t *tracebackW() const { if ( m_bTracebackResolved == false ) { m_bTracebackResolved = true; CPyObject importTraceback = PyImport_ImportModule( "traceback" ); if ( importTraceback == nullptr ) return L""; CPyObject funcFormatException = PyObject_GetAttrString( importTraceback.get(), "format_exception" ); if ( funcFormatException == nullptr ) return L""; CPyObject result = PyObject_CallFunctionObjArgs( funcFormatException.get(), m_pType.get(), m_pValue.get(), m_pTraceback.get(), nullptr ); if ( result == nullptr ) return L""; m_sTraceback = StringListToString( result.get() ); } return m_sTraceback; } bool IsExceptionSystemExit() const { // We cannot use PyErr_GivenExceptionMatches() because it prevents the ability to delay link pythonXX.dll //return _wcsicmp(m_sTypeW.c_str(), L"") == 0; return PyErr_GivenExceptionMatches( GetException(), PyExc_SystemExit ) != 0; } PyObject *GetException() const { return m_pType.get(); } PyObject *GetValue() const { return m_pValue.get(); } private: CPyObject m_pType; CPyObject m_pValue; CPyObject m_pTraceback; PyTracebackObject *m_pTracebackObject = nullptr; CPyString m_sValue; CPyStringW m_sValueW; CPyStringW m_sTypeW; mutable CStringW m_sTraceback; mutable bool m_bTracebackResolved = false; }; class CPyImport : public CPyObject { public: CPyImport(const char* name) { p = PyImport_ImportModule( name ); if ( p == nullptr ) { throw CPyException(); } } }; class CPyAttr : public CPyObject { public: CPyAttr(PyObject* object, const char* name) { p = PyObject_GetAttrString( object, name ); if ( p == nullptr ) { throw CPyException(); } } }; class CPyInstance : public CPyObject { public: CPyInstance(PyObject* object, const char* name) { // locate the object CPyObject pAttr = PyObject_GetAttrString( object, name ); if ( pAttr == nullptr ) { throw CPyException(); } // create an instance of the object p = PyObject_CallObject( pAttr.get(), nullptr ); if ( p == nullptr ) { throw CPyException(); } } }; class CPyCallMethod : public CPyObject { public: template CPyCallMethod(PyObject* object, const char* name, const char* format, Args&&... args) { p = PyObject_CallMethod( object, name, format, std::forward(args)... ); if ( p == nullptr ) { throw CPyException(); } } }; class CPyCallFunction : public CPyObject { public: template CPyCallFunction(PyObject* object, const char* format, Args&&... args) { p = PyObject_CallFunction( object, format, std::forward(args)... ); if ( p == nullptr ) { throw CPyException(); } } }; inline void PySetEnvironmentVariable( LPCWSTR sEnvironmentVariable, LPCWSTR sValue ) { if ( sEnvironmentVariable == nullptr || sEnvironmentVariable[0] == '\0' ) return; CPyObject os = PyImport_ImportModule( "os" ); if ( os == nullptr ) return; CPyObject environClass = PyObject_GetAttrString( os.get(), "environ" ); if ( environClass == nullptr ) return; CPyObject environSetItem = PyObject_GetAttrString( environClass.get(), "__setitem__" ); if ( environSetItem == nullptr ) return; CPyObject pyEnvironmentVariable = PyUnicode_FromString( static_cast(ATL::CW2A( sEnvironmentVariable, CP_UTF8 )) ); if ( pyEnvironmentVariable == nullptr ) return; CPyObject pyValue = PyUnicode_FromString( static_cast(ATL::CW2A( sValue ? sValue : L"", CP_UTF8 )) ); if ( pyValue == nullptr ) return; CPyObject args = Py_BuildValue( "OO", pyEnvironmentVariable.get(), pyValue.get() ); if ( args == nullptr ) return; CPyObject ret = PyObject_CallObject( environSetItem.get(), args.get() ); } inline void PyAppendSysPath(LPCWSTR sPath) { if ( sPath == nullptr ) return; CPyObject sys = PyImport_ImportModule( "sys" ); if ( sys == nullptr ) return; CPyObject path = PyObject_GetAttrString( sys.get(), "path" ); if ( path == nullptr ) return; #if PY_MAJOR_VERSION < 3 PyList_Append(path.get(), PyString_FromString(static_cast(ATL::CW2A( sPath, CP_UTF8 )))); #else PyList_Append(path.get(), PyUnicode_FromString(static_cast(ATL::CW2A( sPath, CP_UTF8 )))); #endif } inline void PyAppendSysPath(const std::vector& pathList) { if ( pathList.empty() ) return; CPyObject sys = PyImport_ImportModule( "sys" ); if ( sys == nullptr ) return; CPyObject path = PyObject_GetAttrString( sys.get(), "path" ); if ( path == nullptr ) return; for ( const CStringW &sPath : pathList ) { #if PY_MAJOR_VERSION < 3 PyList_Append(path.get(), PyString_FromString(static_cast(ATL::CW2A( sPath, CP_UTF8 )))); #else PyList_Append(path.get(), PyUnicode_FromString(static_cast(ATL::CW2A( sPath, CP_UTF8 )))); #endif } } ================================================ FILE: shared/emb.cpp ================================================ // // Copyright (C) 2011 Mateusz Loskot // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Blog article: http://mateusz.loskot.net/?p=2819 #pragma once #include "stdafx.h" #include "emb.h" namespace emb { struct Stdout { PyObject_HEAD stdout_write_type write; }; PyObject *Stdout_write( PyObject *self, PyObject *args ) { std::size_t written( 0 ); Stdout *selfimpl = reinterpret_cast(self); if ( selfimpl->write ) { char *data; if ( !PyArg_ParseTuple( args, "s", &data ) ) return 0; std::string str( data ); selfimpl->write( str ); written = str.size(); } return PyLong_FromSize_t( written ); } PyObject *Stdout_flush( PyObject * /*self*/, PyObject * /*args*/ ) { // no-op return Py_BuildValue( "" ); } PyMethodDef Stdout_methods[] = { {"write", Stdout_write, METH_VARARGS, "sys.stdout.write"}, {"flush", Stdout_flush, METH_VARARGS, "sys.stdout.write"}, {0, 0, 0, 0} // sentinel }; PyTypeObject StdoutType = { PyVarObject_HEAD_INIT( 0, 0 ) "emb.StdoutType", /* tp_name */ sizeof( Stdout ), /* tp_basicsize */ 0, /* tp_itemsize */ 0, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ "emb.Stdout objects", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ Stdout_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ }; #if PY_MAJOR_VERSION >= 3 PyModuleDef embmodule = { PyModuleDef_HEAD_INIT, "emb", 0, -1, 0, }; #endif // Internal state PyObject *g_stdout; PyObject *g_stdout_saved; PyObject *g_stderr; PyObject *g_stderr_saved; #if PY_MAJOR_VERSION >= 3 #define NULL_MODULE nullptr #else #define NULL_MODULE #endif PyMODINIT_FUNC PyInit_emb( void ) { g_stdout = 0; g_stdout_saved = 0; g_stderr = 0; g_stderr_saved = 0; StdoutType.tp_new = PyType_GenericNew; if ( PyType_Ready( &StdoutType ) < 0 ) return NULL_MODULE; #if PY_MAJOR_VERSION >= 3 PyObject *m = PyModule_Create( &embmodule ); #else PyObject *m = Py_InitModule( "emb", Stdout_methods ); #endif if ( m ) { Py_INCREF( &StdoutType ); PyModule_AddObject( m, "Stdout", reinterpret_cast(&StdoutType) ); } #if PY_MAJOR_VERSION >= 3 return m; #endif } void set_stdout( stdout_write_type write ) { if ( !g_stdout ) { g_stdout_saved = PySys_GetObject( const_cast("stdout") ); // borrowed g_stdout = StdoutType.tp_new( &StdoutType, 0, 0 ); } Stdout *impl = reinterpret_cast(g_stdout); impl->write = write; PySys_SetObject( const_cast("stdout"), g_stdout ); } void reset_stdout() { if ( g_stdout_saved ) PySys_SetObject( const_cast("stdout"), g_stdout_saved ); Py_XDECREF( g_stdout ); g_stdout = 0; } void set_stderr( stdout_write_type write ) { if ( !g_stderr ) { g_stderr_saved = PySys_GetObject( const_cast("stderr") ); // borrowed g_stderr = StdoutType.tp_new( &StdoutType, 0, 0 ); } Stdout *impl = reinterpret_cast(g_stderr); impl->write = write; PySys_SetObject( const_cast("stderr"), g_stderr ); } void reset_stderr() { if ( g_stderr_saved ) PySys_SetObject( const_cast("stderr"), g_stderr_saved ); Py_XDECREF( g_stderr ); g_stderr = 0; } } // namespace emb ================================================ FILE: shared/emb.h ================================================ // // Copyright (C) 2011 Mateusz Loskot // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Blog article: http://mateusz.loskot.net/?p=2819 #pragma once #include #include #include namespace emb { typedef std::function stdout_write_type; PyMODINIT_FUNC PyInit_emb( void ); void set_stdout( stdout_write_type write ); void reset_stdout(); void set_stderr( stdout_write_type write ); void reset_stderr(); } // namespace emb ================================================ FILE: shared/environment.cpp ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "stdafx.h" #include "environment.h" #include #include std::vector g_UsdPathList; std::vector g_UsdPythonPathList; CStringW g_UsdPath; CStringW g_UsdPythonPath; CStringW g_UsdEditor; const std::vector &GetUsdPathList() { return g_UsdPathList; } const std::vector &GetUsdPythonPathList() { return g_UsdPythonPathList; } const CStringW &GetUsdPath() { return g_UsdPath; } const CStringW &GetUsdPythonPath() { return g_UsdPythonPath; } const CStringW &GetUsdEditor() { return g_UsdEditor; } static std::vector TranslatePathsToList(LPCWSTR paths) { std::vector pathList; CStringW sPaths(paths); CStringW sToken; int pos = 0; sToken = sPaths.Tokenize(L";", pos); if ( !sToken.IsEmpty() ) { while ( !sToken.IsEmpty() ) { pathList.push_back( sToken ); sToken = sPaths.Tokenize( L";", pos ); } } else { pathList.push_back( paths ); } return pathList; } static CStringW AppendEnvironmentVariable( LPCWSTR sEnvironmentVariable, LPCWSTR sValue ) { // CRT environment variables size_t sizeRequired = 0; CStringW sGetBuffer; if ( _wgetenv_s( &sizeRequired, nullptr, 0, sEnvironmentVariable ) == 0 ) { if ( sizeRequired > 0 ) { LPWSTR pGetBuffer = sGetBuffer.GetBuffer( static_cast(sizeRequired) ); _wgetenv_s( &sizeRequired, pGetBuffer, sizeRequired, sEnvironmentVariable ); sGetBuffer.ReleaseBufferSetLength( static_cast(sizeRequired) ); } } CStringW sSetBuffer = sValue; sSetBuffer += L";"; sSetBuffer += sGetBuffer; _wputenv_s( sEnvironmentVariable, sSetBuffer ); return sSetBuffer; } static void SetupPathEnvironmentVariable(LPCWSTR sUSD_Path, LPCWSTR sPython_Path) { CStringW sSetBuffer; if ( sPython_Path[0] == '\0' ) { #if PY_MAJOR_VERSION >= 3 #if defined(PYTHONVERSION) CStringW sPythonRegKeyInstallPath; sPythonRegKeyInstallPath.Format( L"SOFTWARE\\Python\\PythonCore\\%hs\\InstallPath", _CRT_STRINGIZE(PYTHONVERSION) ); LSTATUS ls; CRegKey regPythonInstallPath; ls = regPythonInstallPath.Open( HKEY_CURRENT_USER, sPythonRegKeyInstallPath, KEY_READ ); if ( ls == ERROR_SUCCESS ) { TCHAR sValue[512]; ULONG nChars = ARRAYSIZE( sValue ); ls = regPythonInstallPath.QueryStringValue( L"", sValue, &nChars ); if ( ls == ERROR_SUCCESS ) { if ( !sSetBuffer.IsEmpty() ) sSetBuffer += L";"; sSetBuffer += sValue; } } #endif #elif PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION == 7 static constexpr wchar_t python27InstallPath[] = L"C:\\Python27\\"; DWORD nAttrib = ::GetFileAttributesW( python27InstallPath ); if ( (nAttrib != INVALID_FILE_ATTRIBUTES) && (nAttrib & FILE_ATTRIBUTE_DIRECTORY) ) { if ( !sSetBuffer.IsEmpty() ) sSetBuffer += L";"; sSetBuffer += python27InstallPath; } #endif } else { if ( !sSetBuffer.IsEmpty() ) sSetBuffer += L";"; sSetBuffer += sPython_Path; } if ( !sSetBuffer.IsEmpty() ) sSetBuffer += L";"; sSetBuffer += sUSD_Path; g_UsdPath = AppendEnvironmentVariable( L"PATH", sSetBuffer ); } static void SetupPythonPathEnvironmentVariable(LPCWSTR sUSD_PythonPath, LPCWSTR sPython_PythonPath) { CStringW sSetBuffer = sUSD_PythonPath; if ( !sSetBuffer.IsEmpty() ) sSetBuffer += L";"; sSetBuffer += sPython_PythonPath; g_UsdPythonPath = AppendEnvironmentVariable( L"PYTHONPATH", sSetBuffer ); } static void SetupUsdEditorEnvironmentVariable(LPCWSTR sUSD_EditorPath) { if ( sUSD_EditorPath && sUSD_EditorPath[0] != '\0' ) { AppendEnvironmentVariable( L"USD_EDITOR", sUSD_EditorPath ); g_UsdEditor = sUSD_EditorPath; } } static void SetupUsdPluginPathEnvironmentVariable(LPCWSTR sUSD_PluginPath) { if ( sUSD_PluginPath && sUSD_PluginPath[0] != '\0' ) { AppendEnvironmentVariable( L"PXR_PLUGINPATH_NAME", sUSD_PluginPath ); } } void GetPrivateProfileStringAndExpandEnvironmentStrings( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, CStringW& lpReturnedString, const std::vector &ConfigFileList ) { // a default string that a user wouldn't enter by hand const wchar_t sDefault[] = L"{80CA827C-F8A2-42E3-B582-BF7940014D71}"; wchar_t sBuffer[8196]; for ( const CStringW &sConfigFile : ConfigFileList ) { sBuffer[0] = '\0'; ::GetPrivateProfileStringW( lpAppName, lpKeyName, sDefault, sBuffer, ARRAYSIZE(sBuffer), sConfigFile ); if ( sBuffer[0] != '\0' && wcscmp( sBuffer, sDefault ) ) break; } // if we never found an entry, use the passed in default if ( sBuffer[0] == '\0' || wcscmp( sBuffer, sDefault ) == 0 ) { wcscpy_s( sBuffer, lpDefault ); } DWORD nLengthInChars = ::ExpandEnvironmentStringsW( sBuffer, lpReturnedString.GetBuffer(), lpReturnedString.GetAllocLength() ); if ( static_cast(nLengthInChars) > lpReturnedString.GetAllocLength() ) { ::ExpandEnvironmentStringsW( sBuffer, lpReturnedString.GetBuffer(nLengthInChars), nLengthInChars ); } lpReturnedString.ReleaseBuffer( nLengthInChars ); } std::vector BuildConfigFileList( HMODULE hCurrentModule ) { std::vector ConfigFileList; // 1. current user config file { wchar_t *pFolderPath = nullptr; if ( ::SHGetKnownFolderPath( FOLDERID_LocalAppData, KF_FLAG_DEFAULT, nullptr, &pFolderPath ) == S_OK ) { wchar_t sConfigPath[1024]; wcscpy_s( sConfigPath, pFolderPath ); CoTaskMemFree( pFolderPath ); pFolderPath = nullptr; ::PathCchAppend( sConfigPath, ARRAYSIZE( sConfigPath ), L"Activision" ); ::PathCchAppend( sConfigPath, ARRAYSIZE( sConfigPath ), L"UsdShellExtension" ); ::PathCchAppend( sConfigPath, ARRAYSIZE( sConfigPath ), L"UsdShellExtension.ini" ); ConfigFileList.push_back( sConfigPath ); } } // 2. all users config file { wchar_t *pFolderPath = nullptr; if ( ::SHGetKnownFolderPath( FOLDERID_ProgramData, KF_FLAG_DEFAULT, nullptr, &pFolderPath ) == S_OK ) { wchar_t sConfigPath[1024]; wcscpy_s( sConfigPath, pFolderPath ); CoTaskMemFree( pFolderPath ); pFolderPath = nullptr; ::PathCchAppend( sConfigPath, ARRAYSIZE( sConfigPath ), L"Activision" ); ::PathCchAppend( sConfigPath, ARRAYSIZE( sConfigPath ), L"UsdShellExtension" ); ::PathCchAppend( sConfigPath, ARRAYSIZE( sConfigPath ), L"UsdShellExtension.ini" ); ConfigFileList.push_back( sConfigPath ); } } // 3. config file next to module { wchar_t sConfigPath[1024]; ::GetModuleFileNameW( hCurrentModule, sConfigPath, ARRAYSIZE( sConfigPath ) ); ::PathCchRemoveFileSpec( sConfigPath, ARRAYSIZE( sConfigPath ) ); ::PathCchAppend( sConfigPath, ARRAYSIZE( sConfigPath ), L"UsdShellExtension.ini" ); ConfigFileList.push_back( sConfigPath ); } return ConfigFileList; } void SetupPythonEnvironment( HMODULE hCurrentModule ) { std::vector ConfigFileList = BuildConfigFileList(hCurrentModule); CStringW sUSD_Path; GetPrivateProfileStringAndExpandEnvironmentStrings( L"USD", L"PATH", L"", sUSD_Path, ConfigFileList ); CStringW sUSD_PythonPath; GetPrivateProfileStringAndExpandEnvironmentStrings( L"USD", L"PYTHONPATH", L"", sUSD_PythonPath, ConfigFileList ); CStringW sUSD_EditorPath; GetPrivateProfileStringAndExpandEnvironmentStrings( L"USD", L"EDITOR", L"", sUSD_EditorPath, ConfigFileList ); CStringW sUSD_PluginPath; GetPrivateProfileStringAndExpandEnvironmentStrings( L"USD", L"PXR_PLUGINPATH_NAME", L"", sUSD_PluginPath, ConfigFileList ); CStringW sPython_Path; GetPrivateProfileStringAndExpandEnvironmentStrings( L"PYTHON", L"PATH", L"", sPython_Path, ConfigFileList ); CStringW sPython_PythonPath; GetPrivateProfileStringAndExpandEnvironmentStrings( L"PYTHON", L"PYTHONPATH", L"", sPython_PythonPath, ConfigFileList ); g_UsdPathList = TranslatePathsToList(sUSD_Path); g_UsdPythonPathList = TranslatePathsToList(sUSD_PythonPath); SetupPathEnvironmentVariable( sUSD_Path, sPython_Path ); SetupPythonPathEnvironmentVariable( sUSD_PythonPath, sPython_PythonPath ); SetupUsdEditorEnvironmentVariable( sUSD_EditorPath ); SetupUsdPluginPathEnvironmentVariable( sUSD_PluginPath ); } ================================================ FILE: shared/environment.h ================================================ // Copyright 2021 Activision Publishing, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include void SetupPythonEnvironment( HMODULE hCurrentModule ); const std::vector &GetUsdPathList(); const std::vector &GetUsdPythonPathList(); const CStringW &GetUsdPath(); const CStringW &GetUsdPythonPath(); const CStringW &GetUsdEditor(); std::vector BuildConfigFileList( HMODULE hCurrentModule ); void GetPrivateProfileStringAndExpandEnvironmentStrings( LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault, CStringW &lpReturnedString, const std::vector &ConfigFileList ); ================================================ FILE: usd-monolithic.props ================================================ monolithic 21.02 d:\USD-monolithic-bare-debug\bin\ d:\USD-monolithic-bare-debug\lib\ d:\USD-monolithic-bare-debug\include\ d:\USD-monolithic-bare-debug\lib\usd\ d:\USD-monolithic-bare\bin\ d:\USD-monolithic-bare\lib\ d:\USD-monolithic-bare\include\ d:\USD-monolithic-bare\lib\usd\ %(PreprocessorDefinitions) $(USDINCLUDEPATH);$(USDINCLUDEPATH)\boost-1_70;%(AdditionalIncludeDirectories) dbghelp.lib;Ws2_32.lib;usd_ms.lib;%(AdditionalDependencies) $(USDLIBPATH);%(AdditionalLibraryDirectories) /WHOLEARCHIVE:"$(USDLIBPATH)usd_ms" %(AdditionalOptions) xcopy "$(USDBINPATH)tbb_debug.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDBINPATH)tbb_debug.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDBINPATH)tbbmalloc_debug.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDBINPATH)tbbmalloc_debug.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usd_ms.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usd_ms.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(PXR_PLUGINPATH_NAME)" "$(TargetDir)\usd" /I /Y /F /R /S %(Command) %(PreprocessorDefinitions) $(USDINCLUDEPATH);$(USDINCLUDEPATH)\boost-1_70;%(AdditionalIncludeDirectories) dbghelp.lib;Ws2_32.lib;usd_ms.lib;%(AdditionalDependencies) $(USDLIBPATH);%(AdditionalLibraryDirectories) /WHOLEARCHIVE:"$(USDLIBPATH)usd_ms" %(AdditionalOptions) xcopy "$(USDBINPATH)tbb.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDBINPATH)tbb.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDBINPATH)tbbmalloc.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDBINPATH)tbbmalloc.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usd_ms.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usd_ms.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(PXR_PLUGINPATH_NAME)" "$(TargetDir)\usd" /I /Y /F /R /S %(Command) ================================================ FILE: usd-shared.props ================================================ shared D:\USD-21.02-debug\bin\ D:\USD-21.02-debug\lib\ D:\USD-21.02-debug\include\ D:\USD-21.02-debug\lib\usd\ D:\USD-21.02\bin\ D:\USD-21.02\lib\ D:\USD-21.02\include\ D:\USD-21.02\lib\usd\ %(PreprocessorDefinitions) $(USDINCLUDEPATH);$(USDINCLUDEPATH)\boost-1_70;%(AdditionalIncludeDirectories) dbghelp.lib;Ws2_32.lib;ar.lib;arch.lib;plug.lib;sdf.lib;tf.lib;usd.lib;usdUtils.lib;vt.lib;%(AdditionalDependencies) $(USDLIBPATH);%(AdditionalLibraryDirectories) /WHOLEARCHIVE:"$(USDLIBPATH)usd" %(AdditionalOptions) xcopy "$(USDLIBPATH)ar.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)ar.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)arch.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)arch.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)plug.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)plug.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)sdf.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)sdf.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)tf.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)tf.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usd.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usd.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usdUtils.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usdUtils.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)vt.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)vt.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDBINPATH)tbb.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDBINPATH)tbb.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(PXR_PLUGINPATH_NAME)" "$(TargetDir)\usd" /I /Y /F /R /S %(Command) %(PreprocessorDefinitions) $(USDINCLUDEPATH);$(USDINCLUDEPATH)\boost-1_70;%(AdditionalIncludeDirectories) dbghelp.lib;Ws2_32.lib;ar.lib;arch.lib;plug.lib;sdf.lib;tf.lib;usd.lib;usdUtils.lib;vt.lib;%(AdditionalDependencies) $(USDLIBPATH);%(AdditionalLibraryDirectories) /WHOLEARCHIVE:"$(USDLIBPATH)usd" %(AdditionalOptions) xcopy "$(USDLIBPATH)ar.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)ar.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)arch.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)arch.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)plug.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)plug.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)sdf.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)sdf.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)tf.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)tf.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usd.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usd.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usdUtils.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)usdUtils.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)vt.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDLIBPATH)vt.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(USDBINPATH)tbb.dll" "$(TargetDir)" /I /Y /F /R xcopy "$(USDBINPATH)tbb.pdb" "$(TargetDir)" /I /Y /F /R xcopy "$(PXR_PLUGINPATH_NAME)" "$(TargetDir)\usd" /I /Y /F /R /S %(Command) ================================================ FILE: usd.props ================================================