System.Runtime.InteropServices.ICustomMarshaler – rozhraní

Tento článek obsahuje doplňující poznámky k referenční dokumentaci pro toto rozhraní API.

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

Marshaller poskytuje most mezi funkcemi starých a nových rozhraní. Vlastní zařazová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í jiné zařazování chování nebo které je vystaveno modelu COM (Component Object Model) jiným způsobem, můžete navrhnout vlastní zařazovač místo použití zařazovače komunikace. Pomocí vlastního marshalleru můžete minimalizovat rozdíl mezi novými komponentami rozhraní .NET Framework 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ího obálky volatelného modelu COM (CCW), má stejné metody jako spravované rozhraní a používá pravidla zařazování integrovaná do zprostředkovatele komunikace. Předpokládejme, že dobře známé rozhraní IOld MODELU COM již poskytuje stejné funkce jako INew rozhraní. 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.

Poznámka:

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í.

Definování typu zařazová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é obálky modulu 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 Popis
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í volatelný obálka modulu runtime (RCW), která může zařazení nespravovaného rozhraní, které je předáno jako argument. Marshaller by měl vrátit instanci vlastní rcW pro tento typ.
Převod (ze spravovaného na nativní kód) MarshalManagedToNative Zařadí spravovaný objekt do ukazatele na nativní data. Tato metoda vrátí vlastní volatelný obálka modelu COM (CCW), která může zařazení spravovaného rozhraní, které je předáno jako argument. Marshaller by měl vrátit instanci vlastního objektu CCW pro tento typ.
Vyčištění (nativního kódu) CleanUpNativeData Umožňuje marshalleru vyčistit nativní data (CCW), která je vrácena metodou MarshalManagedToNative .
Vyčištění (spravovaného kódu) CleanUpManagedData Umožňuje zařazovač vyčistit spravovaná data (RCW), která je vrácena metodou MarshalNativeToManaged .
Informace (o nativním kódu) GetNativeDataSize Vrátí velikost nespravovaných dat, která se mají zařašovat.

Převod

ICustomMarshaler.MarshalNativeToManaged

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

ICustomMarshaler.MarshalManagedToNative

Zařadí spravovaný objekt do ukazatele na nativní data. Tato metoda vrátí vlastní volatelný obálka modelu COM (CCW), která může zařazení spravovaného rozhraní, které je předáno jako argument. Marshaller by měl vrátit instanci vlastního objektu CCW pro tento typ.

Vyčištění

ICustomMarshaler.CleanUpNativeData

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

ICustomMarshaler.CleanUpManagedData

Umožňuje zařazovač vyčistit spravovaná data (RCW), která je vrácena metodou MarshalNativeToManaged .

Informace o velikosti

ICustomMarshaler.GetNativeDataSize

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

Poznámka:

Pokud vlastní zařazovač volá všechny metody, které při zařazování z nativního do spravovaného nebo při čištění nastaví poslední chybu volání volání P/Invoke, vrátí hodnota vrácená Marshal.GetLastWin32Error() a Marshal.GetLastPInvokeError() bude představovat volání ve volání zařazování nebo čištění. To může způsobit, že při použití vlastních zařazovačů s voláními nespravovaných zpráv s nastaveným parametrem DllImportAttribute.SetLastErrortrue. Pokud chcete zachovat poslední chybu volání nespravovaného kódu, použijte Marshal.GetLastPInvokeError() v implementaci ICustomMarshaler metody a Marshal.SetLastPInvokeError(Int32) metody.

Implementace metody GetInstance

Kromě implementace ICustomMarshaler rozhraní musí vlastní marshaller implementovat metodu static , GetInstance která přijímá String jako parametr a má návratový ICustomMarshalertyp . Tato static metoda je volána vrstvou zprostředkovatele komunikace MODELU COM modulu CLR (Common Language Runtime), která vytvoří instanci vlastního zařazovače. Řetězec předaný GetInstance je soubor cookie, který metoda může 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žít MarshalAsAttribute

Chcete-li použít vlastní marshaller, musíte MarshalAsAttribute použít atribut na parametr nebo pole, které se zařazují.

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 vlastní marshaller není definován v sestavení, ve kterém se používá, je nutné zadat název sestavení, ve kterém je definován.

    Poznámka:

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

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

Atribut MarshalAsAttribute identifikuje vlastní marshaller, aby mohl aktivovat odpovídající 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).

Modul runtime pak zavolá MarshalNativeToManaged metody vlastního MarshalManagedToNative marshalleru, aby aktivoval správnou obálku pro zpracování volání.

Použití vlastního marshalleru

Po dokončení vlastního marshalleru ho můžete použít jako vlastní 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 povolení nespravovaných klientských aplikací 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 zadaným MarshalAsAttribute atributem hodnota UnmanagedType.CustomMarshalervýčtu UnmanagedType.CustomMarshaler .

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