Inno Setup by default looks at the PrivilegesRequired setup variable, if this is set to admin or poweruser, the installer installs the
The PrivilegesRequired=none solution was not what I wanted. In some cases, it still prompts for elevation on administrator accounts and also the registry destination was still not reflective of the users selection.
Since I was already using a native helper DLL in my Inno Setup project, I coded this in C++ as I'm more comfortable there. I'm calling this method is called in CurStepChanged where CurPage=ssDoneInstall. Just call this method with the [Setup] AppId and whether or not the registry keys should be installed locally or not.
#include
extern "C" __declspec(dllexport)
bool DetectAndMoveRegKeyW(LPCWSTR app_id, bool install_local)
{
std::wstring s_app = app_id;
std::wstring path =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + s_app + L"_is1";
LPCWSTR c_path = path.c_str();
LRESULT res;
HKEY source = nullptr, subKey = nullptr;
// try to find source in HKLM
source = HKEY_LOCAL_MACHINE;
res = RegOpenKeyExW(source, c_path, 0, KEY_READ, &subKey);
if (subKey != nullptr)
RegCloseKey(subKey);
// try to find source in HKCU
if (res != ERROR_SUCCESS)
{
subKey = nullptr;
source = HKEY_CURRENT_USER;
res = RegOpenKeyExW(source, c_path, 0, KEY_READ, &subKey);
if (subKey != nullptr)
RegCloseKey(subKey);
}
if (res != ERROR_SUCCESS)
return false; // cant find the registry key
HKEY dest = install_local ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
if (source == dest)
return true; // registry already in the right place
// copy registry key to correct destination
HKEY hOldKey;
HKEY hNewKey;
bool bResult = false;
if (RegOpenKeyW(source, c_path, &hOldKey) == 0)
{
if (RegCreateKeyW(dest, c_path, &hNewKey) == 0)
{
bResult = (SHCopyKeyW(hOldKey, nullptr, hNewKey, 0) == 0);
RegCloseKey(hNewKey);
}
RegCloseKey(hOldKey);
if (bResult)
{
RegDeleteKeyW(source, c_path);
}
}
return bResult;
}
I'm exporting this method as cdecl instead of stdcall, this is because VC++ ignores the C extern and mangles method names anyways when using stdcall. You'll need to import this as cdecl in inno (see inno docs for this). Also, of course this is the Unicode-only implementation, if you require an Ansi version it should be simple enough.
IMPORTANT NOTICE:
This code is incomplete, it doesn't account for 64bit registry redirection. Inno-Setup completely ignores windows registry redirection and this code doesn't search the 64 bit registry at all since Inno and itself are running in 32bit.