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 中调用这个函数,我发现 lpStartupInfo
和 lpProcessInfo
必须定义如下
var lpStartupInfo: TStartupInfo;
var lpProcessInfo: TProcessInformation
函数按预期工作。
我的问题:如果函数参数在调用上述外部 WinAPI 函数时必须是可变的,我现在该怎么做。因为我没有在文档中找到有关此信息的信息。
【问题讨论】:
"如果函数参数必须是可变的,我现在怎么做" MSDN 文档很清楚。 struct args 作为结构的地址传递。你读过 C 吗? @theB 我的意思是var lpProcessInfo: TProcessInformation
或lpProcessInfo: 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 WinAPI WaitForSingleObject-等待函数-等待指定对象处于有信号状态或超时间隔结束。