ICustomMarshaler 接口

定义

提供用于处理方法调用的自定义包装器。Provides custom wrappers for handling method calls.

public interface class ICustomMarshaler
public interface ICustomMarshaler
[System.Runtime.InteropServices.ComVisible(true)]
public interface ICustomMarshaler
type ICustomMarshaler = interface
Public Interface ICustomMarshaler
派生
属性

注解

封送拆收器在新旧接口的功能之间提供桥梁。A marshaler provides a bridge between the functionality of old and new interfaces. 自定义封送具有以下优势:Custom marshaling provides the following benefits:

  • 它使设计为使用旧接口的客户端应用程序也可以使用实现新接口的服务器。It enables client applications that were designed to work with an old interface to also work with servers that implement a new interface.

  • 它允许生成的客户端应用程序使用新接口来处理实现旧接口的服务器。It enables client applications built to work with a new interface to work with servers that implement an old interface.

如果某个接口引入了不同的封送行为,或以不同方式向组件对象模型(COM)公开的接口,则可以设计自定义封送拆收器而不是使用互操作封送拆收器。If you have an interface that introduces different marshaling behavior or that is exposed to the Component Object Model (COM) in a different way, you can design a custom marshaler instead of using the interop marshaler. 通过使用自定义封送拆收器,你可以最大程度地减少新 .NET Framework 组件和现有 COM 组件之间的差异。By using a custom marshaler, you can minimize the distinction between new .NET Framework components and existing COM components.

例如,假设您正在开发一个名为 INew的托管接口。For example, suppose that you are developing a managed interface called INew. 如果通过标准 COM 可调用包装器(CCW)向 COM 公开此接口,则它具有与托管接口相同的方法,并使用互操作封送拆收器中内置的封送规则。When this interface is exposed to COM through a standard COM callable wrapper (CCW), it has the same methods as the managed interface and uses the marshaling rules built into the interop marshaler. 现在假设名为 IOld 的已知 COM 接口已提供与 INew 接口相同的功能。Now suppose that a well-known COM interface called IOld already provides the same functionality as the INew interface. 通过设计自定义封送拆收器,你可以提供 IOld 的非托管实现,只需将调用委托给 INew 接口的托管实现。By designing a custom marshaler, you can provide an unmanaged implementation of IOld that simply delegates the calls to the managed implementation of the INew interface. 因此,自定义封送拆收器充当托管和非托管接口之间的桥梁。Therefore, the custom marshaler acts as a bridge between the managed and unmanaged interfaces.

备注

从托管代码调用到仅调度接口上的非托管代码时,不会调用自定义封送拆收器。Custom marshalers are not invoked when calling from managed code to unmanaged code on a dispatch-only interface.

定义封送处理类型Defining the Marshaling Type

在可以生成自定义封送拆收器之前,必须定义将被封送的托管和非托管接口。Before you can build a custom marshaler, you must define the managed and unmanaged interfaces that will be marshaled. 这些接口通常执行相同的功能,但以不同方式向托管和非托管对象公开。These interfaces commonly perform the same function but are exposed differently to managed and unmanaged objects.

托管编译器从元数据生成托管接口,生成的接口看起来像其他任何托管接口。A managed compiler produces a managed interface from metadata, and the resulting interface looks like any other managed interface. 下面的示例演示一个典型接口。The following example shows a typical interface.

public interface class INew
{
    void NewMethod();
};
public interface INew
{
    void NewMethod();
}
Public Interface INew
    Sub NewMethod()
End Interface

可以在接口定义语言(IDL)中定义非托管类型,并将其与 Microsoft 接口定义语言(MIDL)编译器一起编译。You define the unmanaged type in Interface Definition Language (IDL) and compile it with the Microsoft Interface Definition Language (MIDL) compiler. 在 library 语句中定义接口,并为其分配一个具有通用唯一标识符(UUID)特性的接口 ID,如下面的示例所示。You define the interface within a library statement and assign it an interface ID with the universal unique identifier (UUID) attribute, as the following example demonstrates.

 [uuid(9B2BAADA-0705-11D3-A0CD-00C04FA35826)]  
library OldLib {  
     [uuid(9B2BAADD-0705-11D3-A0CD-00C04FA35826)]  
     interface IOld : IUnknown  
         HRESULT OldMethod();  
}  

MIDL 编译器将生成多个输出文件。The MIDL compiler produces several output files. 如果在旧 .idl 中定义了接口,则输出文件 Old_i. c 将使用接口的接口标识符(IID)定义 const 变量,如下例所示。If the interface is defined in Old.idl, the output file Old_i.c defines a const variable with the interface identifier (IID) of the interface, as the following example demonstrates.

const IID IID_IOld = {0x9B2BAADD,0x0705,0x11D3,{0xA0,0xCD,0x00,0xC0,0x4F,0xA3,0x58,0x26}};  

旧 .h 文件也由 MIDL 生成。The Old.h file is also produced by MIDL. 它包含可C++在C++源代码中包含的接口的定义。It contains a C++ definition of the interface that can be included in your C++ source code.

实现 ICustomMarshaler 接口Implementing the ICustomMarshaler Interface

自定义封送拆收器必须实现 ICustomMarshaler 接口,才能向运行时提供适当的包装。Your custom marshaler must implement the ICustomMarshaler interface to provide the appropriate wrappers to the runtime.

下面C#的代码显示必须由所有自定义封送拆收器实现的基接口。The following C# code displays the base interface that must be implemented by all custom marshalers.

public interface class ICustomMarshaler
{
     Object^ MarshalNativeToManaged( IntPtr^ pNativeData );
     IntPtr^ MarshalManagedToNative( Object^ ManagedObj );
     void CleanUpNativeData( IntPtr^ pNativeData );
     void CleanUpManagedData( Object^ ManagedObj );
     int GetNativeDataSize();
};
public interface ICustomMarshaler
{
     Object MarshalNativeToManaged( IntPtr pNativeData );
     IntPtr MarshalManagedToNative( Object ManagedObj );
     void CleanUpNativeData( IntPtr pNativeData );
     void CleanUpManagedData( Object ManagedObj );
     int GetNativeDataSize();
}
Public Interface ICustomMarshaler
     Function MarshalNativeToManaged( pNativeData As IntPtr ) As Object
     Function MarshalManagedToNative( ManagedObj As Object ) As IntPtr
     Sub CleanUpNativeData( pNativeData As IntPtr )
     Sub CleanUpManagedData( ManagedObj As Object )
     Function GetNativeDataSize() As Integer
End Interface

ICustomMarshaler 接口包含提供转换支持、清除支持和有关要封送的数据的信息的方法。The ICustomMarshaler interface includes methods that provide conversion support, cleanup support, and information about the data to be marshaled.

操作类型Type of operation ICustomMarshaler 方法ICustomMarshaler method 描述Description
转换(从本机到托管代码)Conversion (from native to managed code) MarshalNativeToManaged 将指向本机数据的指针封送到托管对象。Marshals a pointer to native data into a managed object. 此方法返回一个自定义运行时可调用包装(RCW),该包装器可以封送作为参数传递的非托管接口。This method returns a custom runtime callable wrapper (RCW) that can marshal the unmanaged interface that is passed as an argument. 封送拆收器应为该类型返回自定义 RCW 的实例。The marshaler should return an instance of the custom RCW for that type.
转换(从托管代码到本机代码)Conversion (from managed to native code) MarshalManagedToNative 将托管对象封送到指向本机数据的指针。Marshals a managed object into a pointer to native data. 此方法返回一个自定义 COM 可调用包装器(CCW),它可以封送作为参数传递的托管接口。This method returns a custom COM callable wrapper (CCW) that can marshal the managed interface that is passed as an argument. 封送拆收器应返回该类型的自定义 CCW 的实例。The marshaler should return an instance of the custom CCW for that type.
清理(本机代码)Cleanup (of native code) CleanUpNativeData 允许封送拆收器清理由 MarshalManagedToNative 方法返回的本机数据(CCW)。Enables the marshaler to clean up the native data (the CCW) that is returned by the MarshalManagedToNative method.
清除(托管代码)Cleanup (of managed code) CleanUpManagedData 允许封送拆收器清理由 MarshalNativeToManaged 方法返回的托管数据(RCW)。Enables the marshaler to clean up the managed data (the RCW) that is returned by the MarshalNativeToManaged method.
信息(关于本机代码)Information (about native code) GetNativeDataSize 返回要封送处理的非托管数据的大小。Returns the size of the unmanaged data to be marshaled.

转换Conversion

ICustomMarshaler.MarshalNativeToManaged

将指向本机数据的指针封送到托管对象。Marshals a pointer to native data into a managed object. 此方法返回一个自定义运行时可调用包装(RCW),该包装器可以封送作为参数传递的非托管接口。This method returns a custom runtime callable wrapper (RCW) that can marshal the unmanaged interface that is passed as an argument. 封送拆收器应为该类型返回自定义 RCW 的实例。The marshaler should return an instance of the custom RCW for that type.

ICustomMarshaler.MarshalManagedToNative

将托管对象封送到指向本机数据的指针。Marshals a managed object into a pointer to native data. 此方法返回一个自定义 COM 可调用包装器(CCW),它可以封送作为参数传递的托管接口。This method returns a custom COM callable wrapper (CCW) that can marshal the managed interface that is passed as an argument. 封送拆收器应返回该类型的自定义 CCW 的实例。The marshaler should return an instance of the custom CCW for that type.

清理Cleanup

ICustomMarshaler.CleanUpNativeData

允许封送拆收器清理由 MarshalManagedToNative 方法返回的本机数据(CCW)。Enables the marshaler to clean up the native data (the CCW) that is returned by the MarshalManagedToNative method.

ICustomMarshaler.CleanUpManagedData

允许封送拆收器清理由 MarshalNativeToManaged 方法返回的托管数据(RCW)。Enables the marshaler to clean up the managed data (the RCW) that is returned by the MarshalNativeToManaged method.

大小信息Size Information

ICustomMarshaler.GetNativeDataSize

返回要封送处理的非托管数据的大小。Returns the size of the unmanaged data to be marshaled.

实现 GetInstance 方法Implementing the GetInstance Method

除了实现 ICustomMarshaler 接口外,自定义封送拆收器还必须实现一个名为 GetInstancestatic 方法,该方法接受 String 作为参数并且其返回类型为 ICustomMarshalerIn addition to implementing the ICustomMarshaler interface, custom marshalers must implement a static method called GetInstance that accepts a String as a parameter and has a return type of ICustomMarshaler. static 方法由公共语言运行时的 COM 互操作层调用,用于实例化自定义封送拆收器的实例。This static method is called by the common language runtime's COM interop layer to instantiate an instance of the custom marshaler. 传递给 GetInstance 的字符串是一个 cookie,该方法可用于自定义返回的自定义封送拆收器。The string that is passed to GetInstance is a cookie that the method can use to customize the returned custom marshaler.

static ICustomMarshaler *GetInstance(String *pstrCookie);  

应用 MarshalAsAttributeApplying MarshalAsAttribute

若要使用自定义封送拆收器,必须将 MarshalAsAttribute 特性应用到要封送的参数或字段。To use a custom marshaler, you must apply the MarshalAsAttribute attribute to the parameter or field that is being marshaled.

还必须将 UnmanagedType.CustomMarshaler 枚举值传递到 MarshalAsAttribute 构造函数。You must also pass the UnmanagedType.CustomMarshaler enumeration value to the MarshalAsAttribute constructor. 此外,还必须指定包含以下命名参数之一的 MarshalType 字段:In addition, you must specify the MarshalType field with one of the following named parameters:

  • MarshalType (必需):自定义封送拆收器的程序集限定名称。MarshalType (required): The assembly-qualified name of the custom marshaler. 名称应包括自定义封送拆收器的命名空间和类。The name should include the namespace and class of the custom marshaler. 如果未在中使用自定义封送拆收器,则必须指定定义它的程序集的名称。If the custom marshaler is not defined in the assembly it is used in, you must specify the name of the assembly in which it is defined.

    备注

    您可以使用 MarshalTypeRef 字段,而不是 MarshalType 字段。You can use the MarshalTypeRef field instead of the MarshalType field. MarshalTypeRef 采用更易于指定的类型。MarshalTypeRef takes a type that is easier to specify.

  • MarshalCookie (可选):传递到自定义封送拆收器的 cookie。MarshalCookie (optional): A cookie that is passed to the custom marshaler. 可以使用 cookie 向封送拆收器提供附加信息。You can use the cookie to provide additional information to the marshaler. 例如,如果使用相同的封送拆收器来提供多个包装,cookie 会标识特定包装。For example, if the same marshaler is used to provide a number of wrappers, the cookie identifies a specific wrapper. Cookie 传递给封送拆收器的 GetInstance 方法。The cookie is passed to the GetInstance method of the marshaler.

MarshalAsAttribute 属性标识自定义封送拆收器,使其可以激活适当的包装。The MarshalAsAttribute attribute identifies the custom marshaler so it can activate the appropriate wrapper. 然后,公共语言运行时的互操作服务将检查属性,并在第一次需要封送参数(参数或字段)时创建自定义封送拆收器。The common language runtime's interop service then examines the attribute and creates the custom marshaler the first time the argument (parameter or field) needs to be marshaled.

然后,运行时调用自定义封送拆收器上的 MarshalNativeToManagedMarshalManagedToNative 方法,以激活正确的包装器来处理调用。The runtime then calls the MarshalNativeToManaged and MarshalManagedToNative methods on the custom marshaler to activate the correct wrapper to handle the call.

使用自定义封送拆收器Using a Custom Marshaler

自定义封送拆收器完成后,可以将其用作特定类型的自定义包装器。When the custom marshaler is complete, you can use it as a custom wrapper for a particular type. 下面的示例演示 IUserData 托管接口的定义:The following example shows the definition of the IUserData managed interface:

public interface class IUserData
{
    void DoSomeStuff(INew^ pINew);
};
interface IUserData
{
    void DoSomeStuff(INew pINew);
}
Public Interface IUserData
    Sub DoSomeStuff(pINew As INew)
End Interface

在下面的示例中,IUserData 接口使用 NewOldMarshaler 自定义封送拆收器使非托管客户端应用程序能够将 IOld 接口传递到 DoSomeStuff 方法。In the following example, the IUserData interface uses the NewOldMarshaler custom marshaler to enable unmanaged client applications to pass an IOld interface to the DoSomeStuff method. 如前面的示例所示,DoSomeStuff 方法的托管说明采用 INew 接口,而非托管版本的 DoSomeStuff 采用 IOld 接口指针,如以下示例中所示。The managed description of the DoSomeStuff method takes an INew interface, as shown in the previous example, whereas the unmanaged version of DoSomeStuff takes an IOld interface pointer, as shown in the following example.

[uuid(9B2BAADA-0705-11D3-A0CD-00C04FA35826)]  
library UserLib {  
     [uuid(9B2BABCD-0705-11D3-A0CD-00C04FA35826)]  
     interface IUserData : IUnknown  
         HRESULT DoSomeStuff(IUnknown* pIOld);  
}  

通过导出 IUserData 的托管定义而生成的类型库将生成本示例中所示的非托管定义,而不是标准定义。The type library that is generated by exporting the managed definition of IUserData yields the unmanaged definition shown in this example instead of the standard definition. 应用于 DoSomeStuff 方法的托管定义中的 INew 参数的 MarshalAsAttribute 特性指示该参数使用自定义封送拆收器,如下面的示例所示。The MarshalAsAttribute attribute applied to the INew argument in the managed definition of the DoSomeStuff method indicates that the argument uses a custom marshaler, as the following example shows.

using namespace System::Runtime::InteropServices;
using System.Runtime.InteropServices;
Imports System.Runtime.InteropServices

public interface class IUserData
{
    void DoSomeStuff(
        [MarshalAs(UnmanagedType::CustomMarshaler,
             MarshalType="MyCompany.NewOldMarshaler")]
        INew^ pINew
    );
};
interface IUserData
{
    void DoSomeStuff(
        [MarshalAs(UnmanagedType.CustomMarshaler,
             MarshalType="MyCompany.NewOldMarshaler")]
        INew pINew
    );
}
Public Interface IUserData
    Sub DoSomeStuff( _
        <MarshalAs(UnmanagedType.CustomMarshaler, _
        MarshalType := "MyCompany.NewOldMarshaler")> pINew As INew)
End Interface

在前面的示例中,提供给 MarshalAsAttribute 特性的第一个参数是 UnmanagedType.CustomMarshalerUnmanagedType.CustomMarshaler 枚举值。In the previous examples, the first parameter provided to the MarshalAsAttribute attribute is the UnmanagedType.CustomMarshaler enumeration value UnmanagedType.CustomMarshaler.

第二个参数是 MarshalType 字段,它提供自定义封送拆收器的程序集限定名称。The second parameter is the MarshalType field, which provides the assembly-qualified name of the custom marshaler. 此名称包含自定义封送拆收器(MarshalType="MyCompany.NewOldMarshaler")的命名空间和类。This name consists of the namespace and class of the custom marshaler (MarshalType="MyCompany.NewOldMarshaler").

方法

CleanUpManagedData(Object)

不再需要时执行必要的托管数据的清除。Performs necessary cleanup of the managed data when it is no longer needed.

CleanUpNativeData(IntPtr)

不再需要时执行必要的非托管数据的清除。Performs necessary cleanup of the unmanaged data when it is no longer needed.

GetNativeDataSize()

返回要封送的本机数据的大小。Returns the size of the native data to be marshaled.

MarshalManagedToNative(Object)

将托管数据转换为非托管数据。Converts the managed data to unmanaged data.

MarshalNativeToManaged(IntPtr)

将非托管数据转换为托管数据。Converts the unmanaged data to managed data.

适用于