Delphi Xe4。例如,有两个函数(Unicode):
CryptAcquireContext,CryptGetProvParam。
我在MSDN上阅读说明:
1)http://msdn.microsoft.com/en-us/library/windows/desktop/aa379886(v=vs.85).aspx
BOOL WINAPI CryptAcquireContext(
_Out_ HCRYPTPROV *phProv,
_In_ LPCTSTR pszContainer,
_In_ LPCTSTR pszProvider,
_In_ DWORD dwProvType,
_In_ DWORD dwFlags);
2)http://msdn.microsoft.com/en-us/library/windows/desktop/aa379929(v=vs.85).aspx
BOOL WINAPI CryptEnumProviders(
_In_ DWORD dwIndex,
_In_ DWORD *pdwReserved,
_In_ DWORD dwFlags,
_Out_ DWORD *pdwProvType,
_Out_ LPTSTR pszProvName,
_Inout_ DWORD *pcbProvName);
如果我理解正确,那么翻译成Delphi应该是这样的:
{S} Function CryptAcquireContext(Out hpProv:PNativeUInt;Const Container:PWideChar;
Const Provider:PWideChar;Const ProvType:DWord;Const Flags:DWord):Bool; StdCall; External Advapi32dll Name 'CryptAcquireContextW';
{S} Function CryptEnumProviders(Const Index:DWord;Const Reserved:PDWord;Const Flags:DWord;
Out ProvType:PDWord;Out pszProvName:DWord;Var pcbProvName:DWord):Bool; StdCall; External Advapi32dll Name 'CryptEnumProvidersW';
主要对返回参数参数感兴趣,标有“OUT”和“VAR”( Out , InOut )。 因此,我不会使用interente中的各种示例。例如电话:
Procedure Test;
var hProv:NativeUInt;provName: array[0..200] of char;dwProvType: DWORD;
begin
...
if not CryptAcquireContext(@hProv, nil, provName, dwProvType,CRYPT_VERIFYCONTEXT) then RaiseLastOSError;
...
while CryptEnumProviders(i, nil, 0,@dwProvType, nil, @cbName)) do
begin
..
end;
给出编译错误:“E2033实际和正式var参数的类型必须相同” - 指的是@ hProv和@dwProvType。如果您想在VAR上替换OUT并在PDword(dwProvType)上替换文本@dwProvType,则会出现错误:“E2197常量对象不能作为var参数传递”。
如果我没有指定输入和输出参数(像这样 - http://www.bvbcode.com/code/oyma7f3h-1618784,字符串№692),一切都编译,运行并正常工作(Const - 无效):< / p>
{S} Function CryptAcquireContext(hpProv:PNativeUInt;Container:PWideChar;Provider:PWideChar;ProvType:DWord;Flags:DWord):Bool; StdCall; External Advapi32dll Name 'CryptAcquireContextW';
{S} Function CryptEnumProviders(Index:DWord;Reserved:PDWord;Flags:DWord;ProvType:PDWord;pszProvName:PWideChar;pcbProvName:PDWord):Bool; StdCall; External Advapi32dll Name 'CryptEnumProvidersW';
过去,我建议采用JEDI API函数值的问题。我下载了最新版本的(http://sourceforge.net/projects/jedi-apilib/),我看到了(单位JwaWinCrypt):
function CryptAcquireContext(var phProv: HCRYPTPROV; pszContainer: LPCTSTR;
pszProvider: LPCTSTR; dwProvType: DWORD; dwFlags: DWORD): BOOL; stdcall;
function CryptEnumProviders(dwIndex: DWORD; pdwReserved: LPDWORD; dwFlags: DWORD;
var pdwProvType: DWORD; pszProvName: LPTSTR; var pcbProvName: DWORD): BOOL; stdcall;
相反,调用“OUT”和“INOUT”的值写“VAR”。但是这些我的例子都不行。和DWORD类型的pdwProvType和pcbProvName,虽然描述是DWORD * = PDWORD?
问题:
1)如何正确行事。 MSDN OUT = Delphi OUT还是VAR? IN_OUT = Delphi VAR?或者他们没有指定?
2)我需要写Const吗? IN = Delphi Const?
3)带指针的类型。 DWORD = Delphi Dword。好。 DWORD * = Delphi PDWROD(或所有标记的* = Delphi指针类型)?
P.S。抱歉英语不好。
答案 0 :(得分:6)
为HCRYPTPROV声明一个类型:
type
HCRYPTPROV = NativeUInt;
然后声明函数:
function CryptAcquireContext(
out hpProv: HCRYPTPROV;
Container: PWideChar;
Provider: PWideChar;
ProvType: DWORD;
Flags: DWORD
):BOOL; stdcall; external Advapi32dll name 'CryptAcquireContextW';
function CryptEnumProviders(
Index: DWORD;
Reserved: PDWORD;
Flags: DWORD;
out ProvType: DWORD;
pszProvName: PWideChar;
var pcbProvName: DWORD
):BOOL; stdcall; external Advapi32dll name 'CryptEnumProvidersW';
请注意,var和out参数作为指向实际参数的指针传递。所以在你的代码中你会有太多的间接。
在我的翻译中,我采用了以下政策:
答案 1 :(得分:4)
AS。下面的函数声明不正确。它只是从问题正文中逐字复制,以演示编译错误背后的逻辑。
给出编译错误:“E2033实际和正式var参数的类型必须相同” - 指的是@hProv和@dwProvType。
这是正确的。函数(声明它)返回一个指针,而不是一个整数。你的代码是
var hProv:NativeUInt;
const pProv = @hProv;
if not CryptAcquireContext(pProv,...
var dwProvType: DWORD;
const pPropType = @dwPropType;
while CryptEnumProviders(... @dwProvType, ...
但是函数不能将值写入常量。正确的代码应该是
var hProv: NativeUInt;
VAR pProv: PNativeUInt;
pProv := @hProv; (** see remarks **)
if not CryptAcquireContext(pProv,...
var dwProvType: DWORD;
VAR pPropType: ^DWORD;
pPropType := @dwPropType; (** see remarks **)
while CryptEnumProviders(... @dwProvType, ...
嗯......实际上。由于这些参数只是OUT,因此您不必为它们赋值 - 应省略那些标记的行。我把它们只是为了突出变量和常量之间的区别;因此,hProv
和dwProvType
也会被删除 - 它们不会被使用。
1)如何正确行事。 MSDN OUT = Delphi OUT或VAR?
德尔福对OUT的支持不足。除了IUnknown
之类的一些狭隘案例外,Delphi将其视为VAR的synonim。
如果你是来自C ++领域,那么VAR参数就像int Name(int& var; char& Var);
然而 - 正如David Heffernan指出的那样 - 对于C ++,_In_
和_Out_
只是意图的文档,它们不会影响编译代码。实际上,CryptAcquireContext
的第一个参数的声明应该是读取的 - 取决于你的首选项/*Out*/ HCRYPTPROV *phProv
或/*Out*/ HCRYPTPROV &hProv
,它们在Delphi中分别对应const phProv: PNativeUInt
或{{1} }。根据您的心情,您可以将(按值,常量)指针传递给结果的容器,或者传递(by-ref,volatile)容器本身。二进制这些选项是相同的。
我相信out hProv: PNativeUInt
和FPC H2Pas
会给出正确的声明,而不会像我一样错过错误。
2)我需要写Const吗? IN = Delphi Const?
恕我直言:你最好做 - 自我记录代码。然而,事情是关于在给定代码约定中传递不同值的二进制兼容性。我不认为CONST(或它的缺席)会成为确保正确传输任何数据类型的灵丹妙药。总的来说 - 我认为这是个人品味和自律的问题。
3)带指针的类型。 DWORD = Delphi Dword。好。 DWORD * = Delphi PDWROD(或所有标记的* = Delphi指针类型)?
默认情况下,Delphi从Pascal继承了“每个指针都是无类型”的概念。对我来说,破坏了Pascal的类型安全性,在我的项目中,我在选项中检查Jedi API Lib
- 或者将pragma Typed Pointers
放入源代码中。
因此,根据编译器设置{$T+}
可能是DWORD*
或Pointer
; ^DWORD
类型只是PDWORD
的命名别名(C ++:typedef
)。