Skip to content

Commit 321bdb6

Browse files
authored
Replace in-process shell extension with out-of-proc extension (#64)
This makes it work on ARM64 through the MSIX install, but leaves the MSI install without an extension. That's a reasonable tradeoff right now, and possibly forever. Fixes #50
1 parent 0e16136 commit 321bdb6

File tree

8 files changed

+47
-48
lines changed

8 files changed

+47
-48
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
python-version: 3.14-dev
3737

3838
- name: Install build dependencies
39-
run: python -m pip install pymsbuild
39+
run: python -m pip install "pymsbuild>=1.2.0b1"
4040

4141
- name: 'Install test runner'
4242
run: python -m pip install pytest pytest-cov

_msbuild.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,7 @@ def mainw_exe(name):
149149
CProject('launcher',
150150
VersionInfo(FileDescription="Python launcher", OriginalFilename="launcher.exe"),
151151
CPP_SETTINGS,
152-
Property('DynamicLibcppLinkage', 'true'),
153-
ItemDefinition('ClCompile', RuntimeLibrary='MultiThreaded'),
152+
Property('StaticLibcppLinkage', 'true'),
154153
ItemDefinition('Link', SubSystem='CONSOLE'),
155154
Manifest('default.manifest'),
156155
ResourceFile('pyicon.rc'),
@@ -163,8 +162,7 @@ def mainw_exe(name):
163162
CProject('launcherw',
164163
VersionInfo(FileDescription="Python launcher (windowed)", OriginalFilename="launcherw.exe"),
165164
CPP_SETTINGS,
166-
Property('DynamicLibcppLinkage', 'true'),
167-
ItemDefinition('ClCompile', RuntimeLibrary='MultiThreaded'),
165+
Property('StaticLibcppLinkage', 'true'),
168166
ItemDefinition('Link', SubSystem='WINDOWS'),
169167
Manifest('default.manifest'),
170168
ResourceFile('pywicon.rc'),
@@ -206,24 +204,20 @@ def mainw_exe(name):
206204
CProject("pyshellext",
207205
VersionInfo(
208206
FileDescription="Python shell extension",
209-
OriginalFilename="pyshellext.dll",
210-
),
211-
Property('DynamicLibcppLinkage', 'true'),
212-
ItemDefinition('ClCompile',
213-
LanguageStandard='stdcpp20',
214-
RuntimeLibrary='MultiThreaded',
207+
OriginalFilename="pyshellext.exe",
215208
),
209+
Property('StaticLibcppLinkage', 'true'),
210+
ItemDefinition('ClCompile', LanguageStandard='stdcpp20'),
216211
ItemDefinition('Link',
217212
AdditionalDependencies=Prepend("RuntimeObject.lib;"),
218213
SubSystem='WINDOWS',
219-
ModuleDefinitionFile='$(SourceRootDir)src\\pyshellext\\pyshellext.def',
220214
),
221215
Manifest('default.manifest'),
222216
CSourceFile('shellext.cpp'),
223217
ResourceFile('pyshellext.rc'),
224-
SourceFile('pyshellext.def'),
225218
source='src/pyshellext',
226-
)
219+
ConfigurationType='Application',
220+
),
227221
)
228222

229223

ci/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ stages:
8989
workingDirectory: $(Build.BinariesDirectory)
9090
9191
- powershell: |
92-
python -m pip install pymsbuild
92+
python -m pip install "pymsbuild>=1.2.0b1"
9393
displayName: 'Install build dependencies'
9494
9595
- ${{ if eq(parameters.PreTest, 'true') }}:

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[build-system]
2-
requires = ['pymsbuild>=1.1.1,<2.0']
2+
requires = ['pymsbuild>=1.2.0b1,<2.0']
33
build-backend = "pymsbuild"
44

55
[tool.coverage.run]

src/pymanager/appxmanifest.xml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<Package IgnorableNamespaces="desktop4 desktop6 desktop7 uap13 uap17"
33
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
44
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
5-
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
5+
xmlns:com4="http://schemas.microsoft.com/appx/manifest/com/windows10/4"
66
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
77
xmlns:rescap4="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/4"
88
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
@@ -194,20 +194,20 @@
194194
</uap:SupportedFileTypes>
195195
</uap:FileTypeAssociation>
196196
</uap:Extension>
197-
<com:Extension Category="windows.comServer">
198-
<com:ComServer>
199-
<com:SurrogateServer AppId="C7E29CB0-9691-4DE8-B72B-6719DDC0B4A1" DisplayName="EditInIdleCommand">
200-
<com:Class Id="C7E29CB0-9691-4DE8-B72B-6719DDC0B4A1" Path="pyshellext.dll" ThreadingModel="Both"/>
201-
</com:SurrogateServer>
202-
</com:ComServer>
203-
</com:Extension>
204197
<desktop4:Extension Category="windows.fileExplorerContextMenus">
205198
<desktop4:FileExplorerContextMenus>
206199
<desktop4:ItemType Type=".py">
207200
<desktop4:Verb Id="EditInIdle" Clsid="C7E29CB0-9691-4DE8-B72B-6719DDC0B4A1" />
208201
</desktop4:ItemType>
209202
</desktop4:FileExplorerContextMenus>
210203
</desktop4:Extension>
204+
<com4:Extension Category="windows.comServer">
205+
<com4:ComServer>
206+
<com4:ExeServer Executable="pyshellext.exe" DisplayName="Python Shell Extension">
207+
<com4:Class Id="C7E29CB0-9691-4DE8-B72B-6719DDC0B4A1" DisplayName="EditInIdleCommand" />
208+
</com4:ExeServer>
209+
</com4:ComServer>
210+
</com4:Extension>
211211
</Extensions>
212212
</Application>
213213

src/pymanager/msi.wxs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,17 @@
4444
<File Source="vcruntime140.dll" />
4545
<File Source="vcruntime140_1.dll" />
4646

47-
<File Source="pyshellext.dll">
48-
<Class Id="{C7E29CB0-9691-4DE8-B72B-6719DDC0B4A1}" Advertise="no"
49-
Context="InprocServer32" ThreadingModel="both" />
47+
<!--
48+
When installed via MSIX, this extension must be out of proc.
49+
Apparently, when installed via MSI, it must be in proc. Which means we'd
50+
need to compile DLLs for each platform just for the MSI, as well as the
51+
EXE that we use for regular installs.
52+
Right now, not worth it.
53+
54+
<File Source="pyshellext.exe">
55+
<Class Id="{C7E29CB0-9691-4DE8-B72B-6719DDC0B4A1}" Advertise="no" Context="LocalServer32" />
5056
</File>
57+
-->
5158

5259
<File Source="version.txt" />
5360
<Environment Id="PATH" Action="set" Name="PATH" Part="last" System="yes" Value="[INSTALLFOLDER]" />

src/pyshellext/pyshellext.def

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/pyshellext/shellext.cpp

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
// Support back to Windows 10
21
#define _WIN32_WINNT _WIN32_WINNT_WIN10
32
#include <sdkddkver.h>
43

5-
// Use WRL to define a classic COM class
64
#define __WRL_CLASSIC_COM__
75
#include <wrl.h>
86

@@ -454,24 +452,27 @@ IExplorerCommand *MakeIdleCommand(HKEY hive, LPCWSTR root)
454452
#endif
455453

456454

457-
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv)
458-
{
459-
return Module<InProc>::GetModule().GetClassObject(rclsid, riid, ppv);
460-
}
461-
455+
#ifndef PYSHELLEXT_TEST
456+
class OutOfProcModule : public Module<OutOfProc, OutOfProcModule>
457+
{ };
462458

463-
STDAPI DllCanUnloadNow()
464-
{
465-
return Module<InProc>::GetModule().Terminate() ? S_OK : S_FALSE;
466-
}
467459

468-
#ifndef PYSHELLEXT_TEST
469-
STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*)
460+
int WINAPI wWinMain(
461+
HINSTANCE hInstance,
462+
HINSTANCE hPrevInstance,
463+
LPWSTR lpCmdLine,
464+
int nCmdShow
465+
)
470466
{
471-
if (reason == DLL_PROCESS_ATTACH) {
472-
hModule = hinst;
473-
DisableThreadLibraryCalls(hinst);
474-
}
475-
return TRUE;
467+
HANDLE hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
468+
hModule = hInstance;
469+
470+
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
471+
auto& module = OutOfProcModule::Create([=]() { SetEvent(hStopEvent); });
472+
module.RegisterObjects();
473+
::WaitForSingleObject(hStopEvent, INFINITE);
474+
module.UnregisterObjects();
475+
CoUninitialize();
476+
return 0;
476477
}
477478
#endif

0 commit comments

Comments
 (0)