为什么长数据类型适用于此编组?

Why long datatype work for this marshalling?

我对 .Net 以外的知识非常有限 - 但我花了很多时间阅读许多相关文章。

HCRYPTPROV datatype documentaion 表示它是 ULONG_PTR.

类型

以下参考文献建议使用与此对应的IntPtr

  1. Is there a definitive guide to cross platform (x86 and x64) PInvoke and windows data types?
  2. Using MS crypto library on server 2012 - CryptCreateHash error code 87: ERROR_INVALID_PARAMETER
  3. Calling AuditQuerySystemPolicy() (advapi32.dll) from C# returns "The parameter is incorrect"

但是,在下面的代码中我使用了 long 数据类型并且它工作得很好。是否有任何情况会给出不正确的结果?它与 long 一起工作的原因是什么?

Framework: .Net 2.0;
Architecture: 64 Bit;
OS: Windows Server 2012 R2;
Visual Studio: 2013

代码

Module Module1

    Private Declare Function CryptAcquireContext Lib "advapi32.dll" _
  Alias "CryptAcquireContextA" ( _
ByRef phProv As Long, ByVal pszContainer As String, ByVal pszProvider As String, _
  ByVal dwProvType As Integer, ByVal dwFlags As Integer) As Integer

    Private Declare Function CryptCreateHash Lib "advapi32.dll" (ByVal hProv As Long, _
        ByVal Algid As Integer, ByVal hKey As Integer, ByVal dwFlags As Integer, _
    ByRef phHash As Integer) As Integer

    Private Declare Function GetLastError Lib "kernel32" () As Integer

    Sub Main()

        Dim sClearText As String
        sClearText = "test1"

        Dim lHCryptprov As Long
        Dim sProvider As String
        Const MS_DEF_PROV As String = "Microsoft Base Cryptographic Provider v1.0"

        Dim lHHash As Integer
        Dim sInputBuffer As String

        Const ALG_CLASS_HASH As Integer = 32768
        Const ALG_TYPE_ANY As Integer = 0
        Const ALG_SID_MD5 As Integer = 3
        Const PROV_RSA_FULL As Integer = 1
        Const CRYPT_MACHINE_KEYSET As Integer = &H20
        Const CALG_MD5 As Integer = ((ALG_CLASS_HASH Or ALG_TYPE_ANY) Or ALG_SID_MD5)


        sInputBuffer = sClearText
        'Get handle to the default CSP
        sProvider = MS_DEF_PROV & vbNullChar


        Dim errorCode As Integer
        Dim r As Long
        r = CryptAcquireContext(lHCryptprov, "", sProvider, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)
        errorCode = GetLastError()

        Dim hashResult As Boolean
        hashResult = CBool(CryptCreateHash(lHCryptprov, CALG_MD5, 0, 0, lHHash))
        errorCode = GetLastError()


        Console.WriteLine(hashResult)
        Console.ReadLine()


    End Sub

End Module

Architecture: 64 Bit;

这最有可能让您远离麻烦。 ULONG_PTR 是一个整数类型,其大小取决于进程的位数。在 32 位进程中它是 32 位,在 64 位进程中它是 64 位。最直接的 .NET 等效类型是 UIntPtr.

这里的用法是作为句柄,实际值无所谓。您不对该值进行任何算术运算,您从 CryptAcquireContext() 获取它并简单地将它传递给 CryptCreateHash()。因此,您在 pinvoke 声明中 select 的类型是有符号的还是无符号的都没有关系。 IntPtr 是更常见的建议的原因,它是 [CLSCompliant] 类型。

VB.NET中的一个Long是64位有符号整数类型。因此当您的程序作为 64 位进程运行时匹配 ULONG_PTR。

如果没有,您可能会遇到麻烦。要么因为你的程序运行在 32 位操作系统的机器上,要么当你在 VS2013 上使用默认设置新建项目时。相关的设置是Project > Properties > Compile tab > Target CPU。将其从 AnyCPU 更改为 x86 会遇到麻烦。请注意还有 "Prefer 32-bit" 复选框,它被禁用是因为您的目标是 .NET 2.0

当您在进行此更改后启动您的程序时,您现在应该在调用 CryptCreateHash() 时获得调试器中断。有一个名为 PInvokeStackImbalance 的专用托管调试助手,它应该会注意到当函数 returns 时堆栈失调了 4 个。并调用调试器中断来告诉您它。堆栈不平衡是一个非常严重的问题,可能导致任意程序失败,包括但不限于此站点命名的问题,尤其是在发布版本中。没有 MDA 帮助很难调试。

没有必要故意弄错,请改用 IntPtr 以使其与本机类型匹配。更正确的是当你声明它 HandleRef instead. That's a wrapper that ensures that the handle cannot be destroyed while the native code is busy executing and should be used if you have a Finalize() method that calls CryptReleaseContext(). Even more correct is to use a safe handle wrapper type, like the .NET Framework does 时,它有一个关键的终结器,即使程序严重崩溃也会运行。仅当您的代码在非托管托管程序内部运行时才是真正必要的,SQL 服务器作为常见示例。