搜索Win32 LDAP API函数的引用,我找到了以下JwaWinLDAP.pas单元。
在此单元上,声明了函数ldap_search_st:
function ldap_search_st(ld: PLDAP; base: PAnsiChar; scope: ULONG;
filter, attrs: PAnsiChar; attrsonly: ULONG; var timeout: TLDAPTimeVal;
var res: PLDAPMessage): ULONG; cdecl;
超时: TLDAPTimeVal 参数声明为:
PLDAPTimeVal = ^TLDAPTimeVal;
l_timeval = packed record
tv_sec: Longint;
tv_usec: Longint;
end;
LDAP_TIMEVAL = l_timeval;
PLDAP_TIMEVAL = ^LDAP_TIMEVAL;
TLDAPTimeVal = l_timeval;
在代码中,如果我使用类似的东西:
procedure foo;
var
TimeVal: PLDAPTimeVal;
begin
ldap_search_st(foo1, Nil, 0, PAnsiChar('(objectClass=*)'), Nil, 0, TimeVal, foo2);
end;
编译器给我错误:
[dcc32错误]必须是实际和正式var参数的类型 相同
因为超时参数。如果我将TimeVal类型更改为 TLDAPTimeVal ,则会编译并且应用程序正常工作。
问题是: 当我在Delphi中看到类型声明时,它们总是如下:
type
PType1 = ^Type1
Type1 = record...
在引用的具体例子中,它可能是:
l_timeval = packed record
tv_sec: Longint;
tv_usec: Longint;
end;
TLDAPTimeVal = l_timeval;
它会以完全相同的方式工作(我认为)......为什么会对这种声明产生如此多的混淆?
答案 0 :(得分:7)
type
PType1 = ^Type1
Type1 = record...
上面的类型声明声明了两种类型 - 一种是记录,另一种是特定记录类型的类型指针。它们通常成对声明,因为它们是相关的。但是如果您或任何代码不需要类型指针,则不需要声明指针类型。
函数ldap_search_st
仅使用声明的记录类型。但是该单元中的一些其他函数期望指针作为参数。这就是声明同时具有的原因。
有问题的代码是Delphi的LDAP Windows API头文件翻译。 Windows API使用指针将结构传递给函数。
API翻译通常很复杂,有时候看似多余的声明。为了完整起见,翻译通常包含所有原始声明(符号) - 那些是l_timeval
,LDAP_TIMEVAL
和PLDAP_TIMEVAL
,虽然这些声明足以使用API,但还有两个声明,唯一目的是提供Delphi样式名称,以获得更加用户友好的体验PLDAPTimeVal
和TLDAPTimeVal
如果您查看原始LDAP函数声明,它们都使用指针来传递结构。例如:
ULONG ldap_search_st(
_In_ LDAP *ld,
_In_ PCHAR base,
_In_ ULONG scope,
_In_ PCHAR filter,
_In_ PCHAR attrs[],
_In_ ULONG attrsonly,
_In_ struct l_timeval *timeout,
_Out_ LDAPMessage **res
);
和
ULONG ldap_connect(
_In_ LDAP *ld,
_In_ LDAP_TIMEVAL *timeout
);
考虑到timeout
参数,这两者之间存在一个差异。
ldap_search_st
期望timeout
参数中的非空值 - 并且该参数的Delphi转换为var timeout: TLDAPTimeVal
以更清楚地匹配该意图 - 该声明可防止您意外传递null。虽然TLDAPTimeVal
不是指针类型,但使用var
关键字会使我们的timeout
参数表现得像一个。在幕后,Delphi会将指针传递给结构,并且与原始函数声明完全匹配。
另一方面,ldap_connect
timeout
可以包含空值。在这种情况下,将使用默认超时值。满足该要求的唯一方法是使用指针类型来超时结构。换句话说,PLDAPTimeVal
和该函数声明的Delphi翻译是
function ldap_connect(ld: PLDAP; timeout: PLDAPTimeval): ULONG;
答案 1 :(得分:0)
编码标准和约定的问题很多,因为LDAP声明被PSDK采用然后翻译成Delphi。另外,由于Pascal不允许在形式参数内使用指针类型声明(例如^Integer
)而不像普通C(例如int *
),因此相应的指针类型被添加到声明中。
在这里,我在声明中标记了各种约定,注意了套管和前缀的区别:
PLDAPTimeVal = ^TLDAPTimeVal; // Delphi pointer (Econos convention)
l_timeval = packed record // canonic structure (LDAP convention)
tv_sec: Longint;
tv_usec: Longint;
end;
LDAP_TIMEVAL = l_timeval; // Windows structure (PSDK convention)
PLDAP_TIMEVAL = ^LDAP_TIMEVAL; // Windows pointer (PSDK convention)
TLDAPTimeVal = l_timeval; // Delphi structure (Econos convention)
奇怪的是:Econos convention也强制要求Delphi指针的前向声明( 结构之前)。原始PSDK代码在结构之后声明指针。