Delphi 定义外部 WinAPI 函数的类型

Posted

技术标签:

【中文标题】Delphi 定义外部 WinAPI 函数的类型【英文标题】:Delphi define types of external WinAPI function 【发布时间】:2016-05-26 20:15:43 【问题描述】:

我试图在delphi中调用CreateProcessWithLogonW函数

我的第一次尝试如下

function CreateProcessWithLogonW(
  lpUsername,
  lpDomain,
  lpPassword: LPCWSTR;
  dwLogonFlags: DWORD;
  lpApplicationName: LPCWSTR;
  lpCommandLine: LPWSTR;
  dwCreationFlags: DWORD;
  lpEnvironment: Pointer;
  lpCurrentDirectory: LPCWSTR;
  lpStartupInfo: TStartupInfo;
  lpProcessInfo: TProcessInformation
  ): BOOL;
    stdcall; external 'Advapi32.dll';

我在我的程序中调用它后得到了 AV,我 googled 如何在 Delphi 中调用这个函数,我发现 lpStartupInfolpProcessInfo 必须定义如下

 var lpStartupInfo: TStartupInfo;
 var lpProcessInfo: TProcessInformation

函数按预期工作。

我的问题:如果函数参数在调用上述外部 WinAPI 函数时必须是可变的,我现在该怎么做。因为我没有在文档中找到有关此信息的信息。

【问题讨论】:

"如果函数参数必须是可变的,我现在怎么做" MSDN 文档很清楚。 struct args 作为结构的地址传递。你读过 C 吗? @theB 我的意思是var lpProcessInfo: TProcessInformationlpProcessInfo: TProcessInformation我如何知道正确的类型,也许我不知道如何表达我的问题或建模它,但是,因为我的母语是不是英语 这些参数必须是通过引用(这包括指针)。 按值传递是行不通的。 var lpProcessInfo: TProcessInformation - var-parameters 和 out-parameters 总是通过引用。 const-parameters 可能既是按值(像整数这样的小参数)也可以是按引用(较长的参数)。既不是 const 也不是 var/out 的参数必须由 Delphi 复制,以便函数可以在其中进行本地更改。因此最好避免它们:-) 【参考方案1】:

您的第一次尝试很接近但略有错误。正确的声明应该是这样的:

function CreateProcessWithLogonW(
  lpUsername,
  lpDomain,
  lpPassword: LPCWSTR;
  dwLogonFlags: DWORD;
  lpApplicationName: LPCWSTR;
  lpCommandLine: LPWSTR;
  dwCreationFlags: DWORD;
  lpEnvironment: Pointer;
  lpCurrentDirectory: LPCWSTR;
  lpStartupInfo: PStartupInfoW;
  lpProcessInfo: PProcessInformation
  ): BOOL;
    stdcall; external 'Advapi32.dll';

请注意,最后两个参数是指针(LP 表示 Win32 API 中的指针),因此您将声明非指针变量,然后使用 @ 运算符将它们的内存地址传递给参数:

var
  StartupInfo: TStartupInfoW;
  ProcessInfo: TProcessInformation;
begin
  CreateProcessWithLogonW(..., @StartupInfo, @ProcessInfo);
end;

但是,参数都是必需的,不能为 nil。在 Delphi 中,习惯1 将必需的指针参数声明为非指针var 参数:

function CreateProcessWithLogonW(
  lpUsername,
  lpDomain,
  lpPassword: LPCWSTR;
  dwLogonFlags: DWORD;
  lpApplicationName: LPCWSTR;
  lpCommandLine: LPWSTR;
  dwCreationFlags: DWORD;
  lpEnvironment: Pointer;
  lpCurrentDirectory: LPCWSTR;
  var lpStartupInfo: TStartupInfoW;
  var lpProcessInfo: TProcessInformation
  ): BOOL;
    stdcall; external 'Advapi32.dll';

...

var
  StartupInfo: TStartupInfoW;
  ProcessInfo: TProcessInformation;
begin
  CreateProcessWithLogonW(..., StartupInfo, ProcessInfo);
end;

不过,这只是一种方便。无论是通过指针还是通过引用传递变量,相同的内存地址仍然以任何方式传递给API。

1:Embarcadero 有一个坏习惯,即在 Win32 中将 optional 指针参数(那些 可以 为 nil 的参数)声明为 var <type> API 声明(而不是 P<type>^<type>)。这使得用户更难在他们想要的时候实际传递 nil 指针(尽管it can still be done,使用了一种尴尬的类型转换)。

【讨论】:

好吧,如果文档列出结构化参数是可选的 - 将其保留为指针,否则翻译为 byref。另一种可能性是添加重载版本。 @FreeConsulting:重载可能会变得丑陋,具体取决于涉及的参数数量以及其中有多少是可选的还是必需的。我更喜欢翻译成 API 中定义的实际类型(在这种情况下是指针),以维护 API 的预期语义,并简化跨语言翻译。 非常感谢,我想让您知道我一直以来多么重视您的支持。

以上是关于Delphi 定义外部 WinAPI 函数的类型的主要内容,如果未能解决你的问题,请参考以下文章

delphi中枚举类型和子界,数组,集合的详解以及类型说明

Delphi WinAPI WaitForSingleObject-等待函数-等待指定对象处于有信号状态或超时间隔结束。

Delphi类引用示例

delphi回调函数

6——在类的外部定义成员函数

关于VC++的Winmain函数(WINAPI是啥?)