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

时间:2016-01-01 12:04:31

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

我正在尝试为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 个答案:

答案 0 :(得分:3)

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,它取决于被调用的函数。如果您正在进行常规转换,则应该使用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开关案例进行分组:数组类型,字符串类型,基本类型,其他指针类型和其他整数类型。

答案 1 :(得分:2)

对于此类直接类似功能的翻译/映射(即每个唯一X只有Y的一个值),我建议使用{{1而不是Dictionary case

<强> VB.Net/C#

switch

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

然后在您的应用首次加载中列出您的Dictionary<UnmanagedType, Type> unToManagedDict = new Dictionary<UnmanagedType, Type>(); //C# UnmanagedType,如下所示:

<强> VB.Net/C#

enum

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

因此,要检查托管对方的存在,您只需使用字典:

<强> VB.Net/C#

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

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 vs unmanaged本身就意味着什么!)

然而,鉴于空案例,我可能会这样做:

managed

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

也就是说,借用数学,f(x)只有f'(x),如果x和f(x)之间的关系是bijection。由于从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) UnmanagedType的当前映射是非双向投影,Managed的成员超过UnmanagedType - &gt;结论:反向并不安全