代码之家  ›  专栏  ›  技术社区  ›  ElektroStudios

将UnmanagedType枚举的值转换为其托管类型等效值

  •  -2
  • ElektroStudios  · 技术社区  · 9 年前

    我正在尝试为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
    
    2 回复  |  直到 9 年前
        1
  •  2
  •   Hadi Brais    9 年前
    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.Object 。这也是 UnmanagedType.Struct .

    Case UnmanagedType.LPStr
        Return GetType(StringBuilder)
    

    你可以使用StringBuilder或String,这取决于被调用的函数。如果您正在进行常规转换,可能应该使用String。

    Case UnmanagedType.R4
    
    Case UnmanagedType.R8
    

    这些对应于 System.Single System.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. 因此,您应该返回 Object IntPtr 。该网页还说明 UnmanagedType.ByValTStr 是一个 String .

    UnmanagedType.ByValArray , UnmanagedType.LPArray UnmanagedType.SafeArray 全部对应于 System.Array .我强烈建议阅读 this 文章以更好地理解这些类型。此外,如果可能,您应该使用 this 技巧

    最后,我想你还是忘记了还是忽略了 UnmanagedType.HString UnmanagedType.IInspectable ,对应于 一串 对象 分别地

    我建议按如下方式对开关类型进行分组:数组类型、字符串类型、基元类型、其他指针类型和其他整数类型。

        2
  •  1
  •   Ian    9 年前

    对于此类直接 功能类似 翻译/映射(即每个都是唯一的 X 正好有一个值 Y ),我建议使用 Dictionary 而不是 switch 案例

    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(字符串))//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 .(对比词的使用 非受管的 管理 他们自己暗示了什么!)

    然而,考虑到这些空箱,我可能会这样做:

    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 。由于当前映射来自 非托管类型 Managed 是非双射,其中 非托管类型 管理 ->结论: 反之则不那么安全 .