2

德尔福 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”(OutInOut)标记。因此,我不会处理在 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 Types of actual andformal var parameters must be same”——指@hProv和@dwProvType。如果您想在 VAR 上替换 OUT 并在 PDword(dwProvType) 上替换文本 @dwProvType,则会出现错误:“E2197 常量对象不能作为 var 参数传递”。

如果我没有指定输入和输出参数(像这样 - http://www.bvbcode.com/code/oyma7f3h-1618784,字符串№692),一切都会编译,运行和工作正常(Const - 无效):

{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”。但是我的这些例子不能正常工作。而pdwProvType和pcbProvName都是DWORD类型,虽然描述是DWORD * = PDWORD?

问题:

1)如何正确地做。MSDN OUT = Delphi OUT 还是 VAR?IN_OUT = 德尔福 VAR?或者他们没有指定?

2)我需要写常量吗?IN = 德尔福常数?

3) 带指针的类型。DWORD = 德尔福双字。好的。DWORD* = Delphi PDWROD(或所​​有标记 * = Delphi 指针类型)?

ps对不起英语不好。

4

2 回答 2

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 参数作为指向实际参数的指针传递。所以在你的代码中你会有太多的间接性。

在我的翻译中,我采用了以下政策:

  • 值参数不使用 const。外部声明似乎没有什么好处。
  • 指针参数由 var 或 out 优先传递。对于像这样的简单类型,out 和 var 具有相同的实现,使用其中之一的唯一原因是记录参数语义。
  • 可选的指针参数被声明为允许调用者传递 nil 的指针。
于 2013-07-16T10:13:09.273 回答
4

作为。下面的非常函数声明是不正确的。它只是从问题正文中逐字复制以演示编译错误背后的逻辑。

给出编译错误:“E2033 Types of actual andformal var parameters must be same”——指@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-only,所以您不必为它们分配值 - 那些标记的行应该被省略。我放它们只是为了突出变量和常量之间的区别;因此hProv并且dwProvType也将被删除 - 它们不被使用。


1)如何正确地做。MSDN OUT = Delphi OUT 还是 VAR?

Delphi 对 OUT 的支持很差。除了像IUnknownDelphi 这样的狭义情况外,将 OUT 作为 VAR 的同义词。

  • 就我个人而言,我认为您应该指定 OUT - 仅用于自我记录的代码。
  • 其他人则认为在 Delphi 中使用 OUT 而不是 VAR 只是在自欺欺人。

如果您来自 C++ 领域,那么 VAR 参数是 C++ 引用类型的直接模拟,例如int Name(int& var; char& Var);

然而——正如 David Heffernan 指出的那样——对于 C++ 来说_In_,这些_Out_仅仅是意图的文档,它们不会影响编译的代码。因此,实际上第一个参数 to 的声明CryptAcquireContext应该读取 - 取决于您的偏好, /*Out*/ HCRYPTPROV *phProv或者/*Out*/ HCRYPTPROV &hProv在 Delphi 中将分别对应于const phProv: PNativeUIntor out hProv: PNativeUInt。根据您的心情,您可以将 (by-value, constant) 指针传递给结果的容器,或者传递 (by-ref, volatile) 容器本身。二进制那些选项是一样的。

我相信FPC H2Pas并且Jedi API Lib会给出正确的声明,不会像我一样错过错误。

2)我需要写常量吗?IN = 德尔福常数?

恕我直言:你最好这样做 - 用于代码的自我记录。然而,事情是关于在给定代码约定中传递不同值的二进制兼容性。我认为 CONST(或它的缺席)不会是确保正确传输任何数据类型的灵丹妙药。所以总的来说 - 我认为这是个人品味和自律的问题。

3) 带指针的类型。DWORD = 德尔福双字。好的。DWORD* = Delphi PDWROD(或所​​有标记 * = Delphi 指针类型)?

默认情况下,Delphi 从 Pascal 继承“每个指针都是无类型的”的概念。对我来说,这破坏了 Pascal 的类型安全,在我的项目中,我总是检查Typed Pointers选项 - 或将 pragma{$T+}放入源代码中。

因此,根据编译器设置DWORD*可能是Pointer^DWORD; 该PDWORD类型只是 . 的命名别名 (C++: typedef) ^DWORD

于 2013-07-16T10:01:53.317 回答