【问题标题】:Translate values of UnmanagedType enumeration to their managed type equivalents将 UnmanagedType 枚举的值转换为其托管类型等效项
【发布时间】:2016-04-05 23:43:44
【问题描述】:

我正在尝试为 P/Invoking 执行此辅助函数,目的是帮助确定哪个应该是最适合为 Windows API 定义的特定编组声明的托管类型。

我从这里获取了信息:UnmanagedType Enumeration

在 C# 或 Vb.Net 中,我请求帮助以填补空白案例并修复我当前的错误(如果有)。

(另外,作为一个可选的和定向的问题来回答或不回答:你认为写相反的东西是否可靠?,一种ManagedTypeToUnmanagedTypeEnum 函数。)

Public Shared Function UnmanagedTypeToManagedType(ByVal [type] As UnmanagedType) As Type

    Select Case [type]

        Case UnmanagedType.AnsiBStr
            Return GetType(String)

        Case UnmanagedType.AsAny
            Return GetType(Object)

        Case UnmanagedType.BStr
            Return GetType(String)

        Case UnmanagedType.Bool
            Return GetType(Boolean)

        Case UnmanagedType.ByValArray

        Case UnmanagedType.ByValTStr

        Case UnmanagedType.Currency
            Return GetType(Decimal)

        Case UnmanagedType.CustomMarshaler
            Return GetType(Object)

        Case UnmanagedType.Error
            Return GetType(IntPtr)

        Case UnmanagedType.FunctionPtr
            Return GetType([Delegate])

        Case UnmanagedType.I1
            Return GetType(SByte)

        Case UnmanagedType.I2
            Return GetType(Short)

        Case UnmanagedType.I4
            Return GetType(Integer)

        Case UnmanagedType.I8
            Return GetType(Long)

        Case UnmanagedType.IDispatch
            Return GetType(IntPtr)

        Case UnmanagedType.Interface
            Return GetType(IntPtr)

        Case UnmanagedType.IUnknown
            Return GetType(IntPtr)

        Case UnmanagedType.LPArray
            Return GetType(IntPtr)

        Case UnmanagedType.LPStr
            Return GetType(StringBuilder)

        Case UnmanagedType.LPStruct
            Return GetType(IntPtr)

        Case UnmanagedType.LPTStr
            Return GetType(String)

        Case UnmanagedType.LPWStr
            Return GetType(String)

        Case UnmanagedType.R4

        Case UnmanagedType.R8

        Case UnmanagedType.SafeArray

        Case UnmanagedType.Struct

        Case UnmanagedType.SysInt
            Return GetType(IntPtr)

        Case UnmanagedType.SysUInt
            Return GetType(UIntPtr)

        Case UnmanagedType.TBStr
            Return GetType(String)

        Case UnmanagedType.U1
            Return GetType(Byte)

        Case UnmanagedType.U2
            Return GetType(UShort)

        Case UnmanagedType.U4
            Return GetType(UInteger)

        Case UnmanagedType.U8
            Return GetType(ULong)

        Case UnmanagedType.VariantBool
            Return GetType(Boolean)

        Case UnmanagedType.VBByRefStr
            Return GetType(String)

        Case Else
            Throw New InvalidEnumArgumentException(argumentName:="type", invalidValue:=[type],
                                                   enumClass:=GetType(UnmanagedType))
            Return Nothing

    End Select

End Function

【问题讨论】:

  • 这个问题是基于一个有缺陷的前提。参数的语义不是按类型指定的。托管类型和非托管类型之间没有一对一的映射。你试图构造的函数是没用的。
  • @DavidHeffernan OP 知道托管类型和非托管类型之间没有一对一的映射,因为他/她要求最合适的类型。问题是从托管类型和非托管类型之间的多对多映射,构造一个典型的一对一映射。由于 OP 没有说明他/她为什么想要这样的功能或它将用于什么,所以很难知道它是否完全没用。
  • @Hadi 请定义“最合适的类型”。令我惊讶的是,您在不了解此地图的应用的情况下能够做到这一点。
  • @DavidHeffernan 好吧,如果您浏览文档,您会发现超过一半的非托管类型只对应一种托管类型。其余的对应于 System.Object、System.Delegate 或 System.Array。当然,确切的类型取决于被调用的函数。但是您不认为这种映射总体上有意义吗? OP 现在可以根据需要尝试它,看看它是否有效。
  • 您应该在必要时告诉用户,确切的托管类型取决于所使用的非托管 API。我的回答中突出显示了模棱两可的地方。

标签: c# .net vb.net winapi unmanaged


【解决方案1】:
Case UnmanagedType.Error
    Return GetType(IntPtr)

没有。 IntPtr 表示一个虚拟地址,在 32 位平台上是 32 位,在 64 位平台上是 64 位。但是UnmanagedType.Error 的大小是固定的。它是一个 32 位有符号整数,主要用于表示操作的编码结果。这是一个用词不当,因为它确实是not always indicate an error

Case UnmanagedType.IDispatch
    Return GetType(IntPtr)

Case UnmanagedType.Interface
    Return GetType(IntPtr)

Case UnmanagedType.IUnknown
    Return GetType(IntPtr)

您可能应该使用System.ObjectUnmanagedType.Struct也是如此。

Case UnmanagedType.LPStr
    Return GetType(StringBuilder)

嗯,你可以使用 StringBuilder 或 String,这取决于被调用的函数。如果您进行一般转换,您可能应该使用字符串。

Case UnmanagedType.R4

Case UnmanagedType.R8

这些分别对应于System.SingleSystem.Double

Case UnmanagedType.VariantBool
    Return GetType(Boolean)

VariantBool 是 2 字节布尔类型,但 VB 布尔类型是 4 字节。您需要使用有符号或无符号的 2 字节整数类型。

Case UnmanagedType.VBByRefStr
    Return GetType(String)

没有。 VBByRefStr 表示通过引用传递字符串。 That is, the address of the reference of the string. 因此,您应该返回ObjectIntPtr。该网页还告诉UnmanagedType.ByValTStrString

UnmanagedType.ByValArrayUnmanagedType.LPArrayUnmanagedType.SafeArray都对应System.Array。我强烈建议阅读this 文章以更好地理解这些类型。此外,如果可能,您应该使用this 技术创建更专业的数组类型。

最后,我想你还是忘记或省略了UnmanagedType.HStringUnmanagedType.IInspectable,它们分别对应StringObject

我建议将switch case分组如下:数组类型、字符串类型、原始类型、其他指针类型和其他整数类型。

【讨论】:

    【解决方案2】:

    对于这种直接的类函数翻译/映射(即每个唯一的X 恰好有一个Y 值),我建议使用Dictionary 而不是@987654325 @案例

    VB.Net/C#

    Dim unToManagedDict As New Dictionary(Of UnmanagedType, Type) 'VB.Net
    

    Dictionary<UnmanagedType, Type> unToManagedDict = new Dictionary<UnmanagedType, Type>(); //C#
    

    然后在您的应用程序的第一次加载中列出您的UnmanagedType enum,如下所示:

    VB.Net/C#

    unToManagedDict.Add(UnmanagedType.AnsiBStr, GetType(String)) 'VB.Net
    unToManagedDict.Add(UnmanagedType.AsAny, GetType(Object)) 'VB.Net
    'and so on... or,
    

    unToManagedDict.Add(UnmanagedType.AnsiBStr, typeof(string)); //C# unToManagedDict.Add(UnmanagedType.AsAny, typeof(object)); //C# //等等...

    因此,要检查其托管对应物的存在,您可以简单地使用字典:

    VB.Net/C#

    Dim type As Type = unToManagedDict(UnmanagedType.AnsiBStr) 'VB.Net
    

    Type type = unToManagedDict[UnmanagedType.AnsiBStr]; //C#
    

    如果未找到非托管输入类型,则会抛出异常错误,类似于您在

    中所做的
    Case Else
            Throw New InvalidEnumArgumentException(argumentName:="type", invalidValue:=[type],
                                                   enumClass:=GetType(UnmanagedType))
    

    这样,您无需使用新函数来处理映射。此外,您不需要每次都输入新的Case

    现在,除了样式之外,您对“填补空白”的要求有些困难,因为并非所有 unmanaged 都与 managed 直接等效。 (使用对比词unmanagedmanaged 本身就意味着什么!)

    但是,鉴于空箱,我可能会这样做:

    Case UnmanagedType.ByValArray -> Array (no best equivalent, but Array is the closest)
    Case UnmanagedType.ByValTStr -> String (no best equivalent, but String could be used)
    Case UnmanagedType.R4 -> Single
    Case UnmanagedType.R8 -> Double
    Case UnmanagedType.SafeArray -> Array (no best equivalent, but Array is the closest)
    Case UnmanagedType.Struct -> some Structure (no equivalent, each struct is unique, best is to use Structure to wrap Struct)
    

    您的可选问题询问反向操作是否安全。要做到相反并完全等效,必须存在 一对一 关系。

    也就是说,借用数学,如果x和f(x)的关系是bijection,f(x)只能有f'(x)。由于当前从UnmanagedTypeManaged 的映射是非双射的,其中UnmanagedType 的成员多于Managed -> 结论:逆向并不安全

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-26
      • 1970-01-01
      • 2018-02-14
      • 1970-01-01
      • 1970-01-01
      • 2015-09-30
      • 2023-02-21
      • 2010-12-21
      相关资源
      最近更新 更多