ICustomMarshaler Rozhraní

Definice

Poskytuje vlastní obálky pro zpracování volání metod.

public interface class ICustomMarshaler
public interface ICustomMarshaler
[System.Runtime.InteropServices.ComVisible(true)]
public interface ICustomMarshaler
type ICustomMarshaler = interface
[<System.Runtime.InteropServices.ComVisible(true)>]
type ICustomMarshaler = interface
Public Interface ICustomMarshaler
Odvozené
Atributy

Poznámky

Rozhraní ICustomMarshaler poskytuje vlastní obálky pro zpracování volání metod.

Marshaller poskytuje most mezi funkcemi starých a nových rozhraní. Vlastní maršálování poskytuje následující výhody:

  • Umožňuje klientským aplikacím, které byly navrženy tak, aby fungovaly se starým rozhraním, aby fungovaly také se servery, které implementují nové rozhraní.
  • Umožňuje klientským aplikacím vytvořeným pracovat s novým rozhraním pro práci se servery, které implementují staré rozhraní.

Pokud máte rozhraní, které zavádí různé způsoby zpracování dat nebo je vystaveno Component Object Modelu (COM) jiným způsobem, můžete navrhnout vlastní maršálovač namísto použití maršálovače interoperability. Pomocí vlastního marshalleru můžete minimalizovat rozdíl mezi novými komponentami .NET a existujícími komponentami modelu COM.

Předpokládejme například, že vyvíjíte spravované rozhraní s názvem INew. Pokud je toto rozhraní vystaveno modelu COM prostřednictvím standardní volatelné obálky modelu COM (CCW), má stejné metody jako spravované rozhraní a používá pravidla pro přenos dat integrovaná do zprostředkovatele interop komunikace. Předpokládejme, že dobře známé rozhraní COM IOld již poskytuje stejné funkce jako rozhraní INew. Návrhem vlastního marshalleru můžete poskytnout nespravovanou implementaci IOld , která jednoduše deleguje volání na spravovanou implementaci INew rozhraní. Vlastní marshaller proto funguje jako most mezi spravovanými a nespravovanými rozhraními.

Note

Vlastní zařazovače se nevyvolávají při volání ze spravovaného kódu do nespravovaného kódu v rozhraní jen pro odesílání.

Definujte typ maršálování

Než budete moct vytvořit vlastní marshaller, musíte definovat spravovaná a nespravovaná rozhraní, která budou zařazována. Tato rozhraní obvykle provádějí stejnou funkci, ale jsou vystavena odlišně spravovaným a nespravovaným objektům.

Spravovaný kompilátor vytvoří spravované rozhraní z metadat a výsledné rozhraní vypadá jako jakékoli jiné spravované rozhraní. Následující příklad ukazuje typické rozhraní.

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

Definujete nespravovaný typ v jazyce IDL (Interface Definition Language) a zkompilujete ho pomocí kompilátoru JAZYKA MIDL (Microsoft Interface Definition Language). Rozhraní definujete v příkazu knihovny a přiřadíte ho ID rozhraní s atributem univerzálního jedinečného identifikátoru (UUID), jak ukazuje následující příklad.

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

Kompilátor MIDL vytvoří několik výstupních souborů. Pokud je rozhraní definováno v Old.idl, výstupní soubor Old_i.c definuje proměnnou const s identifikátorem rozhraní (IID), jak ukazuje následující příklad.

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

Soubor Old.h je také vytvořen aplikací MIDL. Obsahuje definici rozhraní C++, které lze zahrnout do zdrojového kódu jazyka C++.

Implementace rozhraní ICustomMarshaler

Váš vlastní marshaller musí implementovat ICustomMarshaler rozhraní, aby poskytovalo příslušné zabalení pro modul runtime.

Následující kód jazyka C# zobrazí základní rozhraní, které musí implementovat všechny vlastní marshallery.

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

Rozhraní ICustomMarshaler obsahuje metody, které poskytují podporu převodu, podporu čištění a informace o zařazovaných datech.

Typ operace Metoda ICustomMarshaler Description
Převod (z nativního na spravovaný kód) MarshalNativeToManaged Zařadí ukazatel na nativní data do spravovaného objektu. Tato metoda vrátí vlastní volatelnou obálku modulu runtime (RCW), která může zprostředkovat nespravované rozhraní, jež je předáno jako argument. Marshaller by měl vrátit instanci upraveného RCW pro tento typ.
Převod (ze spravovaného na nativní kód) MarshalManagedToNative Převádí spravovaný objekt na ukazatel na nativní data. Tato metoda vrátí vlastní volatelný obal modelu COM (CCW), který může zprostředkovat spravované rozhraní, jež je předáno jako argument. Marshaller by měl vrátit instanci přizpůsobeného objektu CCW pro daný typ.
Vyčištění (nativního kódu) CleanUpNativeData Umožňuje marshalleru vyčistit nativní data (CCW), která jsou vrácena metodou MarshalManagedToNative.
Vyčištění (spravovaného kódu) CleanUpManagedData Umožňuje marshalleru vyčistit spravovaná data (RCW), která vrací metoda MarshalNativeToManaged.
Informace (o nativním kódu) GetNativeDataSize Vrátí velikost nespravovaných dat, která se mají zmaršalovat.

Conversion

ICustomMarshaler.MarshalNativeToManaged

Zařadí ukazatel na nativní data do spravovaného objektu. Tato metoda vrátí vlastní volatelnou obálku modulu runtime (RCW), která může zprostředkovat nespravované rozhraní, jež je předáno jako argument. Marshaller by měl vrátit instanci upraveného RCW pro tento typ.

ICustomMarshaler.MarshalManagedToNative

Převádí spravovaný objekt na ukazatel na nativní data. Tato metoda vrátí vlastní volatelný obal modelu COM (CCW), který může zprostředkovat spravované rozhraní, jež je předáno jako argument. Marshaller by měl vrátit instanci přizpůsobeného objektu CCW pro daný typ.

Cleanup

ICustomMarshaler.CleanUpNativeData

Umožňuje marshalleru vyčistit nativní data (CCW), která jsou vrácena metodou MarshalManagedToNative.

ICustomMarshaler.CleanUpManagedData

Umožňuje marshalleru vyčistit spravovaná data (RCW), která vrací metoda MarshalNativeToManaged.

Informace o velikosti

ICustomMarshaler.GetNativeDataSize

Vrátí velikost nespravovaných dat, která se mají zmaršalovat.

Note

Pokud vlastní zařazovač volá některé metody, které při zařazování z nativního do spravovaného prostředí nebo při čištění nastaví poslední chybu P/Invoke, hodnota vrácená funkcemi Marshal.GetLastWin32Error() a Marshal.GetLastPInvokeError() bude reprezentovat toto volání při zařazování nebo čištění. To může způsobit, že při použití vlastních předavačů s P/Invokes s nastaveným DllImportAttribute.SetLastError na true mohou být chyby přehlédnuty. Pokud chcete zachovat poslední chybu P/Invoke, použijte metody Marshal.GetLastPInvokeError() a Marshal.SetLastPInvokeError(Int32) v implementaci ICustomMarshaler.

Implementace metody GetInstance

Kromě implementace rozhraní ICustomMarshaler musí vlastní marshallery implementovat metodu static nazvanou GetInstance, která přijímá String jako parametr a má návratový typ ICustomMarshaler. Tato static metoda je volána vrstvou pro interoperabilitu COM pro CLR (Common Language Runtime), která inicializuje instanci vlastního maršálera. Řetězec předaný GetInstance je cookie, kterou může metoda použít k přizpůsobení vráceného vlastního marshalleru. Následující příklad ukazuje minimální, ICustomMarshaler ale kompletní implementaci.

public class NewOldMarshaler : ICustomMarshaler
{
    public static ICustomMarshaler GetInstance(string pstrCookie)
        => new NewOldMarshaler();

    public Object MarshalNativeToManaged(IntPtr pNativeData) => throw new NotImplementedException();
    public IntPtr MarshalManagedToNative(Object ManagedObj) => throw new NotImplementedException();
    public void CleanUpNativeData(IntPtr pNativeData) => throw new NotImplementedException();
    public void CleanUpManagedData(Object ManagedObj) => throw new NotImplementedException();
    public int GetNativeDataSize() => throw new NotImplementedException();
}

Použijte atribut MarshalAsAttribute

Chcete-li použít vlastní marshaller, musíte atribut MarshalAsAttribute aplikovat na parametr nebo pole, které se mají marshlovat.

Je také nutné předat hodnotu výčtu UnmanagedType.CustomMarshaler konstruktoru MarshalAsAttribute . Kromě toho musíte zadat MarshalType pole s jedním z následujících pojmenovaných parametrů:

  • MarshalType (povinné): Název vlastního marshalleru kvalifikovaný pro sestavení. Název by měl obsahovat obor názvů a třídu vlastního marshalleru. Pokud není vlastní marshaller definován v sestavení, kde se používá, je nutné uvést název sestavení, ve kterém je definován.

    Note

    Místo pole MarshalTypeRef můžete použít MarshalType pole. MarshalTypeRef používá typ, který je jednodušší zadat.

  • MarshalCookie (volitelné): Soubor cookie předaný vlastnímu marshalleru. Soubory cookie můžete použít k poskytnutí dodatkových informací obslužnému programu. Pokud je například stejný marshaller použit k poskytnutí řady zabalovačů, soubor cookie identifikuje konkrétní zabalovač. Soubor cookie se předává GetInstance metodě marshalleru.

Atribut MarshalAsAttribute identifikuje vlastní marshaller, aby mohl aktivovat příslušnou obálku. Služba interoperability modulu CLR (Common Language Runtime) pak atribut prozkoumá a vytvoří vlastní zařazovač při prvním zařazování argumentu (parametru nebo pole).

Pak modul runtime zavolá metody MarshalNativeToManaged a MarshalManagedToNative na vlastním marshalleru, aby aktivoval správnou obálku pro zpracování volání.

Použití vlastního marshalleru

Po dokončení vlastního marshalleru jej můžete použít jako přizpůsobenou obálku pro určitý typ. Následující příklad ukazuje definici spravovaného IUserData rozhraní:

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

V následujícím příkladu IUserData rozhraní používá NewOldMarshaler vlastní marshaller k umožnění, aby nespravované klientské aplikace mohly předat IOld rozhraní metodě DoSomeStuff. Spravovaný popis DoSomeStuff metody přebírá INew rozhraní, jak je znázorněno v předchozím příkladu, zatímco nespravovaná verze DoSomeStuff přebírá IOld ukazatel rozhraní, jak je znázorněno v následujícím příkladu.

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

Knihovna typů vygenerovaná exportem spravované definice poskytuje nespravovanou definici IUserData zobrazenou v tomto příkladu místo standardní definice. Atribut MarshalAsAttribute použitý na INew argument ve spravované definici DoSomeStuff metody označuje, že argument používá vlastní marshaller, jak ukazuje následující příklad.

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

V předchozích příkladech je prvním parametrem předaným atributu MarshalAsAttribute hodnota výčtu UnmanagedType.CustomMarshalerUnmanagedType.CustomMarshaler.

Druhým parametrem je pole MarshalType, které poskytuje kvalifikovaný název sestavení vlastního marshaleru. Tento název se skládá z oboru názvů a třídy vlastního zprostředkovatele (MarshalType="MyCompany.NewOldMarshaler").

Metody

Name Description
CleanUpManagedData(Object)

Provede nezbytné vyčištění spravovaných dat, když už je nepotřebujete.

CleanUpNativeData(IntPtr)

Provede nezbytné vyčištění nespravovaných dat, pokud už je nepotřebujete.

GetNativeDataSize()

Vrátí velikost nativních dat, která se mají zařašovat.

MarshalManagedToNative(Object)

Převede spravovaná data na nespravovaná data.

MarshalNativeToManaged(IntPtr)

Převede nespravovaná data na spravovaná data.

Platí pro