【问题标题】:Why long datatype work for this marshalling?为什么长数据类型适用于这种编组?
【发布时间】:2015-09-18 00:57:58
【问题描述】:

我对 .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 合作的原因是什么?

框架:.Net 2.0;
架构:64 位;
操作系统:Windows Server 2012 R2;
视觉工作室: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

【问题讨论】:

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


【解决方案1】:

架构:64 位;

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

这里的用法是作为句柄,实际值无所谓。您不对该值进行任何算术运算,您可以从 CryptAcquireContext() 获取它,然后将其传递给 CryptCreateHash()。因此,您在 pinvoke 声明中选择的类型是有符号还是无符号都没有关系。之所以IntPtr 是比较常见的advice,是一个[CLSCompliant] 类型。

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

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

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

故意弄错这个没有意义,请改用IntPtr,这样它就可以匹配本机类型。更正确的是当您将其声明为 HandleRef 时。这是一个包装器,可确保在本机代码忙于执行时不会破坏句柄,如果您有一个调用 CryptReleaseContext() 的 Finalize() 方法,则应使用该包装器。更正确的是使用安全的句柄包装器类型,例如.NET Framework does,它有一个关键的终结器,即使程序被严重破坏也能运行。仅当您的代码在非托管托管程序中运行时才真正需要,例如 SQL Server。

【讨论】:

  • 已测试 -- PInvokeStackImbalance 在 32 位机器上:对 PInvoke 函数 'Test001S!Test001S.Module1::CryptCreateHash' 的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配
猜你喜欢
  • 1970-01-01
  • 2018-03-01
  • 2015-08-30
  • 2013-07-20
  • 2015-09-22
  • 1970-01-01
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多