diff --git a/_msbuild.py b/_msbuild.py index d191698..ee87f7c 100644 --- a/_msbuild.py +++ b/_msbuild.py @@ -148,6 +148,31 @@ def launcher_exe(name, platform, windowed=False): ) +def pyshellext(ext='.exe', **props): + link_opts = ItemDefinition( + 'Link', + AdditionalDependencies=Prepend('RuntimeObject.lib;'), + ) + if ext != '.exe': + link_opts.options['ModuleDefinitionFile'] = '$(SourceRootDir)src\\pyshellext\\pyshellext.def' + + + return CProject(f"pyshellext{ext.rpartition('.')[0]}", + VersionInfo( + FileDescription='Python shell extension', + OriginalFilename=f'pyshellext{ext}', + ), + ItemDefinition('ClCompile', LanguageStandard='stdcpp20'), + link_opts, + Manifest('default.manifest'), + CSourceFile('shellext.cpp'), + ResourceFile('pyshellext.rc'), + source='src/pyshellext', + StaticLibcppLinkage=True, + **props, + ) + + PACKAGE = Package('python-manager', PyprojectTomlFile('pyproject.toml'), # MSIX manifest @@ -206,23 +231,9 @@ def launcher_exe(name, platform, windowed=False): main_exe("python3"), mainw_exe("pythonw3"), - CProject("pyshellext", - VersionInfo( - FileDescription="Python shell extension", - OriginalFilename="pyshellext.exe", - ), - Property('StaticLibcppLinkage', 'true'), - ItemDefinition('ClCompile', LanguageStandard='stdcpp20'), - ItemDefinition('Link', - AdditionalDependencies=Prepend("RuntimeObject.lib;"), - SubSystem='WINDOWS', - ), - Manifest('default.manifest'), - CSourceFile('shellext.cpp'), - ResourceFile('pyshellext.rc'), - source='src/pyshellext', - ConfigurationType='Application', - ), + pyshellext(".exe", ConfigurationType="Application"), + pyshellext("-64.dll", Platform="x64"), + pyshellext("-arm64.dll", Platform="ARM64"), ) diff --git a/make-msix.py b/make-msix.py index 84f3e70..cc07fdc 100644 --- a/make-msix.py +++ b/make-msix.py @@ -53,10 +53,19 @@ "/mf", "appx"]) # Clean up non-shipping files from LAYOUT +preserved = [ + *LAYOUT.glob("pyshellext*.dll"), +] + +for f in preserved: + print("Preserving", f, "as", TEMP / f.name) + copyfile(f, TEMP / f.name) + unlink( *LAYOUT.rglob("*.pdb"), *LAYOUT.rglob("*.pyc"), *LAYOUT.rglob("__pycache__"), + *preserved, ) # Package into DIST @@ -122,3 +131,9 @@ def patch_appx(source): with zipfile.ZipFile(DIST_MSIXUPLOAD, "w") as zf: zf.write(DIST_STORE_MSIX, arcname=DIST_STORE_MSIX.name) zf.write(DIST_APPXSYM, arcname=DIST_APPXSYM.name) + + +for f in preserved: + print("Restoring", f, "from", TEMP / f.name) + copyfile(TEMP / f.name, f) + unlink(TEMP / f.name) diff --git a/src/pymanager/msi.wxs b/src/pymanager/msi.wxs index a9a33c1..320dfad 100644 --- a/src/pymanager/msi.wxs +++ b/src/pymanager/msi.wxs @@ -27,9 +27,12 @@ + + + @@ -44,18 +47,6 @@ - - @@ -115,5 +106,21 @@ + + + + + + + + + + + + + + diff --git a/src/pyshellext/pyshellext.def b/src/pyshellext/pyshellext.def new file mode 100644 index 0000000..751bc6c --- /dev/null +++ b/src/pyshellext/pyshellext.def @@ -0,0 +1,3 @@ +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE diff --git a/src/pyshellext/shellext.cpp b/src/pyshellext/shellext.cpp index 991e816..974bf92 100644 --- a/src/pyshellext/shellext.cpp +++ b/src/pyshellext/shellext.cpp @@ -167,7 +167,7 @@ HRESULT ReadAllIdleInstalls(std::vector &idles, HKEY hive, LPCWSTR roo } class DECLSPEC_UUID(CLSID_LAUNCH_COMMAND) LaunchCommand - : public RuntimeClass, IExplorerCommand> + : public RuntimeClass, IExplorerCommand, IObjectWithSite> { std::wstring title; std::wstring exe; @@ -269,6 +269,26 @@ class DECLSPEC_UUID(CLSID_LAUNCH_COMMAND) LaunchCommand *ppEnum = NULL; return E_NOTIMPL; } + + // IObjectWithSite +private: + ComPtr _site; + +public: + IFACEMETHODIMP GetSite(REFIID riid, void **ppvSite) + { + if (_site) { + return _site->QueryInterface(riid, ppvSite); + } + *ppvSite = NULL; + return E_FAIL; + } + + IFACEMETHODIMP SetSite(IUnknown *pSite) + { + _site = pSite; + return S_OK; + } }; @@ -316,7 +336,7 @@ class DECLSPEC_UUID(CLSID_COMMAND_ENUMERATOR) CommandEnumerator class DECLSPEC_UUID(CLSID_IDLE_COMMAND) IdleCommand - : public RuntimeClass, IExplorerCommand> + : public RuntimeClass, IExplorerCommand, IObjectWithSite> { std::vector idles; std::wstring iconPath; @@ -432,12 +452,33 @@ class DECLSPEC_UUID(CLSID_IDLE_COMMAND) IdleCommand ).Detach(); return S_OK; } + + // IObjectWithSite +private: + ComPtr _site; + +public: + IFACEMETHODIMP GetSite(REFIID riid, void **ppvSite) + { + if (_site) { + return _site->QueryInterface(riid, ppvSite); + } + *ppvSite = NULL; + return E_FAIL; + } + + IFACEMETHODIMP SetSite(IUnknown *pSite) + { + _site = pSite; + return S_OK; + } }; CoCreatableClass(IdleCommand); #ifdef PYSHELLEXT_TEST + IExplorerCommand *MakeLaunchCommand(std::wstring title, std::wstring exe, std::wstring idle) { IdleData data = { .title = title, .exe = exe, .idle = idle }; @@ -449,10 +490,31 @@ IExplorerCommand *MakeIdleCommand(HKEY hive, LPCWSTR root) { return Make(hive, root).Detach(); } -#endif +#elif defined(_WINDLL) + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv) +{ + return Module::GetModule().GetClassObject(rclsid, riid, ppv); +} + + +STDAPI DllCanUnloadNow() +{ + return Module::GetModule().Terminate() ? S_OK : S_FALSE; +} + +STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*) +{ + if (reason == DLL_PROCESS_ATTACH) { + hModule = hinst; + DisableThreadLibraryCalls(hinst); + } + return TRUE; +} + +#else -#ifndef PYSHELLEXT_TEST class OutOfProcModule : public Module { }; @@ -475,4 +537,5 @@ int WINAPI wWinMain( CoUninitialize(); return 0; } + #endif