ICustomMarshaler Rozhraní
Definice
Důležité
Některé informace platí pro předběžně vydaný produkt, který se může zásadně změnit, než ho výrobce nebo autor vydá. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
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á
GetInstancemetodě 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. |