Winapi 如何在Inno安装程序中使用GetVolumeInformation?

Winapi 如何在Inno安装程序中使用GetVolumeInformation?,winapi,installation,inno-setup,pascalscript,Winapi,Installation,Inno Setup,Pascalscript,在使用Inno Setup创建的安装过程中,我需要获取驱动器号的卷序列号。我知道DLL函数可以导入Inno,但我对它还比较陌生,在让它工作时遇到了一些问题。我知道内核32中的GetVolumeInformation函数可以满足我的需要。有人能告诉我如何在Inno脚本中导入和使用该功能来检索卷序列号吗 谢谢 由于不支持指针,因此必须为函数调用创建外部库。以下代码示例适用于Delphi和InnoSetup的所有组合(从Unicode支持的角度来看) 以下是Delphi库代码: library Vol

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

谢谢

由于不支持指针,因此必须为函数调用创建外部库。以下代码示例适用于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;
Inno设置代码::

[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安装程序版本5.2.3进行测试

在Inno Setup的Unicode版本中将
PChar
替换为
PAnsiChar

中,我尝试过与之非常相似的方法,事实上,我看过了同一篇delphi文章,试图让它发挥作用。但我总是出错。使用您提供的代码,我在函数导入中得到“未知类型:PDWORD”。如果我将其更改为其他内容,它将继续执行,直到它达到@VolumeSerialNumber时我得到“未知标识符VolumeSerialNumber”。我试图删除“@”只是为了看看会发生什么,它一直编译到调用GetVolumeInformation(),在函数调用结束时收到一个“类型不匹配”错误。有什么想法吗?@TLama,您可以通过引用(“指针”)传递变量。只需将参数声明为
var lpVolumeSerialNumber:DWORD
等。无需在调用者中指定
@
。另一个问题是将
nil
传递给函数。这可以通过装入
PChar
变量(如
\u NIL
)并为其赋值
\0
来实现
HiWord
LoWord
是简单的宏。我一直使用
IntToHex
:),但是我能够在Inno中实现您的初始代码并获得序列号。但是,我认为将助手函数保留在单独的DLL中的最终解决方案要好得多+1看起来像更新版本的Inno支持
IntToHex
,但它也很容易实现:)@kobik,关于
lpVolumeSerialNumber
声明的观点很好。关于
IntToHex
我不确定(即使ReObject的引用也没有提到它)。然而,我认为OP正在进行一些注册过程,因为我不知道获取卷序列号的任何合理原因,所以我认为该库在其他方面也可能有用。但是发布您所拥有的,也许您的解决方案更适合OP;)@TLama感谢您的输入,无需道歉!我总是感激每个人的帮助,即使不是100%正确。至少我们都可以通过这种方式学到一些东西!根据您最新的示例,我仍然对将函数导入Inno感到有些困惑。我是否必须编译DLL来存储Inno的外部函数?或者一个更好的问题是我怎么做?这听起来是一个好主意,供将来参考,但我希望只使用本机Windows DLL进行函数导入。非常感谢你的帮助!再三感谢你。原谅我是个白痴,但我该怎么解释呢?例如,我的C驱动器在命令提示符下标记为449D-0C30,但当我运行您的Inno代码时,msgbox显示为17565-3120。我知道我的思路是正确的,但我对将函数导入Inno还不熟悉!非常感谢你的帮助!我已经有好几个人给了我可靠的建议。我是新来的,我该如何表扬他们的贡献呢?