Skip to content

Handle systems with multiple users #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
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
95 changes: 73 additions & 22 deletions Installer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ using namespace NppShell::Installer;
using namespace NppShell::Registry;

extern HMODULE thisModule;
extern thread ensureRegistrationThread;

const wstring SparsePackageName = L"NotepadPlusPlus";
constexpr int FirstWindows11BuildNumber = 22000;
Expand Down Expand Up @@ -178,6 +179,33 @@ void ResetAclPermissionsOnApplicationFolder()
aclHelper.ResetAcl(applicationPath);
}

Package GetSparsePackage()
{
PackageManager packageManager;
IIterable<Package> packages;

try
{
packages = packageManager.FindPackagesForUser(L"");
}
catch (winrt::hresult_error)
{
return NULL;
}

for (const Package& package : packages)
{
if (package.Id().Name() != SparsePackageName)
{
continue;
}

return package;
}

return NULL;
}

HRESULT NppShell::Installer::RegisterSparsePackage()
{
PackageManager packageManager;
Expand Down Expand Up @@ -207,32 +235,20 @@ HRESULT NppShell::Installer::UnregisterSparsePackage()
PackageManager packageManager;
IIterable<Package> packages;

try
Package package = GetSparsePackage();

if (package == NULL)
{
packages = packageManager.FindPackagesForUser(L"");
}
catch (winrt::hresult_error const& ex)
{
return ex.code();
return S_FALSE;
}

for (const Package& package : packages)
{
if (package.Id().Name() != SparsePackageName)
{
continue;
}

winrt::hstring fullName = package.Id().FullName();
auto deploymentOperation = packageManager.RemovePackageAsync(fullName, RemovalOptions::None);
auto deployResult = deploymentOperation.get();

if (!SUCCEEDED(deployResult.ExtendedErrorCode()))
{
return deployResult.ExtendedErrorCode();
}
winrt::hstring fullName = package.Id().FullName();
auto deploymentOperation = packageManager.RemovePackageAsync(fullName, RemovalOptions::None);
auto deployResult = deploymentOperation.get();

break;
if (!SUCCEEDED(deployResult.ExtendedErrorCode()))
{
return deployResult.ExtendedErrorCode();
}

// After unregistering the sparse package, we reset the folder permissions of the folder where we are installed.
Expand Down Expand Up @@ -347,6 +363,41 @@ HRESULT NppShell::Installer::Uninstall()
return S_OK;
}

void EnsureRegistrationOnCurrentUserWorker()
{
// Initialize the WinRT apartment.
winrt::init_apartment();

// Get the package to check if it is already installed for the current user.
Package existingPackage = GetSparsePackage();

if (existingPackage == NULL)
{
// The package is not installed for the current user - but we know that Notepad++ is.
// If it wasn't, this code wouldn't be running, so it is safe to just register the package.
RegisterSparsePackage();

// Finally we notify the shell that we have made changes, so it reloads the right click menu items.
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);
}
}

void NppShell::Installer::EnsureRegistrationOnCurrentUser()
{
// First we find the name of the process the DLL is being loaded into.
wstring moduleName = GetExecutingModuleName();

if (moduleName == L"explorer.exe")
{
// We are being loaded into explorer.exe, so we can continue.
// Explorer.exe only loads the DLL on the first time a user right-clicks a file
// after that it stays in memory for the rest of their session.
// Since we are here, we spawn a thread and call the EnsureRegistrationOnCurrentUserWorker function.
ensureRegistrationThread = thread(EnsureRegistrationOnCurrentUserWorker);
ensureRegistrationThread.detach();
}
}

STDAPI CleanupDll()
{
// First we get the full path to this DLL.
Expand Down
2 changes: 2 additions & 0 deletions Installer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace NppShell::Installer

HRESULT Install();
HRESULT Uninstall();

void EnsureRegistrationOnCurrentUser();
}

STDAPI CleanupDll();
12 changes: 12 additions & 0 deletions PathHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,16 @@ const wstring NppShell::Helpers::GetContextMenuFullName()
{
path modulePath = GetThisModulePath();
return modulePath.wstring();
}

const wstring NppShell::Helpers::GetExecutingModuleName()
{
wchar_t pathBuffer[FILENAME_MAX] = { 0 };
GetModuleFileNameW(NULL, pathBuffer, FILENAME_MAX);
PathStripPathW(pathBuffer);

wstring moduleName(pathBuffer);
transform(moduleName.begin(), moduleName.end(), moduleName.begin(), towlower);

return moduleName;
}
1 change: 1 addition & 0 deletions PathHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ namespace NppShell::Helpers
const wstring GetApplicationPath();
const wstring GetContextMenuPath();
const wstring GetContextMenuFullName();
const wstring GetExecutingModuleName();
}
2 changes: 2 additions & 0 deletions dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ using namespace NppShell::CommandHandlers;
using namespace NppShell::Factories;

HMODULE thisModule;
thread ensureRegistrationThread;

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
Expand All @@ -18,6 +19,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReser
{
case DLL_PROCESS_ATTACH:
thisModule = hModule;
NppShell::Installer::EnsureRegistrationOnCurrentUser();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
Expand Down