System.Object として型指定されているパラメーターおよびフィールドを、次のいずれかの型としてアンマネージ コードに公開できます。
オブジェクトがパラメーターの場合にはバリアント。
オブジェクトが構造体フィールドの場合にはインターフェイス。
オブジェクト型のマーシャリングは COM 相互運用機能のみでサポートされます。 既定の動作では、オブジェクトは COM バリアントにマーシャリングされます。 これらの規則は Object 型にのみ適用され、 Object クラスから派生する厳密に型指定されたオブジェクトには適用されません。
マーシャリング オプション
次の表に、 Object データ型のマーシャリング オプションを示します。
MarshalAsAttribute 属性は、オブジェクトをマーシャリングするための UnmanagedType 列挙値をいくつか提供します。
| 列挙型 | アンマネージ形式の説明 |
|---|---|
|
UnmanagedType.Struct (パラメーターの既定値) |
COM スタイルのバリアント。 |
| UnmanagedType.Interface | 可能な場合は IDispatch インターフェイス。それ以外の場合は IUnknown インターフェイス。 |
|
UnmanagedType.IUnknown (フィールドの既定値) |
IUnknown インターフェイスです。 |
| UnmanagedType.IDispatch |
IDispatch インターフェイスです。 |
次の例は、MarshalObject のマネージド インターフェイス定義を示しています。
Interface MarshalObject
Sub SetVariant(o As Object)
Sub SetVariantRef(ByRef o As Object)
Function GetVariant() As Object
Sub SetIDispatch( <MarshalAs(UnmanagedType.IDispatch)> o As Object)
Sub SetIDispatchRef(ByRef <MarshalAs(UnmanagedType.IDispatch)> o _
As Object)
Function GetIDispatch() As <MarshalAs(UnmanagedType.IDispatch)> Object
Sub SetIUnknown( <MarshalAs(UnmanagedType.IUnknown)> o As Object)
Sub SetIUnknownRef(ByRef <MarshalAs(UnmanagedType.IUnknown)> o _
As Object)
Function GetIUnknown() As <MarshalAs(UnmanagedType.IUnknown)> Object
End Interface
interface MarshalObject {
void SetVariant(Object o);
void SetVariantRef(ref Object o);
Object GetVariant();
void SetIDispatch ([MarshalAs(UnmanagedType.IDispatch)]Object o);
void SetIDispatchRef([MarshalAs(UnmanagedType.IDispatch)]ref Object o);
[MarshalAs(UnmanagedType.IDispatch)] Object GetIDispatch();
void SetIUnknown ([MarshalAs(UnmanagedType.IUnknown)]Object o);
void SetIUnknownRef([MarshalAs(UnmanagedType.IUnknown)]ref Object o);
[MarshalAs(UnmanagedType.IUnknown)] Object GetIUnknown();
}
次のコードでは、MarshalObject インターフェイスをタイプ ライブラリにエクスポートします。
interface MarshalObject {
HRESULT SetVariant([in] VARIANT o);
HRESULT SetVariantRef([in,out] VARIANT *o);
HRESULT GetVariant([out,retval] VARIANT *o)
HRESULT SetIDispatch([in] IDispatch *o);
HRESULT SetIDispatchRef([in,out] IDispatch **o);
HRESULT GetIDispatch([out,retval] IDispatch **o)
HRESULT SetIUnknown([in] IUnknown *o);
HRESULT SetIUnknownRef([in,out] IUnknown **o);
HRESULT GetIUnknown([out,retval] IUnknown **o)
}
注
相互運用マーシャラーは、バリアント内に割り当てられたオブジェクトがある場合は、呼び出しの後で自動的にそのオブジェクトを解放します。
次の例は、フォーマットされた値型を示しています。
Public Structure ObjectHolder
Dim o1 As Object
<MarshalAs(UnmanagedType.IDispatch)> Public o2 As Object
End Structure
public struct ObjectHolder {
Object o1;
[MarshalAs(UnmanagedType.IDispatch)]public Object o2;
}
次のコードでは、フォーマットされた型をタイプ ライブラリにエクスポートします。
struct ObjectHolder {
VARIANT o1;
IDispatch *o2;
}
インターフェイスへのオブジェクトのマーシャリング
オブジェクトがインターフェイスとして COM に公開されている場合、そのインターフェイスはマネージド型 Object ( _Object インターフェイス) のクラス インターフェイスです。 このインターフェイスは、結果のタイプ ライブラリで IDispatch (UnmanagedType) または IUnknown (UnmanagedType.IUnknown) として型指定されます。 COM クライアントは、マネージド クラスのメンバー、または派生クラスによって実装されたメンバーを、 _Object インターフェイスを介して動的に呼び出すことができます。 また、クライアントは QueryInterface を呼び出して、マネージド型によって明示的に実装されているその他のインターフェイスを取得することもできます。
バリアントへのオブジェクトのマーシャリング
オブジェクトがバリアントにマーシャリングされると、内部バリアント型は、次の規則に基づいて実行時に決定されます。
オブジェクト参照が null (Visual Basic では Nothing) の場合、オブジェクトは VT_EMPTY 型のバリアントにマーシャリングされます。
オブジェクトが、次の表にリストされているいずれかの型のインスタンスである場合、結果として生成されるバリアント型は、表に示されている、マーシャラーに組み込まれている規則によって決定されます。
マーシャリング動作を明示的に制御する必要があるその他のオブジェクトは、IConvertible インターフェイスを実装できます。 その場合、バリアント型は IConvertible.GetTypeCode メソッドから返される型コードによって決定されます。 それ以外の場合、オブジェクトは VT_UNKNOWN 型のバリアントとしてマーシャリングされます。
バリアントへのシステム型のマーシャリング
次の表に、マネージド オブジェクト型とそれに対応する COM バリアント型を示します。 これらの型は、呼び出されるメソッドのシグネチャが System.Object 型の場合にのみ変換されます。
| オブジェクトの種類 | COM バリアント型 |
|---|---|
| null オブジェクト参照 (Visual Basic では Nothing)。 | VT_EMPTY |
| System.DBNull | VT_NULL |
| System.Runtime.InteropServices.ErrorWrapper | VT_ERROR |
| System.Reflection.Missing | VT_ERROR と E_PARAMNOTFOUND |
| System.Runtime.InteropServices.DispatchWrapper | VT_DISPATCH |
| System.Runtime.InteropServices.UnknownWrapper | VT_UNKNOWN |
| System.Runtime.InteropServices.CurrencyWrapper | VT_CY |
| System.Boolean | VT_BOOL |
| System.SByte | VT_I1 |
| System.Byte | VT_UI1 |
| System.Int16 | VT_I2 |
| System.UInt16 | VT_UI2 |
| System.Int32 | VT_I4 |
| System.UInt32 | VT_UI4 |
| System.Int64 | VT_I8 |
| System.UInt64 | VT_UI8 |
| System.Single | VT_R4 |
| System.Double | VT_R8 |
| System.Decimal | VT_DECIMAL |
| System.DateTime | VT_DATE |
| System.String | VT_BSTR |
| System.IntPtr | VT_INT |
| System.UIntPtr | VT_UINT |
| System.Array | VT_ARRAY |
上の例で定義した MarshalObject インターフェイスを使用して、次のコード例ではさまざまな型のバリアントを COM サーバーに渡す方法を示します。
Dim mo As New MarshalObject()
mo.SetVariant(Nothing) ' Marshal as variant of type VT_EMPTY.
mo.SetVariant(System.DBNull.Value) ' Marshal as variant of type VT_NULL.
mo.SetVariant(CInt(27)) ' Marshal as variant of type VT_I2.
mo.SetVariant(CLng(27)) ' Marshal as variant of type VT_I4.
mo.SetVariant(CSng(27.0)) ' Marshal as variant of type VT_R4.
mo.SetVariant(CDbl(27.0)) ' Marshal as variant of type VT_R8.
MarshalObject mo = new MarshalObject();
mo.SetVariant(null); // Marshal as variant of type VT_EMPTY.
mo.SetVariant(System.DBNull.Value); // Marshal as variant of type VT_NULL.
mo.SetVariant((int)27); // Marshal as variant of type VT_I2.
mo.SetVariant((long)27); // Marshal as variant of type VT_I4.
mo.SetVariant((single)27.0); // Marshal as variant of type VT_R4.
mo.SetVariant((double)27.0); // Marshal as variant of type VT_R8.
ErrorWrapper、DispatchWrapper、UnknownWrapper、CurrencyWrapper などのラッパー クラスを使用すると、対応するマネージド型を持たない COM 型をマーシャリングできます。 次のコード例では、これらのラッパーを使用して、さまざまな型のバリアントを COM サーバーに渡す方法を示します。
Imports System.Runtime.InteropServices
' Pass inew as a variant of type VT_UNKNOWN interface.
mo.SetVariant(New UnknownWrapper(inew))
' Pass inew as a variant of type VT_DISPATCH interface.
mo.SetVariant(New DispatchWrapper(inew))
' Pass a value as a variant of type VT_ERROR interface.
mo.SetVariant(New ErrorWrapper(&H80054002))
' Pass a value as a variant of type VT_CURRENCY interface.
mo.SetVariant(New CurrencyWrapper(New Decimal(5.25)))
using System.Runtime.InteropServices;
// Pass inew as a variant of type VT_UNKNOWN interface.
mo.SetVariant(new UnknownWrapper(inew));
// Pass inew as a variant of type VT_DISPATCH interface.
mo.SetVariant(new DispatchWrapper(inew));
// Pass a value as a variant of type VT_ERROR interface.
mo.SetVariant(new ErrorWrapper(0x80054002));
// Pass a value as a variant of type VT_CURRENCY interface.
mo.SetVariant(new CurrencyWrapper(new Decimal(5.25)));
ラッパー クラスは、System.Runtime.InteropServices 名前空間で定義されます。
バリアントへの IConvertible インターフェイスのマーシャリング
前のセクションでリストしたもの以外の型は、IConvertible インターフェイスを実装することにより、型のマーシャリング方法を制御できます。 オブジェクトがIConvertible インターフェイスを実装する場合、COM バリアント型は実行時に、TypeCode メソッドから返されるIConvertible.GetTypeCode列挙体の値によって決定されます。
次の表に、 TypeCode 列挙体で使用できる値と、各値に対応する COM バリアント型を示します。
| タイプコード | COM バリアント型 |
|---|---|
| TypeCode.Empty | VT_EMPTY |
| TypeCode.Object | VT_UNKNOWN |
| TypeCode.DBNull | VT_NULL |
| TypeCode.Boolean | VT_BOOL |
| TypeCode.Char | VT_UI2 |
| TypeCode.Sbyte | VT_I1 |
| TypeCode.Byte | VT_UI1 |
| TypeCode.Int16 | VT_I2 |
| TypeCode.UInt16 | VT_UI2 |
| TypeCode.Int32 | VT_I4 |
| TypeCode.UInt32 | VT_UI4 |
| TypeCode.Int64 | VT_I8 |
| TypeCode.UInt64 | VT_UI8 |
| TypeCode.Single | VT_R4 |
| TypeCode.Double | VT_R8 |
| TypeCode.Decimal | VT_DECIMAL |
| TypeCode.DateTime | VT_DATE |
| TypeCode.String | VT_BSTR |
| サポートされていません。 | VT_INT |
| サポートされていません。 | VT_UINT |
| サポートされていません。 | VT_ARRAY |
| サポートされていません。 | VT_RECORD |
| サポートされていません。 | VT_CY |
| サポートされていません。 | VT_VARIANT |
COM バリアントの値は 、IConvertible.To型 インターフェイスを呼び出すことによって決定されます。ここで、 ToType は IConvertible.GetTypeCode から返された型に対応する変換ルーチンです。 たとえば、IConvertible.GetTypeCode から TypeCode.Double を返すオブジェクトは、VT_R8 型の COM バリアントとしてマーシャリングされます。
dblVal インターフェイスにキャストし、IConvertible メソッドを呼び出すことで、バリアントの値 (COM バリアントの ToDouble フィールドに格納) を取得できます。
オブジェクトへのバリアントのマーシャリング
バリアントをオブジェクトにマーシャリングする場合、マーシャリングされるバリアントの型、および場合によっては値で、生成されるオブジェクトの型が決まります。 次の表に、各バリアント型とそれに対応するオブジェクト型を示します。オブジェクト型はバリアントが COM から .NET Framework に渡されるときにマーシャラーによって作成されます。
| COM バリアント型 | オブジェクトの種類 |
|---|---|
| VT_EMPTY | null オブジェクト参照 (Visual Basic では Nothing)。 |
| VT_NULL | System.DBNull |
| VT_DISPATCH | System.__ComObject、または (pdispVal == null) の場合は null |
| VT_UNKNOWN | System.__ComObject、または (punkVal == null) の場合は null |
| VT_ERROR | System.UInt32 |
| VT_BOOL | System.Boolean |
| VT_I1 | System.SByte |
| VT_UI1 | System.Byte |
| VT_I2 | System.Int16 |
| VT_UI2 | System.UInt16 |
| VT_I4 | System.Int32 |
| VT_UI4 | System.UInt32 |
| VT_I8 | System.Int64 |
| VT_UI8 | System.UInt64 |
| VT_R4 | System.Single |
| VT_R8 | System.Double |
| VT_DECIMAL | System.Decimal |
| VT_DATE | System.DateTime |
| VT_BSTR | System.String |
| VT_INT | System.Int32 |
| VT_UINT | System.UInt32 |
| VT_ARRAY | VT_* | System.Array |
| VT_CY | System.Decimal |
| VT_RECORD | 対応するボックス化された値型。 |
| VT_VARIANT | サポートされていません。 |
COM からマネージド コードに渡された後で COM に返されるバリアント型が、呼び出し中に同じバリアント型を維持しないことがあります。
VT_DISPATCH型のバリアントが COM から .NET Framework に渡されるとどうなるかを考えてみましょう。 マーシャリング時に、バリアントは System.Object に変換されます。 その後、 Object が COM に戻されると、 VT_UNKNOWN型のバリアントにマーシャリングされます。 オブジェクトをマネージド コードから COM にマーシャリングするときに、生成されるバリアントの型が、最初にオブジェクトを生成するときに使用したバリアントの型と同じになる保証はありません。
ByRef バリアントのマーシャリング
バリアント自体は値または参照によって渡すことができますが、 VT_BYREF フラグを任意のバリアント型と共に使用して、バリアントの内容が値ではなく参照渡しされていることを示すこともできます。 参照によるバリアントのマーシャリングと、 VT_BYREF フラグが設定されたバリアントのマーシャリングの違いは、混乱を招く可能性があります。 その違いを次の図で明確にします。
値渡しされるバリアントと参照渡しされるバリアント
オブジェクトとバリアントを値渡しでマーシャリングする場合の既定の動作
オブジェクトをマネージド コードから COM に渡す場合、そのオブジェクトの内容は、「バリアントへのオブジェクトのマーシャリング」で定義されている規則を使用して、マーシャラーによって作成される新しいバリアントにコピーされます。 アンマネージ側でバリアントに対して行われた変更の内容は、呼び出しから制御が返されるときに、元のオブジェクトには反映されません。
バリアントを COM からマネージド コードに渡す場合、そのバリアントの内容は、「オブジェクトへのバリアントのマーシャリング」で定義されている規則を使用して、新規作成されるオブジェクトにコピーされます。 マネージド側でオブジェクトに対して行われた変更の内容は、呼び出しから制御が返されるときに、元のバリアントには反映されません。
オブジェクトとバリアントを参照渡しでマーシャリングする場合の既定の動作
変更内容を呼び出し元に反映させるには、パラメーターを参照渡しする必要があります。 たとえば、C# の ref キーワード (または Visual Basic マネージド コードの ByRef ) を使用して、パラメーターを参照渡しできます。 COM の場合、参照パラメーターは variant * などのポインターを使用して渡されます。
オブジェクトを COM に参照渡しする場合、マーシャラーは呼び出しを行う前に新しいバリアントを作成し、オブジェクト参照の内容をそのバリアントにコピーします。 このバリアントはアンマネージ関数に渡されます。ここで、バリアントの内容を自由に変更できます。 呼び出しから制御が返されるときに、アンマネージ側でバリアントが変更されている場合には、その内容が元のオブジェクトに反映されます。 バリアントの型が、呼び出しに渡されたバリアントの型と異なる場合、変更内容は別の型のオブジェクトに反映されます。 つまり、呼び出しに渡したオブジェクトの型が、呼び出しから返されるオブジェクトの型と異なることがあります。
バリアントをマネージド コードに参照渡しする場合、マーシャラーは呼び出しを行う前に、新しいオブジェクトを作成し、バリアントの内容をそのオブジェクトにコピーします。 オブジェクトへの参照がマネージド関数に渡されます。ここで、オブジェクトを自由に変更できます。 呼び出しから制御が返されるときに、参照先オブジェクトが変更されている場合には、その内容が元のバリアントに反映されます。 オブジェクトの型が、呼び出しに渡されたオブジェクトの型と異なる場合、元のバリアントの型が変更され、値がそのバリアントに反映されます。 ここでも、呼び出しに渡されたバリアントの型が、呼び出しから返されるバリアントの型と異なることがあります。
VT_BYREF フラグの設定によるバリアントのマーシャリングの既定の動作
値によってマネージ コードに渡されるバリアントには、バリアントに値ではなく参照が含まれていることを示す
VT_BYREFフラグを設定できます。 この場合でも、バリアントは値渡しされるため、オブジェクトにマーシャリングされます。 呼び出しを行う前に、マーシャラーは自動的にバリアントの内容を逆参照し、その内容を新しく作成されるオブジェクトにコピーします。 その後、オブジェクトはマネージド関数に渡されます。ただし、呼び出しから制御が返されるときに、このオブジェクトは元のバリアントには反映されません。 マネージド オブジェクトに対する変更内容は失われます。注意事項
バリアントに
VT_BYREFフラグが設定されている場合でも、値渡しされたバリアントの値を変更する方法はありません。参照によってマネージ コードに渡されるバリアントには、バリアントに別の参照が含まれていることを示す
VT_BYREFフラグを設定することもできます。 その場合、バリアントは参照渡しされているため、バリアントはrefオブジェクトにマーシャリングされます。 呼び出しを行う前に、マーシャラーは自動的にバリアントの内容を逆参照し、その内容を新しく作成されるオブジェクトにコピーします。 呼び出しから制御が返されるときに、オブジェクトの値が元のバリアント内の参照に反映されるのは、そのオブジェクトの型が渡されたオブジェクトの型と同じ場合に限られます。 つまり、反映によって、VT_BYREFフラグが設定されたバリアントの型は変更されません。 呼び出しの間にオブジェクトの型が変更された場合、呼び出しから制御が返されるときに InvalidCastException が発生します。
バリアントとオブジェクトに関する反映規則を次の表にまとめます。
| より | 終了 | 変更内容の反映 |
|---|---|---|
| バリアントv | オブジェクトo | 決してない |
| オブジェクトo | バリアントv | 決してない |
| * | Ref オブジェクトo | 常時 |
| Ref オブジェクトo | * | 常時 |
| バリアントv(VT_BYREF|VT_*) | オブジェクトo | 決してない |
| バリアントv(VT_BYREF|VT_) | Ref オブジェクトo | 型が変更されていない場合のみ。 |
関連項目
.NET