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

Translate values of UnmanagedType enumeration to their managed type equivalents

我正在尝试为 P/Invoking 执行此辅助函数,目的是帮助确定哪种托管类型最适合为 windows [=26= 的特定封送处理声明]定义。

我从这里获取信息: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

对于这样的直接function-liketranslation/mapping(即每个唯一的X恰好有一个Y的值) ,我建议使用 Dictionary 而不是 switch case

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# //等等...

因此,要检查其 managed-counterpart 是否存在,您可以简单地使用字典:

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

现在,除了样式之外,您对 "fill the emptiness" 的请求有点困难,因为并非所有 unmanagedmanaged 中都有直接等效项。 (使用对比词 unmanaged vs 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)

你的可选问题是问反向操作是否安全。要反过来并完全等效,必须存在 one-to-one 关系。

即借用数学,如果x与f(x)的关系为bijection,则f(x)只能有f'(x)。由于当前从 UnmanagedTypeManaged 的映射是 non-bijection,其中 UnmanagedType 的成员多于 Managed -> 结论:反之则不安全.

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. 因此,你应该 return ObjectIntPtr。该网页还表明 UnmanagedType.ByValTStrString.

UnmanagedType.ByValArrayUnmanagedType.LPArrayUnmanagedType.SafeArray都对应System.Array。我强烈建议阅读 this article to better understand these types. Also, if possible, you should create more specialized array types using this 技巧。

最后,我觉得你要么忘了要么省略了UnmanagedType.HStringUnmanagedType.IInspectable,分别对应StringObject

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