Skip to content

Commit 0e16136

Browse files
authored
Adds test harness and tests for pyshellext. (#62)
Fixes #54
1 parent 2e4203c commit 0e16136

File tree

7 files changed

+489
-59
lines changed

7 files changed

+489
-59
lines changed

_msbuild_test.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,23 @@
5252
CFunction('reg_rename_key'),
5353
source='src/_native',
5454
),
55+
DllPackage('_shellext_test',
56+
PyFile('_native/__init__.py'),
57+
ItemDefinition('ClCompile',
58+
PreprocessorDefinitions=Prepend("PYSHELLEXT_TEST=1;"),
59+
LanguageStandard='stdcpp20',
60+
),
61+
ItemDefinition('Link', AdditionalDependencies=Prepend("RuntimeObject.lib;")),
62+
CSourceFile('pyshellext/shellext.cpp'),
63+
CSourceFile('pyshellext/shellext_test.cpp'),
64+
IncludeFile('pyshellext/shellext.h'),
65+
CSourceFile('_native/helpers.cpp'),
66+
IncludeFile('_native/helpers.h'),
67+
CFunction('shellext_RegReadStr'),
68+
CFunction('shellext_ReadIdleInstalls'),
69+
CFunction('shellext_ReadAllIdleInstalls'),
70+
CFunction('shellext_PassthroughTitle'),
71+
CFunction('shellext_IdleCommand'),
72+
source='src',
73+
)
5574
)

src/pyshellext/shellext.cpp

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,7 @@
88

99
using namespace Microsoft::WRL;
1010

11-
#include <windows.h>
12-
#include <shlobj.h>
13-
#include <shlwapi.h>
14-
#include <olectl.h>
15-
16-
#include <string>
17-
#include <vector>
11+
#include "shellext.h"
1812

1913
static HINSTANCE hModule;
2014

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

2519

26-
struct IdleData {
27-
std::wstring title;
28-
std::wstring exe;
29-
std::wstring idle;
30-
};
31-
32-
33-
static LRESULT RegReadStr(HKEY key, LPCWSTR valueName, std::wstring& result)
20+
LRESULT RegReadStr(HKEY key, LPCWSTR valueName, std::wstring& result)
3421
{
3522
DWORD reg_type;
3623
while (true) {
@@ -59,7 +46,7 @@ static LRESULT RegReadStr(HKEY key, LPCWSTR valueName, std::wstring& result)
5946
}
6047

6148

62-
static HRESULT ReadIdleInstalls(std::vector<IdleData> &idles, HKEY hkPython, LPCWSTR company, REGSAM flags)
49+
HRESULT ReadIdleInstalls(std::vector<IdleData> &idles, HKEY hkPython, LPCWSTR company, REGSAM flags)
6350
{
6451
HKEY hkCompany = NULL, hkTag = NULL, hkInstall = NULL;
6552
LSTATUS err = RegOpenKeyExW(
@@ -121,6 +108,8 @@ static HRESULT ReadIdleInstalls(std::vector<IdleData> &idles, HKEY hkPython, LPC
121108
data.idle += L"Lib\\idlelib\\idle.pyw";
122109
}
123110
}
111+
} else {
112+
err = 0;
124113
}
125114
}
126115
if (err) {
@@ -154,11 +143,11 @@ static HRESULT ReadIdleInstalls(std::vector<IdleData> &idles, HKEY hkPython, LPC
154143
return S_OK;
155144
}
156145

157-
static HRESULT ReadAllIdleInstalls(std::vector<IdleData> &idles, HKEY hive, REGSAM flags)
146+
HRESULT ReadAllIdleInstalls(std::vector<IdleData> &idles, HKEY hive, LPCWSTR root, REGSAM flags)
158147
{
159148
HKEY hkPython = NULL;
160149
HRESULT hr = S_OK;
161-
LSTATUS err = RegOpenKeyExW(hive, L"Software\\Python", 0, KEY_READ | flags, &hkPython);
150+
LSTATUS err = RegOpenKeyExW(hive, root ? root : L"", 0, KEY_READ | flags, &hkPython);
162151

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

352-
hr = ReadAllIdleInstalls(idles, HKEY_LOCAL_MACHINE, KEY_WOW64_32KEY);
341+
hr = ReadAllIdleInstalls(idles, HKEY_LOCAL_MACHINE, L"Software\\Python", KEY_WOW64_32KEY);
353342
if (SUCCEEDED(hr)) {
354-
hr = ReadAllIdleInstalls(idles, HKEY_LOCAL_MACHINE, KEY_WOW64_64KEY);
343+
hr = ReadAllIdleInstalls(idles, HKEY_LOCAL_MACHINE, L"Software\\Python", KEY_WOW64_64KEY);
355344
}
356345
if (SUCCEEDED(hr)) {
357-
hr = ReadAllIdleInstalls(idles, HKEY_CURRENT_USER, 0);
346+
hr = ReadAllIdleInstalls(idles, HKEY_CURRENT_USER, L"Software\\Python", 0);
358347
}
359348

360349
if (FAILED(hr)) {
@@ -365,6 +354,29 @@ class DECLSPEC_UUID(CLSID_IDLE_COMMAND) IdleCommand
365354
}
366355
}
367356

357+
#ifdef PYSHELLEXT_TEST
358+
IdleCommand(HKEY hive, LPCWSTR root) : title(L"Edit in &IDLE")
359+
{
360+
HRESULT hr;
361+
362+
DWORD cch = 260;
363+
while (iconPath.size() < cch) {
364+
iconPath.resize(cch);
365+
cch = GetModuleFileNameW(hModule, iconPath.data(), iconPath.size());
366+
}
367+
iconPath.resize(cch);
368+
if (cch) {
369+
iconPath += L",-4";
370+
}
371+
372+
hr = ReadAllIdleInstalls(idles, hive, root, 0);
373+
374+
if (FAILED(hr)) {
375+
idles.clear();
376+
}
377+
}
378+
#endif
379+
368380
// IExplorerCommand
369381
IFACEMETHODIMP GetTitle(IShellItemArray *psiItemArray, LPWSTR *ppszName)
370382
{
@@ -427,6 +439,20 @@ class DECLSPEC_UUID(CLSID_IDLE_COMMAND) IdleCommand
427439

428440
CoCreatableClass(IdleCommand);
429441

442+
#ifdef PYSHELLEXT_TEST
443+
IExplorerCommand *MakeLaunchCommand(std::wstring title, std::wstring exe, std::wstring idle)
444+
{
445+
IdleData data = { .title = title, .exe = exe, .idle = idle };
446+
return Make<LaunchCommand>(data).Detach();
447+
}
448+
449+
450+
IExplorerCommand *MakeIdleCommand(HKEY hive, LPCWSTR root)
451+
{
452+
return Make<IdleCommand>(hive, root).Detach();
453+
}
454+
#endif
455+
430456

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

442-
468+
#ifndef PYSHELLEXT_TEST
443469
STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*)
444470
{
445471
if (reason == DLL_PROCESS_ATTACH) {
@@ -448,3 +474,4 @@ STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*)
448474
}
449475
return TRUE;
450476
}
477+
#endif

src/pyshellext/shellext.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
3+
#include <windows.h>
4+
#include <shlobj.h>
5+
#include <shlwapi.h>
6+
#include <olectl.h>
7+
8+
#include <string>
9+
#include <vector>
10+
11+
LRESULT RegReadStr(HKEY key, LPCWSTR valueName, std::wstring& result);
12+
13+
struct IdleData {
14+
std::wstring title;
15+
std::wstring exe;
16+
std::wstring idle;
17+
};
18+
19+
HRESULT ReadIdleInstalls(std::vector<IdleData> &idles, HKEY hkPython, LPCWSTR company, REGSAM flags);
20+
HRESULT ReadAllIdleInstalls(std::vector<IdleData> &idles, HKEY hive, LPCWSTR root, REGSAM flags);
21+
22+
IExplorerCommand *MakeIdleCommand(HKEY hive, LPCWSTR root);
23+
IExplorerCommand *MakeLaunchCommand(std::wstring title, std::wstring exe, std::wstring idle);

0 commit comments

Comments
 (0)