【问题标题】:How can I use GetVolumeInformation in Inno Setup?如何在 Inno Setup 中使用 GetVolumeInformation?
【发布时间】:2012-02-14 05:48:56
【问题描述】:

在使用 Inno Setup 创建的安装过程中,我需要获取驱动器号的卷序列号。我知道 DLL 函数可以导入 Inno,但我对它还很陌生,并且在让它工作时遇到了一些问题。我知道 kernel32 中的 GetVolumeInformation 函数可以满足我的需要。有人可以告诉我如何在 Inno 脚本中导入和使用该功能来检索卷序列号吗?

谢谢!

【问题讨论】:

    标签: winapi installation inno-setup pascalscript


    【解决方案1】:

    Inno-Setup 代码::

    [Code]
    function GetVolumeInformation(
      lpRootPathName: PChar;
      lpVolumeNameBuffer: PChar;
      nVolumeNameSize: DWORD;
      var lpVolumeSerialNumber: DWORD;
      var lpMaximumComponentLength: DWORD;
      var lpFileSystemFlags: DWORD;
      lpFileSystemNameBuffer: PChar;
      nFileSystemNameSize: DWORD
      ): BOOL;
      external 'GetVolumeInformationA@kernel32.dll stdcall';
    
    
    function LoWord(dw: DWORD): WORD;
    begin
      Result := WORD(dw);
    end;
    
    function HiWord(dw: DWORD): WORD;
    begin
      Result := WORD((dw shr 16) and $FFFF);
    end;
    
    function WordToHex(w: WORD): string;
    begin
      Result := Format('%.4x', [w]);
    end;
    
    function FindVolumeSerial(const Drive: string): string;
    var
      FileSystemFlags: DWORD;
      VolumeSerialNumber: DWORD;
      MaximumComponentLength: DWORD;
    begin
      Result := '';
      // Note on passing PChars using RemObjects Pascal Script:
      // '' pass a nil PChar  
      // #0 pass an empty PChar    
      if GetVolumeInformation(
        PChar(Drive), 
        '', // nil
        0,
        VolumeSerialNumber,
        MaximumComponentLength,
        FileSystemFlags,
        '', // nil
        0)
      then
        Result := WordToHex(HiWord(VolumeSerialNumber)) + '-' + WordToHex(LoWord(VolumeSerialNumber));
    end;
    
    function InitializeSetup(): Boolean;
    begin
      MsgBox(FindVolumeSerial('c:\'), mbInformation, mb_Ok);
    end;
    

    使用 Inno-setup 版本 5.2.3 测试
    在 Inno-Setup 的 Unicode 版本中,将 PChar 替换为 PAnsiChar

    【讨论】:

    • 再次感谢您。原谅我是个白痴,但我该如何解释呢?例如,我的 C 盘在命令提示符下标记为 449D-0C30,但是当我运行您的 Inno 代码时,msgbox 显示 17565-3120。我知道我走在正确的轨道上,但我对将函数导入 Inno 很陌生!非常感谢您的帮助!
    • 我有几个人提供了可靠的建议。我是新的堆栈,那么我该如何赞扬他们的贡献?
    【解决方案2】:

    由于InnoSetup 不支持指针,您必须为调用GetVolumeInformation 函数创建外部库。以下代码示例应该适用于 Delphi 和 InnoSetup 的所有组合(从 Unicode 支持的角度来看)。

    这是 Delphi 库代码:

    library VolumeInformation;
    
    uses
      Types, Classes, SysUtils, Windows;
    
    var
      SerialNumber: AnsiString;
    
    function GetVolumeSerial(Drive: PAnsiChar): PAnsiChar; stdcall;
    var
      FileSystemFlags: DWORD;
      VolumeSerialNumber: DWORD;
      MaximumComponentLength: DWORD;
    begin
      SerialNumber := '';
      GetVolumeInformationA(Drive, nil, 0, @VolumeSerialNumber,
        MaximumComponentLength, FileSystemFlags, nil, 0);
      SerialNumber := IntToHex(HiWord(VolumeSerialNumber), 4) + ' - ' +
        IntToHex(LoWord(VolumeSerialNumber), 4);
      Result := PAnsiChar(SerialNumber);
    end;
    
    exports
      GetVolumeSerial;
    
    end.
    

    这是 InnoSetup 代码:

    [Files]
    Source: "VolumeInformation.dll"; Flags: dontcopy
    
    [Code]
    
    function GetVolumeSerial(Drive: PAnsiChar): PAnsiChar;
      external 'GetVolumeSerial@files:VolumeInformation.dll stdcall setuponly';
    
    procedure ButtonOnClick(Sender: TObject);
    var
      S: string;
    begin
      S := GetVolumeSerial('c:\');
      MsgBox(S, mbInformation, mb_Ok);
    end;
    

    【讨论】:

    • 我已经尝试过与那些非常相似的事情,事实上我查看了同一篇 delphi 文章试图让它工作。但我不断收到错误。使用您提供的代码,我在函数导入中得到“未知类型:PDWORD”。如果我将其更改为其他内容,它会进一步遵守,直到当它到达@VolumeSerialNumber 时我得到“未知标识符 VolumeSerialNumber”。我尝试删除“@”只是为了看看会发生什么,它一直编译到对 GetVolumeInformation() 的调用,并且在函数调用结束时收到“类型不匹配”错误。有什么想法吗?
    • @TLama,您可以通过引用(“指针”)传递变量。您只需将参数声明为var lpVolumeSerialNumber: DWORD 等。无需在调用者中指定@。另一个问题是将nil 传递给函数。这可以通过创建PChar 变量(例如_NIL)并将#0 分配给它来完成。 HiWordLoWord 是简单的宏。我被IntToHex 卡住了 :) 但我能够在 Inno 中实现你的初始代码并获得序列号。但是,我认为将辅助函数保存在单独的 DLL 中的最终解决方案要好得多! +1
    • 似乎新版本的 Inno 支持IntToHex,但也很容易实现:)
    • @kobik,关于lpVolumeSerialNumber 声明的要点。关于IntToHex 我不确定(即使是 RemObject 的参考资料也没有说明)。但是我认为 OP 正在进行一些注册过程,因为我不知道获取卷序列号的任何合理原因,所以我认为该库可能对其他目的也有用。但是发布你所拥有的,也许你的解决方案更适合 OP ;)
    • @TLama 感谢您的意见,无需道歉!我总是感谢大家的帮助,即使它不是 100% 正确的。至少我们都可以通过这种方式学到一些东西!根据您的最新示例,我仍然对将函数导入 Inno 感到有些困惑。我是否必须编译一个 DLL 来存储 Inno 的外部函数?或者更好的问题是我该怎么做?这听起来是个不错的主意以供将来参考,但我希望简单地使用本机 Windows DLL 进行函数导入。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2011-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-16
    • 1970-01-01
    相关资源
    最近更新 更多