Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions _msbuild_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,23 @@
CFunction('reg_rename_key'),
source='src/_native',
),
DllPackage('_shellext_test',
PyFile('_native/__init__.py'),
ItemDefinition('ClCompile',
PreprocessorDefinitions=Prepend("PYSHELLEXT_TEST=1;"),
LanguageStandard='stdcpp20',
),
ItemDefinition('Link', AdditionalDependencies=Prepend("RuntimeObject.lib;")),
CSourceFile('pyshellext/shellext.cpp'),
CSourceFile('pyshellext/shellext_test.cpp'),
IncludeFile('pyshellext/shellext.h'),
CSourceFile('_native/helpers.cpp'),
IncludeFile('_native/helpers.h'),
CFunction('shellext_RegReadStr'),
CFunction('shellext_ReadIdleInstalls'),
CFunction('shellext_ReadAllIdleInstalls'),
CFunction('shellext_PassthroughTitle'),
CFunction('shellext_IdleCommand'),
source='src',
)
)
71 changes: 49 additions & 22 deletions src/pyshellext/shellext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@

using namespace Microsoft::WRL;

#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <olectl.h>

#include <string>
#include <vector>
#include "shellext.h"

static HINSTANCE hModule;

Expand All @@ -23,14 +17,7 @@ static HINSTANCE hModule;
#define CLSID_COMMAND_ENUMERATOR "{F82C8CD5-A69C-45CC-ADC6-87FC5F4A7429}"


struct IdleData {
std::wstring title;
std::wstring exe;
std::wstring idle;
};


static LRESULT RegReadStr(HKEY key, LPCWSTR valueName, std::wstring& result)
LRESULT RegReadStr(HKEY key, LPCWSTR valueName, std::wstring& result)
{
DWORD reg_type;
while (true) {
Expand Down Expand Up @@ -59,7 +46,7 @@ static LRESULT RegReadStr(HKEY key, LPCWSTR valueName, std::wstring& result)
}


static HRESULT ReadIdleInstalls(std::vector<IdleData> &idles, HKEY hkPython, LPCWSTR company, REGSAM flags)
HRESULT ReadIdleInstalls(std::vector<IdleData> &idles, HKEY hkPython, LPCWSTR company, REGSAM flags)
{
HKEY hkCompany = NULL, hkTag = NULL, hkInstall = NULL;
LSTATUS err = RegOpenKeyExW(
Expand Down Expand Up @@ -121,6 +108,8 @@ static HRESULT ReadIdleInstalls(std::vector<IdleData> &idles, HKEY hkPython, LPC
data.idle += L"Lib\\idlelib\\idle.pyw";
}
}
} else {
err = 0;
}
}
if (err) {
Expand Down Expand Up @@ -154,11 +143,11 @@ static HRESULT ReadIdleInstalls(std::vector<IdleData> &idles, HKEY hkPython, LPC
return S_OK;
}

static HRESULT ReadAllIdleInstalls(std::vector<IdleData> &idles, HKEY hive, REGSAM flags)
HRESULT ReadAllIdleInstalls(std::vector<IdleData> &idles, HKEY hive, LPCWSTR root, REGSAM flags)
{
HKEY hkPython = NULL;
HRESULT hr = S_OK;
LSTATUS err = RegOpenKeyExW(hive, L"Software\\Python", 0, KEY_READ | flags, &hkPython);
LSTATUS err = RegOpenKeyExW(hive, root ? root : L"", 0, KEY_READ | flags, &hkPython);

for (DWORD i = 0; !err && hr == S_OK && i < 64; ++i) {
wchar_t name[512];
Expand Down Expand Up @@ -349,12 +338,12 @@ class DECLSPEC_UUID(CLSID_IDLE_COMMAND) IdleCommand
iconPath += L",-4";
}

hr = ReadAllIdleInstalls(idles, HKEY_LOCAL_MACHINE, KEY_WOW64_32KEY);
hr = ReadAllIdleInstalls(idles, HKEY_LOCAL_MACHINE, L"Software\\Python", KEY_WOW64_32KEY);
if (SUCCEEDED(hr)) {
hr = ReadAllIdleInstalls(idles, HKEY_LOCAL_MACHINE, KEY_WOW64_64KEY);
hr = ReadAllIdleInstalls(idles, HKEY_LOCAL_MACHINE, L"Software\\Python", KEY_WOW64_64KEY);
}
if (SUCCEEDED(hr)) {
hr = ReadAllIdleInstalls(idles, HKEY_CURRENT_USER, 0);
hr = ReadAllIdleInstalls(idles, HKEY_CURRENT_USER, L"Software\\Python", 0);
}

if (FAILED(hr)) {
Expand All @@ -365,6 +354,29 @@ class DECLSPEC_UUID(CLSID_IDLE_COMMAND) IdleCommand
}
}

#ifdef PYSHELLEXT_TEST
IdleCommand(HKEY hive, LPCWSTR root) : title(L"Edit in &IDLE")
{
HRESULT hr;

DWORD cch = 260;
while (iconPath.size() < cch) {
iconPath.resize(cch);
cch = GetModuleFileNameW(hModule, iconPath.data(), iconPath.size());
}
iconPath.resize(cch);
if (cch) {
iconPath += L",-4";
}

hr = ReadAllIdleInstalls(idles, hive, root, 0);

if (FAILED(hr)) {
idles.clear();
}
}
#endif

// IExplorerCommand
IFACEMETHODIMP GetTitle(IShellItemArray *psiItemArray, LPWSTR *ppszName)
{
Expand Down Expand Up @@ -427,6 +439,20 @@ class DECLSPEC_UUID(CLSID_IDLE_COMMAND) IdleCommand

CoCreatableClass(IdleCommand);

#ifdef PYSHELLEXT_TEST
IExplorerCommand *MakeLaunchCommand(std::wstring title, std::wstring exe, std::wstring idle)
{
IdleData data = { .title = title, .exe = exe, .idle = idle };
return Make<LaunchCommand>(data).Detach();
}


IExplorerCommand *MakeIdleCommand(HKEY hive, LPCWSTR root)
{
return Make<IdleCommand>(hive, root).Detach();
}
#endif


STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv)
{
Expand All @@ -439,7 +465,7 @@ STDAPI DllCanUnloadNow()
return Module<InProc>::GetModule().Terminate() ? S_OK : S_FALSE;
}


#ifndef PYSHELLEXT_TEST
STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*)
{
if (reason == DLL_PROCESS_ATTACH) {
Expand All @@ -448,3 +474,4 @@ STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*)
}
return TRUE;
}
#endif
23 changes: 23 additions & 0 deletions src/pyshellext/shellext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <olectl.h>

#include <string>
#include <vector>

LRESULT RegReadStr(HKEY key, LPCWSTR valueName, std::wstring& result);

struct IdleData {
std::wstring title;
std::wstring exe;
std::wstring idle;
};

HRESULT ReadIdleInstalls(std::vector<IdleData> &idles, HKEY hkPython, LPCWSTR company, REGSAM flags);
HRESULT ReadAllIdleInstalls(std::vector<IdleData> &idles, HKEY hive, LPCWSTR root, REGSAM flags);

IExplorerCommand *MakeIdleCommand(HKEY hive, LPCWSTR root);
IExplorerCommand *MakeLaunchCommand(std::wstring title, std::wstring exe, std::wstring idle);
Loading