From 670c7463e630d741723fe9ca481eb104ff737fd4 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 2 May 2025 16:45:21 +0100 Subject: [PATCH 1/9] Add ARM64 shell extension and conditional installation. Fixes #50 --- .github/workflows/build.yml | 2 +- _msbuild.py | 52 ++++++++++++++++++---------------- ci/release.yml | 2 +- make.py | 3 +- pyproject.toml | 2 +- src/pymanager/appxmanifest.xml | 24 +++++++++------- src/pymanager/msi.wxs | 24 ++++++++++++---- 7 files changed, 65 insertions(+), 44 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6bb2a12..4f3b94a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,7 +36,7 @@ jobs: python-version: 3.14-dev - name: Install build dependencies - run: python -m pip install pymsbuild + run: python -m pip install "pymsbuild>=1.2.0b1" - name: 'Install test runner' run: python -m pip install pytest pytest-cov diff --git a/_msbuild.py b/_msbuild.py index cf8f71f..3eb51dd 100644 --- a/_msbuild.py +++ b/_msbuild.py @@ -127,6 +127,29 @@ def mainw_exe(name): ) +def pyshellext(platform): + return CProject(f"pyshellext-{platform}", + VersionInfo( + FileDescription="Python shell extension", + OriginalFilename=f"pyshellext.{platform}.dll", + ), + Property('StaticLibcppLinkage', 'true'), + ItemDefinition('ClCompile', LanguageStandard='stdcpp20'), + ItemDefinition('Link', + AdditionalDependencies=Prepend("RuntimeObject.lib;"), + SubSystem='WINDOWS', + ModuleDefinitionFile='$(SourceRootDir)src\\pyshellext\\pyshellext.def', + ), + Manifest('default.manifest'), + CSourceFile('shellext.cpp'), + ResourceFile('pyshellext.rc'), + SourceFile('pyshellext.def'), + source='src/pyshellext', + Platform=platform, + TargetName=f"pyshellext.{platform}", + ) + + PACKAGE = Package('python-manager', PyprojectTomlFile('pyproject.toml'), # MSIX manifest @@ -149,8 +172,7 @@ def mainw_exe(name): CProject('launcher', VersionInfo(FileDescription="Python launcher", OriginalFilename="launcher.exe"), CPP_SETTINGS, - Property('DynamicLibcppLinkage', 'true'), - ItemDefinition('ClCompile', RuntimeLibrary='MultiThreaded'), + Property('StaticLibcppLinkage', 'true'), ItemDefinition('Link', SubSystem='CONSOLE'), Manifest('default.manifest'), ResourceFile('pyicon.rc'), @@ -163,8 +185,7 @@ def mainw_exe(name): CProject('launcherw', VersionInfo(FileDescription="Python launcher (windowed)", OriginalFilename="launcherw.exe"), CPP_SETTINGS, - Property('DynamicLibcppLinkage', 'true'), - ItemDefinition('ClCompile', RuntimeLibrary='MultiThreaded'), + Property('StaticLibcppLinkage', 'true'), ItemDefinition('Link', SubSystem='WINDOWS'), Manifest('default.manifest'), ResourceFile('pywicon.rc'), @@ -203,27 +224,8 @@ def mainw_exe(name): main_exe("python3"), mainw_exe("pythonw3"), - CProject("pyshellext", - VersionInfo( - FileDescription="Python shell extension", - OriginalFilename="pyshellext.dll", - ), - Property('DynamicLibcppLinkage', 'true'), - ItemDefinition('ClCompile', - LanguageStandard='stdcpp20', - RuntimeLibrary='MultiThreaded', - ), - ItemDefinition('Link', - AdditionalDependencies=Prepend("RuntimeObject.lib;"), - SubSystem='WINDOWS', - ModuleDefinitionFile='$(SourceRootDir)src\\pyshellext\\pyshellext.def', - ), - Manifest('default.manifest'), - CSourceFile('shellext.cpp'), - ResourceFile('pyshellext.rc'), - SourceFile('pyshellext.def'), - source='src/pyshellext', - ) + pyshellext("x64"), + pyshellext("arm64"), ) diff --git a/ci/release.yml b/ci/release.yml index 6e6528a..1542c62 100644 --- a/ci/release.yml +++ b/ci/release.yml @@ -89,7 +89,7 @@ stages: workingDirectory: $(Build.BinariesDirectory) - powershell: | - python -m pip install pymsbuild + python -m pip install "pymsbuild>=1.2.0b1" displayName: 'Install build dependencies' - ${{ if eq(parameters.PreTest, 'true') }}: diff --git a/make.py b/make.py index 1da9cc2..fa9475b 100644 --- a/make.py +++ b/make.py @@ -2,7 +2,7 @@ import subprocess import sys from subprocess import check_call as run -from _make_helper import get_dirs, rmtree, unlink +from _make_helper import copyfile, get_dirs, rmtree, unlink # Clean DEBUG flag in case it affects build os.environ["PYMANAGER_DEBUG"] = "" @@ -42,6 +42,7 @@ cwd=DIRS["root"], env={**os.environ, "BUILD_SOURCEBRANCH": ref}) + # Bundle current latest release run([LAYOUT / "py-manager.exe", "install", "-v", "-f", "--download", TEMP / "bundle", "default"]) (LAYOUT / "bundled").mkdir(parents=True, exist_ok=True) diff --git a/pyproject.toml b/pyproject.toml index e4d9bdb..76c1914 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ['pymsbuild>=1.1.1,<2.0'] +requires = ['pymsbuild>=1.2.0b1,<2.0'] build-backend = "pymsbuild" [tool.coverage.run] diff --git a/src/pymanager/appxmanifest.xml b/src/pymanager/appxmanifest.xml index bb872fb..818de2a 100644 --- a/src/pymanager/appxmanifest.xml +++ b/src/pymanager/appxmanifest.xml @@ -2,20 +2,20 @@ + Publisher="CN=00000000-0000-0000-0000-000000000000" /> Python Install Manager Python Software Foundation @@ -194,13 +194,6 @@ - - - - - - - @@ -208,6 +201,17 @@ + + + + + + + + + diff --git a/src/pymanager/msi.wxs b/src/pymanager/msi.wxs index e843fe2..ee8da44 100644 --- a/src/pymanager/msi.wxs +++ b/src/pymanager/msi.wxs @@ -16,6 +16,8 @@ + + @@ -27,6 +29,8 @@ + + @@ -44,11 +48,6 @@ - - - - @@ -104,5 +103,20 @@ + + + + + + + + + + + From 996ba41151e8ff06631185784432160fa3b0a70d Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 2 May 2025 16:47:14 +0100 Subject: [PATCH 2/9] Minor cleanup --- make.py | 3 +-- src/pymanager/appxmanifest.xml | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/make.py b/make.py index fa9475b..1da9cc2 100644 --- a/make.py +++ b/make.py @@ -2,7 +2,7 @@ import subprocess import sys from subprocess import check_call as run -from _make_helper import copyfile, get_dirs, rmtree, unlink +from _make_helper import get_dirs, rmtree, unlink # Clean DEBUG flag in case it affects build os.environ["PYMANAGER_DEBUG"] = "" @@ -42,7 +42,6 @@ cwd=DIRS["root"], env={**os.environ, "BUILD_SOURCEBRANCH": ref}) - # Bundle current latest release run([LAYOUT / "py-manager.exe", "install", "-v", "-f", "--download", TEMP / "bundle", "default"]) (LAYOUT / "bundled").mkdir(parents=True, exist_ok=True) diff --git a/src/pymanager/appxmanifest.xml b/src/pymanager/appxmanifest.xml index 818de2a..df8b5c4 100644 --- a/src/pymanager/appxmanifest.xml +++ b/src/pymanager/appxmanifest.xml @@ -8,14 +8,14 @@ xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4" xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6" xmlns:desktop7="http://schemas.microsoft.com/appx/manifest/desktop/windows10/7" - xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4" xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" xmlns:uap13="http://schemas.microsoft.com/appx/manifest/uap/windows10/13" xmlns:uap17="http://schemas.microsoft.com/appx/manifest/uap/windows10/17"> + Publisher="CN=00000000-0000-0000-0000-000000000000" + ProcessorArchitecture="x64" /> Python Install Manager Python Software Foundation From 8aec712cf6099acc79d037b115ec9625c99331ee Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 2 May 2025 17:08:50 +0100 Subject: [PATCH 3/9] Correct MSI conditions --- src/pymanager/msi.wxs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pymanager/msi.wxs b/src/pymanager/msi.wxs index ee8da44..25088ef 100644 --- a/src/pymanager/msi.wxs +++ b/src/pymanager/msi.wxs @@ -103,15 +103,17 @@ + + Condition="WIX_NATIVE_MACHINE = 34404"> + + Condition="WIX_NATIVE_MACHINE = 43620"> From 13c887c4c69858c1b9e433f490aba2c43d347f78 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 2 May 2025 17:35:15 +0100 Subject: [PATCH 4/9] Register shell extension at package level --- src/pymanager/appxmanifest.xml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/pymanager/appxmanifest.xml b/src/pymanager/appxmanifest.xml index df8b5c4..b0a5d46 100644 --- a/src/pymanager/appxmanifest.xml +++ b/src/pymanager/appxmanifest.xml @@ -201,17 +201,6 @@ - - - - - - - - - @@ -280,5 +269,15 @@ + + + + + + + + + + From ea346bcd4f3ac0b620a9037dc8f6fe43f68ea473 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 2 May 2025 19:16:27 +0100 Subject: [PATCH 5/9] Back to SurrogateServer --- src/pymanager/appxmanifest.xml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/pymanager/appxmanifest.xml b/src/pymanager/appxmanifest.xml index b0a5d46..3caa516 100644 --- a/src/pymanager/appxmanifest.xml +++ b/src/pymanager/appxmanifest.xml @@ -201,6 +201,19 @@ + + + + + + + + + + + + @@ -269,15 +282,5 @@ - - - - - - - - - - From 5596ff6a0172852894f4fb49a62133801fafb3c7 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 2 May 2025 21:18:20 +0100 Subject: [PATCH 6/9] Replace inproc server with local server (exe) --- _msbuild.py | 43 ++++++++++++++-------------------- src/pymanager/appxmanifest.xml | 12 +++------- src/pymanager/msi.wxs | 24 ++++--------------- src/pyshellext/pyshellext.def | 3 --- src/pyshellext/shellext.cpp | 35 +++++++++++++-------------- 5 files changed, 44 insertions(+), 73 deletions(-) delete mode 100644 src/pyshellext/pyshellext.def diff --git a/_msbuild.py b/_msbuild.py index 3eb51dd..e1e73d0 100644 --- a/_msbuild.py +++ b/_msbuild.py @@ -127,29 +127,6 @@ def mainw_exe(name): ) -def pyshellext(platform): - return CProject(f"pyshellext-{platform}", - VersionInfo( - FileDescription="Python shell extension", - OriginalFilename=f"pyshellext.{platform}.dll", - ), - Property('StaticLibcppLinkage', 'true'), - ItemDefinition('ClCompile', LanguageStandard='stdcpp20'), - ItemDefinition('Link', - AdditionalDependencies=Prepend("RuntimeObject.lib;"), - SubSystem='WINDOWS', - ModuleDefinitionFile='$(SourceRootDir)src\\pyshellext\\pyshellext.def', - ), - Manifest('default.manifest'), - CSourceFile('shellext.cpp'), - ResourceFile('pyshellext.rc'), - SourceFile('pyshellext.def'), - source='src/pyshellext', - Platform=platform, - TargetName=f"pyshellext.{platform}", - ) - - PACKAGE = Package('python-manager', PyprojectTomlFile('pyproject.toml'), # MSIX manifest @@ -224,8 +201,24 @@ def pyshellext(platform): main_exe("python3"), mainw_exe("pythonw3"), - pyshellext("x64"), - pyshellext("arm64"), + CProject(f"pyshellext", + VersionInfo( + FileDescription="Python shell extension", + OriginalFilename=f"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', + Platform=platform, + ), ) diff --git a/src/pymanager/appxmanifest.xml b/src/pymanager/appxmanifest.xml index 3caa516..5930d6e 100644 --- a/src/pymanager/appxmanifest.xml +++ b/src/pymanager/appxmanifest.xml @@ -203,15 +203,9 @@ - - - - - - - - + + + diff --git a/src/pymanager/msi.wxs b/src/pymanager/msi.wxs index 25088ef..a491ccd 100644 --- a/src/pymanager/msi.wxs +++ b/src/pymanager/msi.wxs @@ -29,8 +29,6 @@ - - @@ -45,6 +43,11 @@ + + + + @@ -103,22 +106,5 @@ - - - - - - - - - - - - - diff --git a/src/pyshellext/pyshellext.def b/src/pyshellext/pyshellext.def deleted file mode 100644 index 751bc6c..0000000 --- a/src/pyshellext/pyshellext.def +++ /dev/null @@ -1,3 +0,0 @@ -EXPORTS - DllGetClassObject PRIVATE - DllCanUnloadNow PRIVATE diff --git a/src/pyshellext/shellext.cpp b/src/pyshellext/shellext.cpp index 4cbc64b..e2fe3ce 100644 --- a/src/pyshellext/shellext.cpp +++ b/src/pyshellext/shellext.cpp @@ -1,8 +1,6 @@ -// Support back to Windows 10 #define _WIN32_WINNT _WIN32_WINNT_WIN10 #include -// Use WRL to define a classic COM class #define __WRL_CLASSIC_COM__ #include @@ -428,23 +426,26 @@ class DECLSPEC_UUID(CLSID_IDLE_COMMAND) IdleCommand CoCreatableClass(IdleCommand); -STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv) -{ - return Module::GetModule().GetClassObject(rclsid, riid, ppv); -} +class OutOfProcModule : public Module +{ }; -STDAPI DllCanUnloadNow() +int WINAPI wWinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPWSTR lpCmdLine, + int nCmdShow +) { - return Module::GetModule().Terminate() ? S_OK : S_FALSE; + HANDLE hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + hModule = hInstance; + + CoInitializeEx(nullptr, COINIT_MULTITHREADED); + auto& module = OutOfProcModule::Create([=]() { SetEvent(hStopEvent); }); + module.RegisterObjects(); + ::WaitForSingleObject(hStopEvent, INFINITE); + module.UnregisterObjects(); + CoUninitialize(); + return 0; } - -STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*) -{ - if (reason == DLL_PROCESS_ATTACH) { - hModule = hinst; - DisableThreadLibraryCalls(hinst); - } - return TRUE; -} From 57c7cfb66cb615932bdf262b2bde6a78610f2e46 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 2 May 2025 21:24:21 +0100 Subject: [PATCH 7/9] Fixes --- _msbuild.py | 5 ++--- src/pyshellext/shellext.cpp | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/_msbuild.py b/_msbuild.py index e1e73d0..18353d3 100644 --- a/_msbuild.py +++ b/_msbuild.py @@ -201,10 +201,10 @@ def mainw_exe(name): main_exe("python3"), mainw_exe("pythonw3"), - CProject(f"pyshellext", + CProject("pyshellext", VersionInfo( FileDescription="Python shell extension", - OriginalFilename=f"pyshellext.exe", + OriginalFilename="pyshellext.exe", ), Property('StaticLibcppLinkage', 'true'), ItemDefinition('ClCompile', LanguageStandard='stdcpp20'), @@ -217,7 +217,6 @@ def mainw_exe(name): ResourceFile('pyshellext.rc'), source='src/pyshellext', ConfigurationType='Application', - Platform=platform, ), ) diff --git a/src/pyshellext/shellext.cpp b/src/pyshellext/shellext.cpp index d439c74..991e816 100644 --- a/src/pyshellext/shellext.cpp +++ b/src/pyshellext/shellext.cpp @@ -449,8 +449,10 @@ IExplorerCommand *MakeIdleCommand(HKEY hive, LPCWSTR root) { return Make(hive, root).Detach(); } +#endif +#ifndef PYSHELLEXT_TEST class OutOfProcModule : public Module { }; From 9568e9529f29fa0a6679947fe77989040265c0bc Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 2 May 2025 22:03:03 +0100 Subject: [PATCH 8/9] Just disable the extension in MSI --- src/pymanager/msi.wxs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/pymanager/msi.wxs b/src/pymanager/msi.wxs index a491ccd..d8d44ad 100644 --- a/src/pymanager/msi.wxs +++ b/src/pymanager/msi.wxs @@ -16,8 +16,6 @@ - - @@ -43,14 +41,21 @@ - - - - + + From 63432da2142b0e0e04c10e8970c5ec87d56d66b0 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 2 May 2025 22:10:16 +0100 Subject: [PATCH 9/9] Remove hyphens from comment --- src/pymanager/msi.wxs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pymanager/msi.wxs b/src/pymanager/msi.wxs index d8d44ad..9abd466 100644 --- a/src/pymanager/msi.wxs +++ b/src/pymanager/msi.wxs @@ -50,7 +50,7 @@ need to compile DLLs for each platform just for the MSI, as well as the EXE that we use for regular installs. Right now, not worth it. - --- +