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

时间:2015-09-18 00:57:58

标签: .net vb.net marshalling native-code

我的知识超出.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"
  4. 但是,在下面的代码中我使用的是long数据类型,它的工作正常。有什么情况会给出不正确的结果吗?它与long合作的原因是什么?

      

    框架:.Net 2.0;
      架构:64位;
      操作系统:Windows Server 2012 R2;
      Visual Studio:2013

    CODE

    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
    

1 个答案:

答案 0 :(得分:2)

  

架构:64位;

这最有可能让你摆脱困境。 ULONG_PTR是一个整数类型,其大小取决于进程的位数。在32位进程中它是32位,在64位进程中它是64位。最直接的.NET类型等价物是UIntPtr

这里的用法是作为句柄,实际值无关紧要。您不对该值执行任何算术,您可以从CryptAcquireContext()获取它并将其传递给CryptCreateHash()。因此,您在pinvoke声明中选择的类型是有符号还是无符号无关紧要。 IntPtr是更常见的建议的原因,它是[CLSCompliant]类型。

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

如果没有,你可能会遇到麻烦。要么是因为您的程序在具有32位操作系统的计算机上运行,​​要么在VS2013上使用新项目的默认设置时运行。相关设置是Project>属性>编译标签>目标CPU。将它从AnyCPU更改为x86以解决问题。请注意,还有“首选32位”复选框,因为您以.NET 2.0

为目标而被禁用

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

故意错误地使用IntPtr,因此它与本机类型匹配。更正确的是当你声明它HandleRef时。这是一个包装器,确保在本机代码忙于执行时不能销毁句柄,如果你有一个调用CryptReleaseContext()的Finalize()方法,则应该使用它。更正确的是使用安全的句柄包装类型,如.NET Framework does,它有一个关键的终结器,即使程序严重爆炸也会运行。只有在代码在非托管主机程序内部运行时才真正需要,SQL Server作为一个常见示例。