2016-05-14 69 views
2

創新安裝默認着眼於PrivilegesRequired設置可變蜂巢,如果它被設置爲adminpoweruser,安裝程序安裝卸載註冊表鍵HKLM。如果這設置爲lowest,那麼它會將註冊表項安裝到HKCU指定註冊表卸載鍵位置/通過[代碼]

我有一個要求,爲用戶提供一個選項來安裝「只是我」或「大家」,並通過用這兩個選項的無線電選擇替換目錄選擇頁面來完成。我現在需要做的還是根據此設置修改註冊表安裝位置。如果我將應用程序安裝到本地用戶應用程序數據中,則在HKLM級別註冊卸載數據將毫無意義,因爲其他用戶將在程序列表中看到它,但仍然無法卸載或使用它。

編輯:通過文檔和Install.pas源看後,我發現CreateUninstallRegKey設置指令,它會從安裝註冊表項的所有,在此之後,我可以添加自己的註冊表項禁用的Inno,但是這是真的是唯一的方法?

編輯#2(標記爲一式兩份):我在這個Conditional Elevation問題已經採取一看(實際上是實現了它),這不是我的一樣。當前的高程狀態確實是而不是 alter Inno Setup實際上保存了卸載註冊表信息(在HKCU或HKLM中)。如果你看看Inno source code (Install.pas #507),你會發現PrivilegesRequired指令是存儲註冊表的主要因素。如果設置爲lowest,安裝程序是否升級無關緊要 - 當所需的行爲是基於用戶安裝首選項而不是當前標高狀態選擇一個或另一個時,它會將註冊表項安裝到HKCU 。因此,所有這一切,我正在尋找一種解決方案,以基於代碼變量來更改註冊表根目錄,而不管當前的PrivilegesRequired或Elevation設置如何。

回答

1

PrivilegesRequired=none溶液不是我想要的。在某些情況下,它仍會提示管理員帳戶提升,而註冊管理機構目標仍不能反映用戶的選擇。

因爲我在Inno Setup項目中已經使用了本地幫助器DLL,所以我用C++編寫了這個代碼,因爲我在那裏更加舒適。我打電話給這個方法叫做CurStepChanged,其中CurPage=ssDoneInstall。只需使用[Setup]AppId以及是否應該在本地安裝註冊表項來調用此方法。

#include <shlwapi.h> 
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; 
} 

我出口這種方法cdecl代替stdcall,這是因爲VC++忽略的C extern和使用stdcall時反正軋液的方法名。您需要將其導入爲cdecl in inno (see inno docs for this)。另外,當然這是僅有Unicode的實現,如果您需要Ansi版本,它應該足夠簡單。

重要提示:
此代碼是不完整的,它沒有考慮到64位註冊表重定向。 Inno-Setup完全忽略了Windows註冊表重定向,並且此代碼根本不搜索64位註冊表,因爲Inno和它本身都在32位版本中運行。

2

正如你發現自己,邏輯是硬編碼的。你無法真正控制。

最接近你可以得到的是通過使用無證件(不贊成)PrivilegesRequired=none

有了這個值(與安裝,自動檢測的在Windows幫助):

這不完全是你想要的,但我認爲你不能接近。


你當然也可以複製(移動)由代碼HKCUHKLM自己的註冊表項:

function MoveHKCUUninstallKeyToHKLM: Boolean; 
var 
    UninstallKey: string; 
    AppId: string; 
    I: Integer; 
    ValueNames: TArrayOfString; 
    ValueName: string; 
    ValueStr: string; 
    ValueDWord: Cardinal; 
begin 
    if '{#emit SetupSetting("AppId")}' <> '' then 
    begin 
    AppId := '{#emit SetupSetting("AppId")}'; 
    end 
    else 
    begin 
    AppId := '{#emit SetupSetting("AppName")}'; 
    end; 

    Result := False; 
    if AppId = '' then 
    begin 
    Log('Cannot identify AppId'); 
    end 
    else 
    begin 
    UninstallKey := 
     'Software\Microsoft\Windows\CurrentVersion\Uninstall\' + AppId + '_is1'; 
    Log(Format(
     'AppId identified as "%s", using uninstall key "%s"', [AppId, UninstallKey])); 
    if not RegKeyExists(HKEY_CURRENT_USER, UninstallKey) then 
    begin 
     Log('HKCU uninstall key not found'); 
    end 
     else 
    if RegKeyExists(HKEY_LOCAL_MACHINE, UninstallKey) then 
    begin 
     Log('HKLM uninstall key exists already'); 
    end 
     else 
    begin 
     Log('HKCU uninstall key found and HKLM key not exists yet'); 

     if not RegGetValueNames(HKEY_CURRENT_USER, UninstallKey, ValueNames) then 
     begin 
     Log('Cannot list uninstall key values'); 
     end 
     else 
     begin 
     I := 0; 
     Result := True; 
     while (I < GetArrayLength(ValueNames)) and Result do 
     begin 
      ValueName := ValueNames[I]; 
      if RegQueryStringValue(HKEY_CURRENT_USER, UninstallKey, ValueName, ValueStr) then 
      begin 
      if not RegWriteStringValue(
        HKEY_LOCAL_MACHINE, UninstallKey, ValueName, ValueStr) then 
      begin 
       Log(Format('Error moving "%s" string value', [ValueName])); 
       Result := False; 
      end 
       else 
      begin 
       Log(Format('Moved "%s" string value', [ValueName])); 
      end; 
      end 
      else 
      if RegQueryDWordValue(
       HKEY_CURRENT_USER, UninstallKey, ValueName, ValueDWord) then 
      begin 
      if not RegWriteDWordValue(
        HKEY_LOCAL_MACHINE, UninstallKey, ValueName, ValueDWord) then 
      begin 
       Log(Format('Error moving "%s" dword value', [ValueName])); 
       Result := False; 
      end 
       else 
      begin 
       Log(Format('Moved "%s" dword value', [ValueName])); 
      end; 
      end 
      else 
      begin 
      { All uninstall values written by Inno Setup are either string or dword } 
      Log(Format('Value "%s" is neither string nor dword', [ValueName])); 
      Result := False; 
      end; 
      Inc(I); 
     end; 

     if Result then 
     begin 
      if not RegDeleteKeyIncludingSubkeys(HKEY_CURRENT_USER, UninstallKey) then 
      begin 
      Log('Error removing HKCU uninstall key'); 
      Result := False; 
      end 
      else 
      begin 
      Log('Removed HKCU uninstall key'); 
      end; 
     end; 

     if not Result then 
     begin 
      if not RegDeleteKeyIncludingSubkeys(HKEY_CURRENT_USER, UninstallKey) then 
      begin 
      Log('Failed to move uninstall key to HKLM, ' + 
       'and also failed to rollback the changes'); 
      end 
      else 
      begin 
      Log('Failed to move uninstall key to HKLM, rolled back the changes'); 
      end; 
     end; 
     end; 
    end; 
    end; 
end; 

procedure CurStepChanged(CurStep: TSetupStep); 
begin 
    if CurStep = ssPostInstall then 
    begin 
    Log('Post install'); 
    MoveHKCUUninstallKeyToHKLM; 
    end; 
end; 
+0

你當然是對的。我想我必須自己重新執行註冊表編寫工作,我沒有想過簡單地將它們複製到正確的位置。感謝您指出我正確的方向,並看到我的答案,我是如何做到的! – caesay

+0

查看我編輯的原生Inno Setup解決方案的答案。 –

+0

我沒有測試,但看起來不錯。我已經將註冊表內容與我的本地解決方案集成在一起,並針對安裝的應用程序是x64還是x86進行了編碼檢測,將鍵放入正確的視圖中(我的解決方案也忽略了此問題)。無論如何,謝謝你!這兩個答案對於將來找到這個問題的任何人都是有價值的。 – caesay