ICustomMarshaler Antarmuka

Definisi

Menyediakan pembungkus kustom untuk menangani panggilan metode.

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
Turunan
Atribut

Keterangan

Antarmuka ICustomMarshaler menyediakan pembungkus kustom untuk menangani panggilan metode.

Marshaller menyediakan jembatan antara fungsionalitas antarmuka lama dan baru. Marshaling kustom memberikan keuntungan berikut:

  • Ini memungkinkan aplikasi klien yang dirancang untuk bekerja dengan antarmuka lama untuk juga bekerja dengan server yang menerapkan antarmuka baru.
  • Ini memungkinkan aplikasi klien yang dibangun untuk bekerja dengan antarmuka baru untuk bekerja dengan server yang mengimplementasikan antarmuka lama.

Jika Anda memiliki antarmuka yang memperkenalkan perilaku marshaling yang berbeda atau yang diekspos ke Model Objek Komponen (COM) dengan cara yang berbeda, Anda dapat merancang marshaller kustom alih-alih menggunakan marshaller interop. Dengan menggunakan marshaller kustom, Anda dapat meminimalkan perbedaan antara komponen .NET baru dan komponen COM yang ada.

Misalnya, Anda mengembangkan antarmuka terkelola yang disebut INew. Ketika antarmuka ini diekspos ke COM melalui pembungkus panggilan COM standar (CCW), antarmuka ini memiliki metode yang sama dengan antarmuka terkelola dan mengikuti aturan pemrosesan yang terintegrasi dalam marshaller interop. Sekarang misalkan antarmuka COM terkenal yang disebut IOld sudah menyediakan fungsionalitas yang sama dengan INew antarmuka. Dengan merancang marshaller kustom, Anda dapat memberikan implementasi IOld yang tidak terkelola yang hanya mendelegasikan panggilan ke antarmuka INew yang terkelola. Oleh karena itu, marshaller kustom bertindak sebagai jembatan antara antarmuka yang terkelola dan tidak terkelola.

Note

Marshaller kustom tidak dipanggil saat memanggil dari kode terkelola ke kode yang tidak dikelola pada antarmuka khusus pengiriman.

Tetapkan jenis marshaling

Sebelum Anda dapat membangun marshaller kustom, Anda harus menentukan antarmuka terkelola dan tidak terkelola yang akan di-marshal. Antarmuka ini biasanya melakukan fungsi yang sama tetapi diekspos secara berbeda dengan objek yang dikelola dan tidak dikelola.

Kompiler terkelola menghasilkan antarmuka terkelola dari metadata, dan antarmuka yang dihasilkan terlihat seperti antarmuka terkelola lainnya. Contoh berikut menunjukkan antarmuka umum.

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

Anda menentukan jenis yang tidak dikelola dalam Bahasa Definisi Antarmuka (IDL) dan mengkompilasinya dengan pengkompilasi Microsoft Interface Definition Language (MIDL). Anda menentukan antarmuka dalam pernyataan pustaka dan menetapkanNYA ID antarmuka dengan atribut pengidentifikasi unik universal (UUID), seperti yang ditunjukkan contoh berikut.

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

Pengkompilasi MIDL menghasilkan beberapa file output. Jika antarmuka didefinisikan dalam Old.idl, file output Old_i.c menentukan const variabel dengan pengidentifikasi antarmuka (IID) antarmuka, seperti yang ditunjukkan contoh berikut.

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

File Old.h juga diproduksi oleh MIDL. Ini berisi definisi C++ antarmuka yang dapat disertakan dalam kode sumber C++Anda.

Menerapkan antarmuka ICustomMarshaler

Marshaller kustom Anda harus mengimplementasikan ICustomMarshaler antarmuka untuk menyediakan pembungkus yang sesuai ke runtime.

Kode C# berikut menampilkan antarmuka dasar yang harus diimplementasikan oleh semua marshaller kustom.

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

Antarmuka ICustomMarshaler mencakup metode yang menyediakan dukungan konversi, dukungan penataan, dan informasi tentang data yang akan dipindahkan.

Jenis operasi Metode ICustomMarshaler Description
Konversi (dari asli ke kode terkelola) MarshalNativeToManaged Mengompilasi penunjuk ke data bawaan menjadi objek terkelola. Metode ini mengembalikan pembungkus panggilan runtime kustom (RCW) yang dapat memproses antarmuka tak dikelola yang diteruskan sebagai argumen. Marshaller harus mengembalikan instance RCW kustom untuk jenis tersebut.
Konversi (dari kode yang dikelola ke kode asli) MarshalManagedToNative Mengatur objek yang dikelola menjadi pointer ke data native. Metode ini mengembalikan pembungkus yang dapat dipanggil COM kustom (CCW) yang dapat mengelola antarmuka terkelola yang diteruskan sebagai parameter. Marshaller harus mengembalikan instance CCW kustom untuk jenis tersebut.
Pembersihan (kode lokal) CleanUpNativeData Memungkinkan marshaller membersihkan data asli (CCW) yang dikembalikan oleh MarshalManagedToNative metode .
Pembersihan (kode yang dikelola) CleanUpManagedData Memungkinkan marshaller untuk membersihkan data terkelola (RCW) yang dikembalikan oleh metode MarshalNativeToManaged.
Informasi (tentang kode asli) GetNativeDataSize Mengembalikan ukuran data yang tidak dikelola untuk di-marshal.

Konversi

ICustomMarshaler.MarshalNativeToManaged

Mengompilasi penunjuk ke data bawaan menjadi objek terkelola. Metode ini mengembalikan pembungkus panggilan runtime kustom (RCW) yang dapat memproses antarmuka tak dikelola yang diteruskan sebagai argumen. Marshaller harus mengembalikan instance RCW kustom untuk jenis tersebut.

ICustomMarshaler.MarshalManagedToNative

Mengatur objek yang dikelola menjadi pointer ke data native. Metode ini mengembalikan pembungkus yang dapat dipanggil COM kustom (CCW) yang dapat mengelola antarmuka terkelola yang diteruskan sebagai parameter. Marshaller harus mengembalikan instance CCW kustom untuk jenis tersebut.

Cleanup

ICustomMarshaler.CleanUpNativeData

Memungkinkan marshaller membersihkan data asli (CCW) yang dikembalikan oleh MarshalManagedToNative metode .

ICustomMarshaler.CleanUpManagedData

Memungkinkan marshaller untuk membersihkan data terkelola (RCW) yang dikembalikan oleh metode MarshalNativeToManaged.

Informasi ukuran

ICustomMarshaler.GetNativeDataSize

Mengembalikan ukuran data yang tidak dikelola untuk di-marshal.

Note

Jika marshaller kustom memanggil metode apa pun yang mengatur kesalahan P/Invoke terakhir saat melakukan marshaling dari native ke managed atau saat proses pembersihan, nilai yang dikembalikan oleh Marshal.GetLastWin32Error() dan Marshal.GetLastPInvokeError() akan mewakili panggilan dalam operasi marshaling atau pembersihan tersebut. Ini dapat menyebabkan kesalahan tidak terdeteksi saat memakai marshaller khusus dengan P/Invokes dengan DllImportAttribute.SetLastError diatur ke true. Untuk mempertahankan kesalahan P/Invoke terakhir, gunakan metode Marshal.GetLastPInvokeError() dan Marshal.SetLastPInvokeError(Int32) dalam implementasi ICustomMarshaler.

Menerapkan metode GetInstance

Selain menerapkan ICustomMarshaler antarmuka, marshaller kustom harus menerapkan metode static yang disebut GetInstance yang menerima String sebagai parameter dan memiliki jenis pengembalian ICustomMarshaler. Metode static ini dipanggil oleh lapisan COM interop dari Common Language Runtime (CLR) untuk menginisiasi sebuah instance dari marshaller kustom. String yang diteruskan ke GetInstance adalah cookie yang dapat digunakan metode untuk menyesuaikan marshaller kustom yang dikembalikan. Contoh berikut menunjukkan implementasi minimal, tetapi lengkap ICustomMarshaler .

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();
}

Terapkan MarshalAsAttribute

Untuk menggunakan marshaller kustom, Anda harus menerapkan atribut MarshalAsAttribute ke parameter atau bidang yang sedang dimarshall.

Anda harus meneruskan nilai enumerasi UnmanagedType.CustomMarshaler ke konstruktor MarshalAsAttribute juga. Selain itu, Anda harus menentukan MarshalType kolom dengan salah satu parameter bernama berikut:

  • MarshalType (wajib): Nama marshaller kustom yang memenuhi syarat rakitan. Nama harus menyertakan namespace dan kelas marshaller kustom. Jika marshaler kustom tidak didefinisikan dalam rakitan yang digunakannya, Anda harus menentukan nama rakitan tempat marshaler tersebut didefinisikan.

    Note

    Anda dapat menggunakan bidang MarshalTypeRef alih-alih bidang MarshalType. MarshalTypeRef menggunakan tipe yang lebih mudah ditentukan.

  • MarshalCookie (opsional): Cookie yang diteruskan ke marshaller kustom. Anda dapat menggunakan cookie untuk memberikan informasi tambahan kepada marshaller. Misalnya, jika marshaller yang sama digunakan untuk menyediakan sejumlah pembungkus, cookie mengidentifikasi pembungkus yang spesifik. Cookie diteruskan ke metode GetInstance dari marshaller.

Atribut MarshalAsAttribute mengidentifikasi marshaller kustom sehingga dapat mengaktifkan pembungkus yang sesuai. Layanan interoperabilitas dari runtime bahasa umum kemudian memeriksa atribut dan membuat marshaler kustom pada saat pertama kali argumen (parameter atau bidang) perlu diproses.

Runtime kemudian memanggil metode MarshalNativeToManaged dan MarshalManagedToNative pada marshaller kustom untuk mengaktifkan pembungkus yang benar untuk menangani panggilan.

Menggunakan marshaller kustom

Ketika marshaller kustom sudah selesai, Anda dapat menggunakannya sebagai pembungkus khusus untuk jenis tertentu. Contoh berikut menunjukkan definisi antarmuka terkelola IUserData :

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

Dalam contoh berikut, antarmuka IUserData menggunakan marshaller kustom NewOldMarshaler untuk memungkinkan aplikasi klien unmanaged meneruskan antarmuka IOld ke metode DoSomeStuff. Deskripsi managed dari DoSomeStuff metode ini mengambil antarmuka INew, seperti yang ditunjukkan pada contoh sebelumnya, sedangkan versi unmanaged DoSomeStuff mengambil penunjuk antarmuka IOld, seperti yang ditunjukkan dalam contoh berikut.

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

Pustaka tipe yang dihasilkan dengan mengekspor definisi IUserData terkelola menghasilkan definisi yang tidak dikelola seperti yang ditunjukkan dalam contoh ini, bukan definisi standar. Atribut MarshalAsAttribute yang diterapkan ke INew argumen dalam definisi terkelola metode DoSomeStuff menunjukkan bahwa argumen menggunakan marshaller kustom, seperti yang ditunjukkan contoh berikut.

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

Dalam contoh sebelumnya, parameter pertama yang disediakan untuk atribut MarshalAsAttribute adalah nilai enumerasi UnmanagedType.CustomMarshalerUnmanagedType.CustomMarshaler.

Parameter kedua adalah bidang MarshalType, yang menyediakan nama marshaller kustom yang memenuhi syarat rakitan. Nama ini terdiri dari namespace dan kelas marshaller kustom (MarshalType="MyCompany.NewOldMarshaler").

Metode

Nama Deskripsi
CleanUpManagedData(Object)

Melakukan pembersihan data terkelola yang diperlukan saat tidak lagi diperlukan.

CleanUpNativeData(IntPtr)

Melakukan pembersihan data yang tidak terkelola yang diperlukan saat tidak lagi diperlukan.

GetNativeDataSize()

Mengembalikan ukuran data asli yang akan dirusak.

MarshalManagedToNative(Object)

Mengonversi data terkelola menjadi data yang tidak dikelola.

MarshalNativeToManaged(IntPtr)

Mengonversi data yang tidak dikelola ke data terkelola.

Berlaku untuk