Installation InnoSetup,展开环境变量(使用{reg:…}从注册表值中获取)

Installation InnoSetup,展开环境变量(使用{reg:…}从注册表值中获取),installation,registry,environment-variables,inno-setup,pascalscript,Installation,Registry,Environment Variables,Inno Setup,Pascalscript,我尝试从注册表设置默认安装路径: DefaultDirName={reg:HKCU\Software\Microsoft\VisualStudio\14.0,VisualStudioLocation|{userdocs}\Visual Studio 2015} 我希望获得的目录路径是注册表值数据,这是一个类型为REG_EXPAND_SZ的值,然后我需要扩展它的变量,在我的例子中,REG值指向与我设置的默认值相同的路径,一旦InnoSetup在运行时扩展了{userdocs}常量,应该是这样的:

我尝试从注册表设置默认安装路径:

DefaultDirName={reg:HKCU\Software\Microsoft\VisualStudio\14.0,VisualStudioLocation|{userdocs}\Visual Studio 2015}
我希望获得的目录路径是注册表值数据,这是一个类型为
REG_EXPAND_SZ
的值,然后我需要扩展它的变量,在我的例子中,REG值指向与我设置的默认值相同的路径,一旦InnoSetup在运行时扩展了
{userdocs}
常量,应该是这样的:

C:\Users\Administrator\Documents\Visual Studio 2015

但我得到的不是这个,而是目录路径:

C:\Users\Administrator\Desktop\%USERPROFILE%\Documents\Visual Studio 2015年

我从“C:\Users\Administrator\Desktop”路径执行安装程序,因此这里似乎发生了两件事,第一件事是注册表值的路径只是附加的,第二件事当然是
%USERPROFILE%
变量没有展开


我怎样才能正确地做到这一点?

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

[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;

以下是我对ElektroStudios解决方案的改进版本:

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

[代码]
#ifdef UNICODE
#定义AW“W”
#否则
#定义“A”
#恩迪夫
函数ExpandEnvironmentStrings(lpSrc:String;lpDst:String;nSize:DWORD):DWORD;
外部“ExpandEnvironmentStrings{#AW}@kernel32.dll stdcall”;
函数ExpandEnvVars(常量输入:String):String;
变量
Buf:字符串;
BufSize:DWORD;
开始
BufSize:=ExpandEnvironmentStrings(输入,#0,0);
如果BufSize>0,则
开始
设置长度(Buf,BufSize);//内部表示可能是+1(0-终止)
如果ExpandEnvironmentString(输入、Buf、BufSize)=0,则
RaiseException(格式('扩展环境字符串失败。%s',[SysErrorMessage(DLLGetLastError)]);
#如果AW==“A”
结果:=拷贝(Buf,1,BufSize-2);
#否则
结果:=拷贝(Buf,1,BufSize-1);
#恩迪夫
结束
其他的
RaiseException(格式('扩展环境字符串失败。%s',[SysErrorMessage(DLLGetLastError)]);
结束;

缓冲区长度存在一些主要问题,导致结尾出现随机字符。是的,请使用解决问题的。您是对的,我的回答没有解决问题,事实上,它甚至使问题变得更糟。我一直想改变它,但我就是没有时间。你发布的解决方案与我自己写的非常相似。