Skip to content

Commit 4f05154

Browse files
GurliGebisdonho
authored andcommitted
Refactoring and cleanup
Close #21
1 parent 8f26080 commit 4f05154

8 files changed

+291
-130
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ Packaging/NppShell.msix
44
*.user
55
Debug
66
Release
7+
*.user

Installer.cpp

+65-125
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "ClassicEditWithNppExplorerCommandHandler.h"
55
#include "PathHelper.h"
66
#include "AclHelper.h"
7+
#include "RegistryKey.h"
78

89
#define GUID_STRING_SIZE 40
910

@@ -14,6 +15,7 @@ using namespace winrt::Windows::Management::Deployment;
1415

1516
using namespace NppShell::Helpers;
1617
using namespace NppShell::Installer;
18+
using namespace NppShell::Registry;
1719

1820
extern HMODULE thisModule;
1921

@@ -30,37 +32,12 @@ const wstring ShellExtensionKey = L"Software\\Classes\\*\\shellex\\ContextMenuHa
3032

3133
bool IsWindows11Installation()
3234
{
33-
wstring keyName = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
34-
wstring valueName = L"CurrentBuildNumber";
35+
RegistryKey registryKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
36+
wstring buildNumberString = registryKey.GetStringValue(L"CurrentBuildNumber");
3537

36-
bool result = false;
38+
const int buildNumber = stoi(buildNumberString);
3739

38-
HKEY hkey;
39-
HRESULT hResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName.c_str(), 0, KEY_READ, &hkey);
40-
41-
if (hResult == ERROR_SUCCESS)
42-
{
43-
DWORD cbData = 0;
44-
hResult = RegGetValue(hkey, nullptr, valueName.c_str(), RRF_RT_REG_SZ, nullptr, nullptr, &cbData);
45-
46-
if (hResult == ERROR_SUCCESS)
47-
{
48-
vector<BYTE> buffer(cbData + 1);
49-
50-
cbData = (DWORD)buffer.size();
51-
hResult = RegGetValue(hkey, nullptr, valueName.c_str(), RRF_RT_REG_SZ, nullptr, &buffer[0], &cbData);
52-
53-
wstring buildNumberString(reinterpret_cast<wchar_t*>(&buffer[0]));
54-
55-
const int buildNumber = stoi(buildNumberString);
56-
57-
result = buildNumber >= FirstWindows11BuildNumber;
58-
}
59-
}
60-
61-
RegCloseKey(hkey);
62-
63-
return result;
40+
return buildNumber >= FirstWindows11BuildNumber;
6441
}
6542

6643
wstring GetCLSIDString()
@@ -90,120 +67,63 @@ wstring GetCLSIDString()
9067
return guid;
9168
}
9269

93-
LRESULT RemoveRegistryKeyIfFound(HKEY hive, wstring keyName)
70+
void inline CleanupRegistry(const wstring& guid)
9471
{
95-
HKEY hkey;
96-
const LRESULT lResult = RegOpenKeyEx(hive, keyName.c_str(), 0, KEY_READ, &hkey);
97-
98-
if (lResult == ERROR_FILE_NOT_FOUND)
72+
// First we remove the shell key if it exists.
73+
if (RegistryKey::KeyExists(HKEY_LOCAL_MACHINE, ShellKey))
9974
{
100-
// Does not exist, so nothing to remove
101-
return ERROR_SUCCESS;
75+
RegistryKey registryKey(HKEY_LOCAL_MACHINE, ShellKey, KEY_READ | KEY_WRITE);
76+
registryKey.DeleteKey();
10277
}
10378

104-
if (lResult != ERROR_SUCCESS)
79+
// Then we remove the shell extension key if it exists.
80+
if (RegistryKey::KeyExists(HKEY_LOCAL_MACHINE, ShellExtensionKey))
10581
{
106-
return lResult;
82+
RegistryKey registryKey(HKEY_LOCAL_MACHINE, ShellExtensionKey, KEY_READ | KEY_WRITE);
83+
registryKey.DeleteKey();
10784
}
10885

109-
RegCloseKey(hkey);
110-
111-
return RegDeleteTree(hive, keyName.c_str());
112-
}
113-
114-
LRESULT CreateRegistryKey(const HKEY hive, const wstring& key, const wstring& name, const wstring& value)
115-
{
116-
HKEY regKey;
117-
LRESULT lResult = RegCreateKeyEx(hive, key.data(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &regKey, NULL);
118-
119-
if (lResult != ERROR_SUCCESS)
86+
// Then we remove the Notepad++_file key if it exists.
87+
if (RegistryKey::KeyExists(HKEY_LOCAL_MACHINE, L"Notepad++_file\\shellex"))
12088
{
121-
return lResult;
89+
RegistryKey registryKey(HKEY_LOCAL_MACHINE, L"Notepad++_file\\shellex", KEY_READ | KEY_WRITE);
90+
registryKey.DeleteKey();
12291
}
12392

124-
lResult = RegSetKeyValue(regKey, NULL, name.empty() ? NULL : name.data(), REG_SZ, value.data(), static_cast<DWORD>(value.length() * sizeof TCHAR));
125-
126-
RegCloseKey(regKey);
127-
128-
return lResult;
129-
}
130-
131-
LRESULT CleanupRegistry(const wstring& guid)
132-
{
133-
constexpr int bufferSize = MAX_PATH + GUID_STRING_SIZE;
134-
WCHAR buffer[bufferSize];
135-
const auto arraySize = bufferSize * sizeof(WCHAR);
136-
137-
LRESULT result;
138-
139-
result = RemoveRegistryKeyIfFound(HKEY_LOCAL_MACHINE, ShellKey);
140-
141-
if (result != ERROR_SUCCESS)
93+
// Finally we remove the CLSID key if it exists.
94+
if (RegistryKey::KeyExists(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\" + guid))
14295
{
143-
return result;
144-
}
145-
146-
result = RemoveRegistryKeyIfFound(HKEY_LOCAL_MACHINE, ShellExtensionKey);
147-
148-
if (result != ERROR_SUCCESS)
149-
{
150-
return result;
151-
}
152-
153-
StringCbPrintf(buffer, arraySize, L"Notepad++_file\\shellex");
154-
result = RemoveRegistryKeyIfFound(HKEY_CLASSES_ROOT, buffer);
155-
if (result != ERROR_SUCCESS)
156-
{
157-
return result;
96+
RegistryKey registryKey(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\" + guid, KEY_READ | KEY_WRITE);
97+
registryKey.DeleteKey();
15898
}
99+
}
159100

160-
StringCbPrintf(buffer, arraySize, L"Software\\Classes\\CLSID\\%s", guid.c_str());
161-
result = RemoveRegistryKeyIfFound(HKEY_LOCAL_MACHINE, buffer);
162-
if (result != ERROR_SUCCESS)
101+
void inline CleanupHack()
102+
{
103+
// First we test if the key even exists.
104+
if (!RegistryKey::KeyExists(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Classes\\*\\shell\\pintohome"))
163105
{
164-
return result;
106+
return;
165107
}
166108

167-
return ERROR_SUCCESS;
168-
}
169-
170-
LRESULT CleanupHack()
171-
{
172-
wstring keyName = L"SOFTWARE\\Classes\\*\\shell\\pintohome";
109+
// If it does, we open it and check if the value exists.
173110
wstring valueName = L"MUIVerb";
111+
RegistryKey registryKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Classes\\*\\shell\\pintohome", KEY_READ | KEY_WRITE);
174112

175-
LRESULT result = 0;
176-
bool found = false;
177-
178-
HKEY hkey;
179-
HRESULT hResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName.c_str(), 0, KEY_READ, &hkey);
180-
181-
if (hResult == ERROR_SUCCESS)
113+
if (!registryKey.ValueExists(valueName))
182114
{
183-
DWORD cbData = 0;
184-
hResult = RegGetValue(hkey, nullptr, valueName.c_str(), RRF_RT_REG_SZ, nullptr, nullptr, &cbData);
185-
186-
if (hResult == ERROR_SUCCESS)
187-
{
188-
vector<BYTE> buffer(cbData + 1);
189-
190-
cbData = (DWORD)buffer.size();
191-
hResult = RegGetValue(hkey, nullptr, valueName.c_str(), RRF_RT_REG_SZ, nullptr, &buffer[0], &cbData);
192-
193-
wstring valueString(reinterpret_cast<wchar_t*>(&buffer[0]));
194-
195-
found = valueString.find(L"Notepad++") != wstring::npos;
196-
}
115+
return;
197116
}
198117

199-
RegCloseKey(hkey);
118+
// Then we get the value and see if it contains the text "Notepad++"
119+
wstring currentValue = registryKey.GetStringValue(valueName);
120+
bool found = currentValue.find(L"Notepad++") != wstring::npos;
200121

122+
// If we found the text, we delete the entire key.
201123
if (found)
202124
{
203-
result = RegDeleteTree(HKEY_LOCAL_MACHINE, keyName.c_str());
125+
registryKey.DeleteKey();
204126
}
205-
206-
return result;
207127
}
208128

209129
HRESULT MoveFileToTempAndScheduleDeletion(const wstring& filePath, bool moveToTempDirectory)
@@ -215,7 +135,10 @@ HRESULT MoveFileToTempAndScheduleDeletion(const wstring& filePath, bool moveToTe
215135

216136
if (moveToTempDirectory)
217137
{
138+
// First we get the path to the temporary directory.
218139
GetTempPath(MAX_PATH, &tempPath[0]);
140+
141+
// Then we get a temporary filename in the temporary directory.
219142
GetTempFileName(tempPath.c_str(), L"tempFileName", 0, &tempFileName[0]);
220143

221144
// Move the file into the temp directory - it can be moved even when it is loaded into memory and locked.
@@ -320,15 +243,22 @@ HRESULT NppShell::Installer::UnregisterSparsePackage()
320243

321244
HRESULT NppShell::Installer::RegisterOldContextMenu()
322245
{
323-
const wstring installationPath = GetContextMenuPath();
246+
const wstring contextMenuFullName = GetContextMenuFullName();
324247
const wstring guid = GetCLSIDString();
325248

326-
CreateRegistryKey(HKEY_LOCAL_MACHINE, ShellKey, L"ExplorerCommandHandler", guid.c_str());
327-
CreateRegistryKey(HKEY_LOCAL_MACHINE, ShellKey, L"", L"Notepad++ Context menu");
328-
CreateRegistryKey(HKEY_LOCAL_MACHINE, ShellKey, L"NeverDefault", L"");
329-
CreateRegistryKey(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\" + guid, L"", L"notepad++");
330-
CreateRegistryKey(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\" + guid + L"\\InProcServer32", L"", installationPath + L"\\NppShell.dll");
331-
CreateRegistryKey(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\" + guid + L"\\InProcServer32", L"ThreadingModel", L"Apartment");
249+
// First we set the shell extension values.
250+
RegistryKey regKeyExtension(HKEY_LOCAL_MACHINE, ShellKey, KEY_READ | KEY_WRITE, true);
251+
regKeyExtension.SetStringValue(L"", L"Notepad++ Context menu");
252+
regKeyExtension.SetStringValue(L"ExplorerCommandHandler", guid);
253+
regKeyExtension.SetStringValue(L"NeverDefault", L"");
254+
255+
// Then we create the CLSID for the handler with it's values.
256+
RegistryKey regKeyClsid(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\" + guid, KEY_READ | KEY_WRITE, true);
257+
regKeyClsid.SetStringValue(L"", L"notepad++");
258+
259+
RegistryKey regKeyInProc = regKeyClsid.GetSubKey(L"InProcServer32", true);
260+
regKeyInProc.SetStringValue(L"", contextMenuFullName);
261+
regKeyInProc.SetStringValue(L"ThreadingModel", L"Apartment");
332262

333263
return S_OK;
334264
}
@@ -356,8 +286,11 @@ HRESULT NppShell::Installer::Install()
356286
{
357287
// We need to unregister the old menu on Windows 11 to prevent double entries in the old menu.
358288
UnregisterOldContextMenu();
289+
290+
// Since we are on Windows 11, we unregister the sparse package as well.
359291
UnregisterSparsePackage();
360292

293+
// And then we register it again.
361294
result = RegisterSparsePackage();
362295
}
363296

@@ -377,6 +310,7 @@ HRESULT NppShell::Installer::Install()
377310
MoveFileToTempAndScheduleDeletion(GetApplicationPath() + L"\\NppModernShell.dll", false);
378311
MoveFileToTempAndScheduleDeletion(GetApplicationPath() + L"\\NppModernShell.msix", false);
379312

313+
// Finally we notify the shell that we have made changes, so it refreshes the context menus.
380314
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
381315

382316
return result;
@@ -387,6 +321,8 @@ HRESULT NppShell::Installer::Uninstall()
387321
const bool isWindows11 = IsWindows11Installation();
388322

389323
HRESULT result;
324+
325+
// We remove the old context menu in all cases, since both Windows 11 and older versions can have it setup if upgrading.
390326
result = UnregisterOldContextMenu();
391327

392328
if (result != S_OK)
@@ -396,6 +332,7 @@ HRESULT NppShell::Installer::Uninstall()
396332

397333
if (isWindows11)
398334
{
335+
// Since we are on Windows 11, we unregister the sparse package as well.
399336
result = UnregisterSparsePackage();
400337

401338
if (result != S_OK)
@@ -404,15 +341,18 @@ HRESULT NppShell::Installer::Uninstall()
404341
}
405342
}
406343

344+
// Finally we notify the shell that we have made changes, so it refreshes the context menus.
407345
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
408346

409347
return S_OK;
410348
}
411349

412350
STDAPI CleanupDll()
413351
{
352+
// First we get the full path to this DLL.
414353
wstring currentFilePath(MAX_PATH, L'\0');
415354
GetModuleFileName(thisModule, &currentFilePath[0], MAX_PATH);
416355

356+
// Then we get it moved out of the way and scheduled for deletion.
417357
return MoveFileToTempAndScheduleDeletion(currentFilePath, true);
418358
}

NppShell.vcxproj

+2
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@
272272
<ClInclude Include="Installer.h" />
273273
<ClInclude Include="pch.h" />
274274
<ClInclude Include="SharedCounter.h" />
275+
<ClInclude Include="RegistryKey.h" />
275276
<ClInclude Include="SimpleFactory.h" />
276277
</ItemGroup>
277278
<ItemGroup>
@@ -292,6 +293,7 @@
292293
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
293294
</ClCompile>
294295
<ClCompile Include="SharedCounter.cpp" />
296+
<ClCompile Include="RegistryKey.cpp" />
295297
</ItemGroup>
296298
<ItemGroup>
297299
<None Include="packages.config" />

NppShell.vcxproj.filters

+9-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
<Filter Include="CommandHandlers\Implementation">
2020
<UniqueIdentifier>{fc167318-0574-47ba-aa80-a48008ef4b8c}</UniqueIdentifier>
2121
</Filter>
22+
<Filter Include="Registry">
23+
<UniqueIdentifier>{2de5b87c-2f6d-4a04-bd61-1e1be9a91fdf}</UniqueIdentifier>
24+
</Filter>
2225
</ItemGroup>
2326
<ItemGroup>
2427
<ClInclude Include="Installer.h">
@@ -48,6 +51,9 @@
4851
<ClInclude Include="ModernEditWithNppExplorerCommandHandler.h">
4952
<Filter>CommandHandlers\Implementation</Filter>
5053
</ClInclude>
54+
<ClInclude Include="RegistryKey.h">
55+
<Filter>Registry</Filter>
56+
</ClInclude>
5157
</ItemGroup>
5258
<ItemGroup>
5359
<ClCompile Include="Installer.cpp">
@@ -74,12 +80,12 @@
7480
<ClCompile Include="ModernEditWithNppExplorerCommandHandler.cpp">
7581
<Filter>CommandHandlers\Implementation</Filter>
7682
</ClCompile>
83+
<ClCompile Include="RegistryKey.cpp">
84+
<Filter>Registry</Filter>
85+
</ClCompile>
7786
</ItemGroup>
7887
<ItemGroup>
7988
<None Include="packages.config" />
8089
<None Include="source.def" />
8190
</ItemGroup>
82-
<ItemGroup>
83-
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
84-
</ItemGroup>
8591
</Project>

PathHelper.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ extern HMODULE thisModule;
88

99
const path GetThisModulePath()
1010
{
11-
wchar_t pathBuffer[FILENAME_MAX] = { 0 };
12-
GetModuleFileName(thisModule, pathBuffer, FILENAME_MAX);
11+
wchar_t pathBuffer[MAX_PATH] = { 0 };
12+
GetModuleFileNameW(thisModule, pathBuffer, MAX_PATH);
1313
return path(pathBuffer);
1414
}
1515

@@ -23,4 +23,10 @@ const wstring NppShell::Helpers::GetContextMenuPath()
2323
{
2424
path modulePath = GetThisModulePath();
2525
return modulePath.parent_path().wstring();
26+
}
27+
28+
const wstring NppShell::Helpers::GetContextMenuFullName()
29+
{
30+
path modulePath = GetThisModulePath();
31+
return modulePath.wstring();
2632
}

PathHelper.h

+1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ namespace NppShell::Helpers
77
{
88
const wstring GetApplicationPath();
99
const wstring GetContextMenuPath();
10+
const wstring GetContextMenuFullName();
1011
}

0 commit comments

Comments
 (0)