Share via


自定义 COM 可调用包装

自定义 COM 可调用包装是一项简单的任务。 如果要向 COM 客户端公开的类型具有非标准封送处理要求,则将 System.Runtime.InteropServices.MarshalAsAttribute 特性应用于方法参数、类字段或者返回值以更改封送处理行为。

如下面的插图所示,可以导出托管 DLL 而不自定义包装(如图左侧所示)。 或者,可以向源代码添加封送处理信息,编译它,然后使用类型库导出程序 (Tlbexp.exe) 导出修改后的 DLL 并产生自定义包装。

导出的 DLL 中的封送处理信息

类型库导出程序

注意注意

要向 COM 公开的所有托管类型、方法、属性、字段和事件都必须是公共的。类型必须具有公共的默认构造函数,该构造函数是唯一可以通过 COM 调用的构造函数。有关其他信息,请参见为互用性限定 .NET 类型

在托管和非托管代码之间封送数据时,interop 封送拆收器必须识别正在传递的数据的表示形式:

  • 对于可直接复制到本机结构中的类型,托管和非托管表示形式始终是相同的。 例如,4 字节整数始终被封送为 4 字节整数。 interop 封送拆收器使用托管签名确定数据的表示形式。

  • 对于非直接复制到本机结构中的类型,interop 封送拆收器根据其方法签名识别托管表示形式,但无法根据方法签名识别非托管表示形式。 若要封送非直接复制到本机结构中的类型,可以使用下列技术中的一种:

    • 允许封送拆收器从托管表示形式推断表示形式。

    • 显式提供非托管数据的表示形式。

例如,当从托管代码到非托管代码进行封送时,字符串将被转换为 BSTR 类型,除非显式应用 MarshalAsAttribute 将字符串封送到其他类型(如 LPWSTR)。 可以将该特性应用到类型定义的源代码中的参数、字段或返回值,如下例中所示。

将 MarshalAsAttribute 应用到参数

Public Sub M1(<MarshalAs(UnmanagedType.LPWStr)> msg As String)
    ' ...
End Sub
void M1([MarshalAs(UnmanagedType.LPWStr)] string msg)
{
    // ...
}
void M1([MarshalAs(UnmanagedType::LPWStr)] String^ msg)
{
    // ...
}

将 MarshalAsAttribute 应用到类中的字段

Class MsgText
    <MarshalAs(UnmanagedType.LPWStr)> _
    Public msg As String = ""
End Class
class MsgText
{
    [MarshalAs(UnmanagedType.LPWStr)]
    public string msg = "";
}
ref class MsgText
{
public:
    [MarshalAs(UnmanagedType::LPWStr)]
    String^ msg;

    MsgText()
    {
        msg = "";
    }
};

将 MarshalAsAttribute 应用到返回值

Public Function M2() As <MarshalAs(UnmanagedType.LPWStr)> String
    Dim msg As New String(New char(128){})
    ' Load message here ...
    Return msg
End Function
[return: MarshalAs(UnmanagedType.LPWStr)]
public string GetMessage()
{
    string msg = new string(new char[128]);
    // Load message here ...
    return msg;
}
[returnvalue: MarshalAs(UnmanagedType::LPWStr)]
String^ GetMessage()
{
    String^ msg = gcnew String(gcnew array<Char>(128));
    // Load message here ...
    return msg;
}

可以设置 System.Runtime.InteropServices.UnmanagedType 枚举以指示所需的非托管类型的格式。 在前面的签名中,msg 数据被作为 Unicode 字符 (LPWStr) 的以 null 终止的缓冲区进行封送处理。

有时,interop 封送拆收器需要的信息比托管和非托管数据格式所提供的信息多。 例如,若要封送数组,必须提供元素类型、秩、大小和数组的界限。 可以使用 MarshalAsAttribute 指定所需的附加信息。

请参见

参考

自定义 COM 可调用包装

概念

COM 数据类型

自定义运行时可调用包装

其他资源

用 COM 互操作对数据进行封送处理

默认封送处理行为