3

我尝试设置默认从注册表安装路径:InnoSetup,扩大环境变量(使用{REG:...}从注册表值取)

DefaultDirName={reg:HKCU\Software\Microsoft\VisualStudio\14.0,VisualStudioLocation|{userdocs}\Visual Studio 2015} 

,我希望获得的目录路径注册表值数据,这是REG_EXPAND_SZ类型的值,那么我需要扩展它的变量,在我的情况下,reg值指向与我设置的默认值相同的路径,一旦{userdocs}常量被扩展为运行时间由InnoSetup,应该是这样的:

C:\用户\管理\文档\ Visual Studio的2015年

的而是说我得到这个为目录路径:

C:\用户\管理员\桌面\%USERPROFILE%\文件\ Visual Studio的 2015年

enter image description here

我执行从“C中的安装:\使用rs \ Administrator \ Desktop“的路径,所以这里似乎发生了两件事情,第一个是注册表值的路径刚刚追加,第二个是当然%USERPROFILE%变量没有扩展。

我该如何正确地做到这一点?

回答

1

我找不到任何使用Inno Setup源代码中的ExpandEnvironmentStrings函数,它指向一个事实(并纠正我,如果我错了),Inno安装程序无法扩展这样的路径(没有函数,也不是常数) ,或者有一个我不知道的API函数。当然,Inno Setup支持这样的文件名,因为它们被传递给可以在内部扩展它们的系统函数。似乎没有任何功能或常量可以在脚本中实现。我的建议是破解这样的:

[Setup] 
AppName=My Program 
AppVersion=1.5 
DefaultDirName={code:GetDefaultDirName} 

[Code] 
#ifdef UNICODE 
    #define AW "W" 
#else 
    #define AW "A" 
#endif 

const 
    RegKeyVS2015 = 'Software\Microsoft\VisualStudio\14.0'; 

function ExpandEnvironmentStrings(lpSrc: string; lpDst: string; nSize: DWORD): DWORD; 
    external 'ExpandEnvironmentStrings{#AW}@kernel32.dll stdcall'; 

function ExpandEnvVars(const Input: string): string; 
var 
    BufSize: DWORD; 
begin 
    BufSize := ExpandEnvironmentStrings(Input, #0, 0); 
    if BufSize > 0 then 
    begin 
    SetLength(Result, BufSize); 
    if ExpandEnvironmentStrings(Input, Result, Length(Result)) = 0 then 
     RaiseException(Format('Expanding env. strings failed. %s', [ 
     SysErrorMessage(DLLGetLastError)])); 
    end 
    else 
    RaiseException(Format('Expanding env. strings failed. %s', [ 
     SysErrorMessage(DLLGetLastError)])); 
end; 

function GetDefaultDirName(Param: string): string; 
begin 
    if RegQueryStringValue(HKCU, RegKeyVS2015, 'VisualStudioLocation', Result) then 
    Result := ExpandEnvVars(Result) 
    else 
    Result := ExpandConstant('{userdocs}\Visual Studio 2015'); 
end; 
+1

缓冲区长度在最后导致随机字符有一些主要问题。 – Tobias81

+0

确实,使用[回答@ Tobias81](http://stackoverflow.com/a/34069631/850848)修复了这个问题。 –

4

这里是我的ElektroStudios的解决方案的改进版本:

它负责正确的字符串终止的,不依赖于添加的0终止Win32函数(猜测在Pascal代码中使用它并不好)。

[Code] 
#ifdef UNICODE 
#define AW "W" 
#else 
#define AW "A" 
#endif 

function ExpandEnvironmentStrings(lpSrc: String; lpDst: String; nSize: DWORD): DWORD; 
external 'ExpandEnvironmentStrings{#AW}@kernel32.dll stdcall'; 

function ExpandEnvVars(const Input: String): String; 
var 
    Buf: String; 
    BufSize: DWORD; 
begin 
    BufSize := ExpandEnvironmentStrings(Input, #0, 0); 
    if BufSize > 0 then 
    begin 
    SetLength(Buf, BufSize); // The internal representation is probably +1 (0-termination) 
    if ExpandEnvironmentStrings(Input, Buf, BufSize) = 0 then 
     RaiseException(Format('Expanding env. strings failed. %s', [SysErrorMessage(DLLGetLastError)])); 
#if AW == "A" 
    Result := Copy(Buf, 1, BufSize - 2); 
#else 
    Result := Copy(Buf, 1, BufSize - 1); 
#endif 
    end 
    else 
    RaiseException(Format('Expanding env. strings failed. %s', [SysErrorMessage(DLLGetLastError)])); 
end; 
+0

你说得对,我的回答并没有解决问题,事实上,它甚至是最糟糕的。我一直想要改变它,但我没有时间。您发布的解决方案与我为自己写的内容非常相似。 – PLopes