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.CustomMarshaler
výč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"
).