ICustomMarshaler 介面

定義

提供用來處理方法呼叫的自訂包裝函式。Provides custom wrappers for handling method calls.

public interface class 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),您可以設計自訂的封送處理器,而不是使用 interop 封送處理器。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的 managed 介面。For example, suppose that you are developing a managed interface called INew. 當此介面透過標準 COM 可呼叫包裝函式(CCW)公開給 COM 時,它具有與 managed 介面相同的方法,而且會使用 interop 封送處理器內建的封送處理規則。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. 現在假設所謂的知名 COM 介面 IOld 已經提供與 INew 介面相同的功能。Now suppose that a well-known COM interface called IOld already provides the same functionality as the INew interface. 藉由設計自訂封送處理器,您可以提供 IOld 的非受控執行,只將呼叫委派給 INew 介面的 managed 執行。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. 因此,自訂封送處理器會當做 managed 和非受控介面之間的橋樑。Therefore, the custom marshaler acts as a bridge between the managed and unmanaged interfaces.

注意

從 managed 程式碼呼叫至僅分派介面上的非受控程式碼時,不會叫用自訂封送處理器。Custom marshalers are not invoked when calling from managed code to unmanaged code on a dispatch-only interface.

定義封送處理類型Defining the Marshaling Type

在您可以建立自訂封送處理器之前,您必須先定義將封送處理的 managed 和非受控介面。Before you can build a custom marshaler, you must define the managed and unmanaged interfaces that will be marshaled. 這些介面通常會執行相同的功能,但會以不同的方式公開給 managed 和非受控物件。These interfaces commonly perform the same function but are exposed differently to managed and unmanaged objects.

Managed 編譯器會從中繼資料產生 managed 介面,而產生的介面看起來就像任何其他 managed 介面。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. 您在程式庫語句中定義介面,並為其指派具有「通用唯一識別碼(UUID)」屬性的介面識別碼,如下列範例所示。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}};  

MIDL 也會產生舊的 .h 檔案。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
轉換(從原生到 managed 程式碼)Conversion (from native to managed code) MarshalNativeToManaged 將原生資料的指標封送處理至 managed 物件。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.
轉換(從 managed 程式碼到機器碼)Conversion (from managed to native code) MarshalManagedToNative 將 managed 物件封送處理成原生資料的指標。Marshals a managed object into a pointer to native data. 這個方法會傳回自訂 COM 可呼叫包裝函式(CCW),它可以封送處理當做引數傳遞的 managed 介面。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.
清除(managed 程式碼)Cleanup (of managed code) CleanUpManagedData 可讓封送處理器清除由 MarshalNativeToManaged 方法傳回的 managed 資料(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

將原生資料的指標封送處理至 managed 物件。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

將 managed 物件封送處理成原生資料的指標。Marshals a managed object into a pointer to native data. 這個方法會傳回自訂 COM 可呼叫包裝函式(CCW),它可以封送處理當做引數傳遞的 managed 介面。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 方法傳回的 managed 資料(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 介面之外,自訂封送處理器還必須實作為一個 static GetInstance 方法,其可接受 String 做為參數,並具有 ICustomMarshaler的傳回型別。In 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 方法是由 common language runtime 的 COM Interop 層呼叫,以具現化自訂封送處理器的實例。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. 然後,common language runtime 的 interop 服務會檢查屬性,並在第一次需要封送處理引數(參數或欄位)時,建立自訂封送處理器。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 managed 介面的定義: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 方法的 managed 描述會採用 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 的 managed 定義所產生的類型程式庫,會產生此範例中所示的非受控定義,而不是標準定義。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 方法之 managed 定義中 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)

針對不需要的 Managed 資料執行必要的清除。Performs necessary cleanup of the managed data when it is no longer needed.

CleanUpNativeData(IntPtr)

針對不需要的 Unmanaged 資料執行必要的清除。Performs necessary cleanup of the unmanaged data when it is no longer needed.

GetNativeDataSize()

傳回要封送處理的原生資料 (Native Data) 的大小。Returns the size of the native data to be marshaled.

MarshalManagedToNative(Object)

將 Managed 資料轉換為 Unmanaged 資料。Converts the managed data to unmanaged data.

MarshalNativeToManaged(IntPtr)

將 Unmanaged 資料轉換為 Managed 資料。Converts the unmanaged data to managed data.

適用於