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