既定のマーシャリングの動作Default Marshaling Behavior

相互運用マーシャリングは、メソッドのパラメーターに関連付けられたデータが、マネージド メモリとアンマネージド メモリの間で渡されるときに、どのように動作するかを指示する規則に従って機能します。Interop marshaling operates on rules that dictate how data associated with method parameters behaves as it passes between managed and unmanaged memory. これらの組み込みの規則は、データ型の変換などのマーシャリング動作、呼び出し先が渡されたデータを変更してその変更を呼び出し元にこ返すことが可能かどうか、およびどのような状況のときにマーシャラーがパフォーマンスの最適化を実現するかを制御します。These built-in rules control such marshaling activities as data type transformations, whether a callee can change data passed to it and return those changes to the caller, and under which circumstances the marshaler provides performance optimizations.

このセクションでは、相互運用マーシャリング サービスの既定の動作特性を示します。This section identifies the default behavioral characteristics of the interop marshaling service. ここでは、配列、ブール型、char 型、デリゲート、クラス、オブジェクト、文字列、および構造体のマーシャリングに関する詳細情報を示します。It presents detailed information on marshaling arrays, Boolean types, char types, delegates, classes, objects, strings, and structures.

注意

ジェネリック型のマーシャリングはサポートされていません。Marshaling of generic types is not supported. 詳しくは、「ジェネリック型を使用する相互運用」を参照してください。For more information see, Interoperating Using Generic Types.

相互運用マーシャラーによるメモリ管理Memory management with the interop marshaler

相互運用マーシャラーは、アンマネージ コードによって割り当てられたメモリを常に解放しようとします。The interop marshaler always attempts to free memory allocated by unmanaged code. この動作は、COM メモリの管理規則に準拠していますが、ネイティブ C++ を制御する規則とは異なります。This behavior complies with COM memory management rules, but differs from the rules that govern native C++.

ネイティブ C++ の動作 (メモリを解放しない) を予期している場合、ポインターのメモリを自動的に解放するプラットフォーム呼び出しを使用すると、混乱が生じることがあります。Confusion can arise if you anticipate native C++ behavior (no memory freeing) when using platform invoke, which automatically frees memory for pointers. たとえば、C++ DLL からの次のアンマネージ メソッドを呼び出しても、メモリは自動的に解放されません。For example, calling the following unmanaged method from a C++ DLL does not automatically free any memory.

アンマネージ シグネチャUnmanaged signature

BSTR MethodOne (BSTR b) {  
     return b;  
}  

ただし、メソッドをプラットフォーム呼び出しのプロトタイプとして定義する場合は、各 BSTR 型を String 型に置き換えて、MethodOne を呼び出します。共通言語ランタイムは、b の解放を 2 回試行します。However, if you define the method as a platform invoke prototype, replace each BSTR type with a String type, and call MethodOne, the common language runtime attempts to free b twice. String 型ではなく IntPtr 型を使用することにより、マーシャリングの動作を変更できます。You can change the marshaling behavior by using IntPtr types rather than String types.

ランタイムは、常に CoTaskMemFree メソッドを使用してメモリを解放します。The runtime always uses the CoTaskMemFree method to free memory. 使用しているメモリが CoTaskMemAlloc メソッドで割り当てられていない場合、IntPtr を使用し、適切なメソッドを使用して手動でメモリを解放する必要があります。If the memory you are working with was not allocated with the CoTaskMemAlloc method, you must use an IntPtr and free the memory manually using the appropriate method. 同様に、カーネル メモリへのポインターを返す GetCommandLine 関数を Kernel32.dll から使用するときなど、メモリを解放してはいけない状況のときには、自動的なメモリの解放を防止できます。Similarly, you can avoid automatic memory freeing in situations where memory should never be freed, such as when using the GetCommandLine function from Kernel32.dll, which returns a pointer to kernel memory. 手動でメモリを解放する方法について詳しくは、「Buffers サンプル」を参照してください。For details on manually freeing memory, see the Buffers Sample.

クラスに対する既定のマーシャリングDefault marshaling for classes

クラスは、COM 相互運用でのみマーシャリングすることができ、常にインターフェイスとしてマーシャリングされます。Classes can be marshaled only by COM interop and are always marshaled as interfaces. クラスをマーシャリングするために使用されるインターフェイスが、クラス インターフェイスと呼ばれる場合があります。In some cases the interface used to marshal the class is known as the class interface. クラス インターフェイスを任意のインターフェイスでオーバーライドする方法について詳しくは、「クラス インターフェイスの概要」をご覧ください。For information about overriding the class interface with an interface of your choice, see Introducing the class interface.

クラスを COM に渡すPassing Classes to COM

マネージド クラスが COM に渡されると、相互運用マーシャラーは自動的にクラスを COM プロキシでラップし、プロキシによって生成されたクラス インターフェイスを COM メソッド呼び出しに渡します。When a managed class is passed to COM, the interop marshaler automatically wraps the class with a COM proxy and passes the class interface produced by the proxy to the COM method call. その後、プロキシは、クラス インターフェイス上のすべての呼び出しを、マネージド オブジェクトにデリゲートして戻します。The proxy then delegates all calls on the class interface back to the managed object. プロキシはまた、クラスによって明示的に実装されていない他のインターフェイスも公開します。The proxy also exposes other interfaces that are not explicitly implemented by the class. プロキシは、クラスの代わりに、IUnknownIDispatch などのインターフェイスを自動的に実装します。The proxy automatically implements interfaces such as IUnknown and IDispatch on behalf of the class.

クラスを .NET Code に渡すPassing Classes to .NET Code

コクラスは、通常、COM のメソッド引数として使用されません。Coclasses are not typically used as method arguments in COM. 代わりに、通常は既定のインターフェイスがコクラスの代わりに渡されます。Instead, a default interface is usually passed in place of the coclass.

インターフェイスがマネージド コードに渡されると、相互運用マーシャラーは、インターフェイスを適切なラッパーでラップし、そのラッパーをマネージド メソッドに渡すことを担当します。When an interface is passed into managed code, the interop marshaler is responsible for wrapping the interface with the proper wrapper and passing the wrapper to the managed method. どのラッパーを使用するかは難しい判断となることがあります。Determining which wrapper to use can be difficult. COM オブジェクトのすべてのインスタンスは、オブジェクトが実装するインターフェイスの数に関係なく、1 つの一意のラッパーを持ちます。Every instance of a COM object has a single, unique wrapper, no matter how many interfaces the object implements. たとえば、5 つの異なるインターフェイスを実装する 1 つの COM オブジェクトには 1 つのラッパーだけがあります。For example, a single COM object that implements five distinct interfaces has only one wrapper. 同一のラッパーが、5 つのすべてのインターフェイスを公開します。The same wrapper exposes all five interfaces. COM オブジェクトの 2 つのインスタンスが作成される場合、ラッパーの 2 つのインスタンスが作成されます。If two instances of the COM object are created, then two instances of the wrapper are created.

ラッパーがその有効期間中は同じ型を維持するように、相互運用マーシャラーは、オブジェクトによって公開されるインターフェイスが初めてマーシャラーを介して渡されるときに、正しいラッパーを識別する必要があります。For the wrapper to maintain the same type throughout its lifetime, the interop marshaler must identify the correct wrapper the first time an interface exposed by the object is passed through the marshaler. マーシャラーは、オブジェクトが実装するインターフェイスの 1 つに注目することにより、オブジェクトを識別します。The marshaler identifies the object by looking at one of the interfaces the object implements.

たとえば、マーシャラーは、マネージド コードに渡されたインターフェイスをラップするために、クラス ラッパーを使用する必要があると判別します。For example, the marshaler determines that the class wrapper should be used to wrap the interface that was passed into managed code. インターフェイスが初めてマーシャラーを介して渡されるとき、マーシャラーは、インターフェイスが既知のオブジェクトからのものかどうかを確認します。When the interface is first passed through the marshaler, the marshaler checks whether the interface is coming from a known object. このチェックは、以下の 2 つの状況で発生します。This check occurs in two situations:

  • インターフェイスは、他の場所で COM に渡された別のマネージド オブジェクトによって実装されています。An interface is being implemented by another managed object that was passed to COM elsewhere. マーシャラーは、マネージド オブジェクトによって公開されるインターフェイスを簡単に特定し、インターフェイスと実装を提供するマネージド オブジェクトとで突き合わせすることができます。The marshaler can readily identify interfaces exposed by managed objects and is able to match the interface with the managed object that provides the implementation. その後、マネージド オブジェクトはメソッドに渡され、ラッパーは必要ありません。The managed object is then passed to the method and no wrapper is needed.

  • 既ににラップされているオブジェクトは、インターフェイスを実装しています。An object that has already been wrapped is implementing the interface. このような状況かどうかを確認するために、マーシャラーは IUnknown インターフェイスのためにオブジェクトのクエリを実行して、返されたインターフェイスを既にラップされているその他のオブジェクトのインターフェイスと比較します。To determine whether this is the case, the marshaler queries the object for its IUnknown interface and compares the returned interface to the interfaces of other objects that are already wrapped. インターフェイスが別のラッパーのものと同じ場合、それらのオブジェクトには同じ ID があり、既存のラッパーがメソッドに渡されます。If the interface is the same as that of another wrapper, the objects have the same identity and the existing wrapper is passed to the method.

インターフェイスが既知のオブジェクトからのものではない場合、マーシャラーは以下を実行します。If an interface is not from a known object, the marshaler does the following:

  1. マーシャラーは IProvideClassInfo2 インターフェイスのためにオブジェクトのクエリを実行します。The marshaler queries the object for the IProvideClassInfo2 interface. 提供された場合、マーシャラーは、IProvideClassInfo2.GetGUID から返される CLSID を使用して、インターフェイスを提供するコクラスを識別します。If provided, the marshaler uses the CLSID returned from IProvideClassInfo2.GetGUID to identify the coclass providing the interface. CLSID によって、マーシャラーは、アセンブリが事前に登録されている場合にレジストリからラッパーを見つけることができます。With the CLSID, the marshaler can locate the wrapper from the registry if the assembly has previously been registered.

  2. マーシャラーは IProvideClassInfo インターフェイスのためにインターフェイスのクエリを実行します。The marshaler queries the interface for the IProvideClassInfo interface. 提供された場合、マーシャラーは、IProvideClassInfo.GetClassinfo から返される ITypeInfo を使用して、インターフェイスを公開するクラスの CLSID を決定します。If provided, the marshaler uses the ITypeInfo returned from IProvideClassInfo.GetClassinfo to determine the CLSID of the class exposing the interface. マーシャラーは、CLSID を使用して、ラッパーのメタデータを見つけることができます。The marshaler can use the CLSID to locate the metadata for the wrapper.

  3. マーシャラーは、まだクラスを識別できない場合には、System.__ComObject と呼ばれるジェネリック ラッパー クラスを使用してインターフェイスをラップします。If the marshaler still cannot identify the class, it wraps the interface with a generic wrapper class called System.__ComObject.

デリゲートに対する既定のマーシャリングDefault marshaling for delegates

マネージド デリゲートは、呼び出し元のメカニズムに基づいて、COM インターフェイスまたは関数ポインターとしてマーシャリングされます。A managed delegate is marshaled as a COM interface or as a function pointer, based on the calling mechanism:

  • プラットフォーム呼び出しの場合、デリゲートは、既定でアンマネージ関数ポインターとしてマーシャリングされます。For platform invoke, a delegate is marshaled as an unmanaged function pointer by default.

  • COM 相互運用の場合、デリゲートは、既定で _Delegate 型の COM インターフェイスとしてマーシャリングされます。For COM interop, a delegate is marshaled as a COM interface of type _Delegate by default. _Delegate インターフェイスは Mscorlib.tlb のタイプ ライブラリで定義され、デリゲートが参照するメソッドの呼び出しを可能にする Delegate.DynamicInvoke メソッドが含まれています。The _Delegate interface is defined in the Mscorlib.tlb type library and contains the Delegate.DynamicInvoke method, which enables you to call the method that the delegate references.

次の表は、マネージド デリゲート データ型のマーシャリング オプションを示しています。The following table shows the marshaling options for the managed delegate data type. MarshalAsAttribute 属性は、デリゲートをマーシャリングする UnmanagedType 列挙値を提供します。The MarshalAsAttribute attribute provides several UnmanagedType enumeration values to marshal delegates.

列挙型Enumeration type アンマネージ形式の説明Description of unmanaged format
UnmanagedType.FunctionPtrUnmanagedType.FunctionPtr アンマネージ関数ポインター。An unmanaged function pointer.
UnmanagedType.InterfaceUnmanagedType.Interface Mscorlib.tlb で定義されている、_Delegate 型のインターフェイス。An interface of type _Delegate, as defined in Mscorlib.tlb.

DelegateTestInterface のメソッドが COM タイプ ライブラリにエクスポートされる、次のコード例を検討してください。Consider the following example code in which the methods of DelegateTestInterface are exported to a COM type library. ref (または ByRef) キーワードでマークされたデリゲートだけが、In/Out パラメーターとして渡されることに注意してください。Notice that only delegates marked with the ref (or ByRef) keyword are passed as In/Out parameters.

using System;  
using System.Runtime.InteropServices;  
  
public interface DelegateTest {  
void m1(Delegate d);  
void m2([MarshalAs(UnmanagedType.Interface)] Delegate d);     
void m3([MarshalAs(UnmanagedType.Interface)] ref Delegate d);    
void m4([MarshalAs(UnmanagedType.FunctionPtr)] Delegate d);   
void m5([MarshalAs(UnmanagedType.FunctionPtr)] ref Delegate d);     
}  

タイプ ライブラリの表現Type library representation

importlib("mscorlib.tlb");  
interface DelegateTest : IDispatch {  
[id(…)] HRESULT m1([in] _Delegate* d);  
[id(…)] HRESULT m2([in] _Delegate* d);  
[id(…)] HRESULT m3([in, out] _Delegate** d);  
[id()] HRESULT m4([in] int d);  
[id()] HRESULT m5([in, out] int *d);  
   };  

他のアンマネージ関数ポインターが逆参照できるのと同様に、関数ポインターは逆参照できます。A function pointer can be dereferenced, just as any other unmanaged function pointer can be dereferenced.

この例では、2 つのデリゲートが UnmanagedType.FunctionPtr としてマーシャリングされると、その結果は int および int へのポインターとなります。In this example, when the two delegates are marshaled as UnmanagedType.FunctionPtr, the result is an int and a pointer to an int. デリゲートの型はマーシャリング中であるため、int はここでは、メモリ内のデリゲートのアドレスである void (void*) を指すポインターを表します。Because delegate types are being marshaled, int here represents a pointer to a void (void*), which is the address of the delegate in memory. つまり、この結果は 32 ビット Windows システムに固有のものとなります。int がここでは関数ポインターのサイズを表すからです。In other words, this result is specific to 32-bit Windows systems, since int here represents the size of the function pointer.

注意

アンマネージド コードで保持されている、マネージド デリゲートへの関数ポインターに対する参照は、共通言語ランタイムがマネージド オブジェクトでガベージ コレクションを実行することを防止しません。A reference to the function pointer to a managed delegate held by unmanaged code does not prevent the common language runtime from performing garbage collection on the managed object.

たとえば、SetChangeHandler メソッドに渡される cb オブジェクトへの参照は Test メソッドの有効期間を超えて cb を有効のまま保持しないので、次のコードは正しくありません。For example, the following code is incorrect because the reference to the cb object, passed to the SetChangeHandler method, does not keep cb alive beyond the life of the Test method. cb オブジェクトでガベージ コレクションを実行した後、SetChangeHandler に渡された関数ポインターは無効になります。Once the cb object is garbage collected, the function pointer passed to SetChangeHandler is no longer valid.

public class ExternalAPI {  
   [DllImport("External.dll")]  
   public static extern void SetChangeHandler(  
      [MarshalAs(UnmanagedType.FunctionPtr)]ChangeDelegate d);  
}  
public delegate bool ChangeDelegate([MarshalAs(UnmanagedType.LPWStr) string S);  
public class CallBackClass {  
   public bool OnChange(string S){ return true;}  
}  
internal class DelegateTest {  
   public static void Test() {  
      CallBackClass cb = new CallBackClass();  
      // Caution: The following reference on the cb object does not keep the   
      // object from being garbage collected after the Main method   
      // executes.  
      ExternalAPI.SetChangeHandler(new ChangeDelegate(cb.OnChange));     
   }  
}  

予期しないガベージ コレクションを補正するために、呼び出し元は、アンマネージ関数ポインターの使用中は cb オブジェクトが有効のまま保持されるようにする必要があります。To compensate for unexpected garbage collection, the caller must ensure that the cb object is kept alive as long as the unmanaged function pointer is in use. 必要に応じて、次の例に示すように、関数ポインターが不要になった際にアンマネージド コードがマネージド コードに通知するようにすることができます。Optionally, you can have the unmanaged code notify the managed code when the function pointer is no longer needed, as the following example shows.

internal class DelegateTest {  
   CallBackClass cb;  
   // Called before ever using the callback function.  
   public static void SetChangeHandler() {  
      cb = new CallBackClass();  
      ExternalAPI.SetChangeHandler(new ChangeDelegate(cb.OnChange));  
   }  
   // Called after using the callback function for the last time.  
   public static void RemoveChangeHandler() {  
      // The cb object can be collected now. The unmanaged code is   
      // finished with the callback function.  
      cb = null;  
   }  
}  

値型に対する既定のマーシャリングDefault marshaling for value types

整数や浮動小数点数など、ほとんどの値型は、blittable であり、マーシャリングを必要としません。Most value types, such as integers and floating-point numbers, are blittable and do not require marshaling. その他の non-blittable 型は、マネージド メモリとアンマネージド メモリに類似しない表現があり、マーシャリングが必要です。Other non-blittable types have dissimilar representations in managed and unmanaged memory and do require marshaling. さらに他の型は、相互運用性の境界を越えて、明示的な書式設定が必要です。Still other types require explicit formatting across the interoperation boundary.

このセクションでは、次の書式設定された値に関する情報を提供します。This section provides information on the following formatted value types:

書式指定された型について説明することに加えて、このトピックでは、マーシャリング動作が通常ではないシステム値型について示します。In addition to describing formatted types, this topic identifies System Value Types that have unusual marshaling behavior.

書式設定された型は、メモリ内のメンバーのレイアウトを明示的に制御するための情報を含む複合型です。A formatted type is a complex type that contains information that explicitly controls the layout of its members in memory. メンバーのレイアウト情報は、StructLayoutAttribute 属性を使用して示すことができます。The member layout information is provided using the StructLayoutAttribute attribute. レイアウトは、次のいずれかの LayoutKind 列挙値です。The layout can be one of the following LayoutKind enumeration values:

  • LayoutKind.AutomaticLayoutKind.Automatic

    共通言語ランタイムで、効率を上げるのために、型のメンバーを自由に再配置できることを示します。Indicates that the common language runtime is free to reorder the members of the type for efficiency. ただし、値型がアンマネージ コードに渡されると、メンバーのレイアウトは予測可能です。However, when a value type is passed to unmanaged code, the layout of the members is predictable. このような構造体を自動的にマーシャリングしようとすると、例外が発生します。An attempt to marshal such a structure automatically causes an exception.

  • LayoutKind.SequentialLayoutKind.Sequential

    型のメンバーは、マネージド型定義での順序と同じ順序で、アンマネージド メモリにレイアウトされることを示します。Indicates that the members of the type are to be laid out in unmanaged memory in the same order in which they appear in the managed type definition.

  • LayoutKind.ExplicitLayoutKind.Explicit

    メンバーが、各フィールドに指定された FieldOffsetAttribute に基づいてレイアウトされることを示します。Indicates that the members are laid out according to the FieldOffsetAttribute supplied with each field.

プラットフォーム呼び出しで使用される値型Value Types Used in Platform Invoke

次の例では、PointRect 型が、StructLayoutAttribute を使用してメンバーのレイアウト情報を提供します。In the following example the Point and Rect types provide member layout information using the StructLayoutAttribute.

Imports System.Runtime.InteropServices  
<StructLayout(LayoutKind.Sequential)> Public Structure Point  
   Public x As Integer  
   Public y As Integer  
End Structure  
<StructLayout(LayoutKind.Explicit)> Public Structure Rect  
   <FieldOffset(0)> Public left As Integer  
   <FieldOffset(4)> Public top As Integer  
   <FieldOffset(8)> Public right As Integer  
   <FieldOffset(12)> Public bottom As Integer  
End Structure  
using System.Runtime.InteropServices;  
[StructLayout(LayoutKind.Sequential)]  
public struct Point {  
   public int x;  
   public int y;  
}     
  
[StructLayout(LayoutKind.Explicit)]  
public struct Rect {  
   [FieldOffset(0)] public int left;  
   [FieldOffset(4)] public int top;  
   [FieldOffset(8)] public int right;  
   [FieldOffset(12)] public int bottom;  
}  

アンマネージ コードにマーシャリングされるとき、これらの書式指定された型は C スタイルの構造体としてマーシャリングされます。When marshaled to unmanaged code, these formatted types are marshaled as C-style structures. これは、構造体の引数を持つアンマネージ API を呼び出すための、簡単な方法を提供します。This provides an easy way of calling an unmanaged API that has structure arguments. たとえば、次のようにして、POINTRECT 構造体を Microsoft Windows API PtInRect 関数に渡すことができます。For example, the POINT and RECT structures can be passed to the Microsoft Windows API PtInRect function as follows:

BOOL PtInRect(const RECT *lprc, POINT pt);  

次のプラットフォーム呼び出し定義を使用して、構造体を渡すことができますYou can pass structures using the following platform invoke definition:

Friend Class WindowsAPI
    Friend Shared Declare Auto Function PtInRect Lib "User32.dll" (
        ByRef r As Rect, p As Point) As Boolean
End Class
internal static class WindowsAPI
{
   [DllImport("User32.dll")]
   internal static extern bool PtInRect(ref Rect r, Point p);
}

アンマネージ API では、RECT へのポインターが関数に渡されることが予期されているので、Rect 値型は参照によって渡す必要があります。The Rect value type must be passed by reference because the unmanaged API is expecting a pointer to a RECT to be passed to the function. アンマネージ API では、POINT がスタックで渡されることが予期されているので、Point 値型は値によって渡します。The Point value type is passed by value because the unmanaged API expects the POINT to be passed on the stack. この微妙な違いは、非常に重要です。This subtle difference is very important. 参照は、ポインターとしてアンマネージ コードに渡されます。References are passed to unmanaged code as pointers. 値は、スタックでアンマネージ コードに渡されます。Values are passed to unmanaged code on the stack.

注意

書式設定された型が構造体としてマーシャリングされると、型内のフィールドだけがアクセス可能となります。When a formatted type is marshaled as a structure, only the fields within the type are accessible. 型にメソッド、プロパティ、またはイベントがある場合、それらにはアンマネージ コードからアクセスできません。If the type has methods, properties, or events, they are inaccessible from unmanaged code.

クラスも、固定のメンバー レイアウトがあれば、C スタイルの構造体としてアンマネージ コードにマーシャリングできます。Classes can also be marshaled to unmanaged code as C-style structures, provided they have fixed member layout. クラスのメンバー レイアウト情報も、StructLayoutAttribute 属性で提供されます。The member layout information for a class is also provided with the StructLayoutAttribute attribute. 固定レイアウトの値型と固定レイアウトのクラスの主な違いは、それらがアンマネージ コードにマーシャリングされる方法です。The main difference between value types with fixed layout and classes with fixed layout is the way in which they are marshaled to unmanaged code. 値型は (スタックで) 値によって渡されるので、呼び出し先が型のメンバーに変更を加えても、その変更は呼び出し元に示されません。Value types are passed by value (on the stack) and consequently any changes made to the members of the type by the callee are not seen by the caller. 参照型は参照によって渡される (型への参照がスタックで渡される) ので、呼び出し先が型の blittable 型のメンバーに加えるすべての変更は呼び出し元に示されます。Reference types are passed by reference (a reference to the type is passed on the stack); consequently, all changes made to blittable-type members of a type by the callee are seen by the caller.

注意

参照型に非 blittable 型のメンバーがある場合、変換は 2 回必要となります。1 回目は引数がアンマネージ サイトに渡されるときで、2 回目は呼び出しから返されるときです。If a reference type has members of non-blittable types, conversion is required twice: the first time when an argument is passed to the unmanaged side and the second time on return from the call. この追加のオーバーヘッドがあるために、呼び出し先による変更を呼び出し元が参照できるようにする場合は、In/Out パラメーターを引数に明示的に適用する必要があります。Due to this added overhead, In/Out parameters must be explicitly applied to an argument if the caller wants to see changes made by the callee.

次の例では、SystemTime クラスにシーケンシャル メンバー レイアウトがあり、それを Windows API GetSystemTime 関数に渡すことができます。In the following example, the SystemTime class has sequential member layout and can be passed to the Windows API GetSystemTime function.

<StructLayout(LayoutKind.Sequential)> Public Class SystemTime  
   Public wYear As System.UInt16  
   Public wMonth As System.UInt16  
   Public wDayOfWeek As System.UInt16  
   Public wDay As System.UInt16  
   Public wHour As System.UInt16  
   Public wMinute As System.UInt16  
   Public wSecond As System.UInt16  
   Public wMilliseconds As System.UInt16  
End Class  
[StructLayout(LayoutKind.Sequential)]  
   public class SystemTime {  
   public ushort wYear;   
   public ushort wMonth;  
   public ushort wDayOfWeek;   
   public ushort wDay;   
   public ushort wHour;   
   public ushort wMinute;   
   public ushort wSecond;   
   public ushort wMilliseconds;   
}  

GetSystemTime 関数は次のように定義されています。The GetSystemTime function is defined as follows:

void GetSystemTime(SYSTEMTIME* SystemTime);  

GetSystemTime に対する同等のプラットフォーム呼び出し定義は、次のようになります。The equivalent platform invoke definition for GetSystemTime is as follows:

Friend Class WindowsAPI
    Friend Shared Declare Auto Sub GetSystemTime Lib "Kernel32.dll" (
        ByVal sysTime As SystemTime)
End Class
internal static class WindowsAPI
{
   [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
   internal static extern void GetSystemTime(SystemTime st);
}

SystemTime は値型ではなくクラスなので、SystemTime 引数は参照引数として型指定されていないことに注意してください。Notice that the SystemTime argument is not typed as a reference argument because SystemTime is a class, not a value type. 値型とは異なり、クラスは常に参照によって渡されます。Unlike value types, classes are always passed by reference.

次のコード例は、SetXY と呼ばれるメソッドを持つ、異なる Point クラスを示しています。The following code example shows a different Point class that has a method called SetXY. 型にはシーケンシャル レイアウトがあるため、それをアンマネージ コードに渡して、構造体としてマーシャリングすることができます。Because the type has sequential layout, it can be passed to unmanaged code and marshaled as a structure. ただし、SetXY メンバーは、オブジェクトが参照によって渡される場合でも、アンマネージ コードから呼び出すことができません。However, the SetXY member is not callable from unmanaged code, even though the object is passed by reference.

<StructLayout(LayoutKind.Sequential)> Public Class Point  
   Private x, y As Integer  
   Public Sub SetXY(x As Integer, y As Integer)  
      Me.x = x  
      Me.y = y  
   End Sub  
End Class  
[StructLayout(LayoutKind.Sequential)]  
public class Point {  
   int x, y;  
   public void SetXY(int x, int y){   
      this.x = x;  
      this.y = y;  
   }  
}  

COM 相互運用で使用される値型Value Types Used in COM Interop

書式指定された型は、COM 相互運用のメソッドの呼び出しに渡すこともできます。Formatted types can also be passed to COM interop method calls. 実際には、タイプ ライブラリにエクスポートされると、値型は構造体に自動的に変換されます。In fact, when exported to a type library, value types are automatically converted to structures. 次の例に示すように、Point 値型は Point という名前の型定義 (typedef) になります。As the following example shows, the Point value type becomes a type definition (typedef) with the name Point. タイプ ライブラリ内の他の場所にある Point 値型へのすべての参照は、Point typedef に置き換えられます。All references to the Point value type elsewhere in the type library are replaced with the Point typedef.

タイプ ライブラリの表現Type library representation

typedef struct tagPoint {  
   int x;  
   int y;  
} Point;  
interface _Graphics {  
   …  
   HRESULT SetPoint ([in] Point p)  
   HRESULT SetPointRef ([in,out] Point *p)  
   HRESULT GetPoint ([out,retval] Point *p)  
}  

値と参照をプラットフォーム呼び出しにマーシャリングする際に使用されるものと同じ規則が、COM インターフェイスを介してマーシャリングする際にも使用されます。The same rules used to marshal values and references to platform invoke calls are used when marshaling through COM interfaces. たとえば、Point 値型のインスタンスが .NET Framework から COM に渡されるとき、Point は値によって渡されます。For example, when an instance of the Point value type is passed from the .NET Framework to COM, the Point is passed by value. Point 値型が参照によって渡される場合、Point へのポインターはスタックで渡されます。If the Point value type is passed by reference, a pointer to a Point is passed on the stack. 相互運用マーシャラーは、どちらの方向でも、より高いレベルの間接参照 (Point **) はサポートしていません。The interop marshaler does not support higher levels of indirection (Point **) in either direction.

注意

LayoutKind 列挙値が Explicit に設定された構造体は、エクスポートされたタイプ ライブラリが明示的なレイアウトを表現できないので、COM 相互運用で使用することはできません。Structures having the LayoutKind enumeration value set to Explicit cannot be used in COM interop because the exported type library cannot express an explicit layout.

システムの値型System Value Types

System 名前空間には、ランタイムのプリミティブ型のボックス化された形式を表す、いくつかの値型があります。The System namespace has several value types that represent the boxed form of the runtime primitive types. たとえば、値型 System.Int32 構造体は、ELEMENT_TYPE_I4 のボックス化された形式を表します。For example, the value type System.Int32 structure represents the boxed form of ELEMENT_TYPE_I4. これらの型は、書式設定された他の型のように構造体としてマーシャリングするのではなく、それらがボックス化するプリミティブ型と同じ方法でマーシャリングします。Instead of marshaling these types as structures, as other formatted types are, you marshal them in the same way as the primitive types they box. そのため、System.Int32 は、long 型の 1 つのメンバーを含む構造体としてではなく、ELEMENT_TYPE_I4 としてマーシャリングされます。System.Int32 is therefore marshaled as ELEMENT_TYPE_I4 instead of as a structure containing a single member of type long. 次の表には、プリミティブ型のボックス化された表現である、System 名前空間にある値型の一覧が含まれています。The following table contains a list of the value types in the System namespace that are boxed representations of primitive types.

システムの値型System value type 要素型Element type
System.Boolean ELEMENT_TYPE_BOOLEANELEMENT_TYPE_BOOLEAN
System.SByte ELEMENT_TYPE_I1ELEMENT_TYPE_I1
System.Byte ELEMENT_TYPE_UI1ELEMENT_TYPE_UI1
System.Char ELEMENT_TYPE_CHARELEMENT_TYPE_CHAR
System.Int16 ELEMENT_TYPE_I2ELEMENT_TYPE_I2
System.UInt16 ELEMENT_TYPE_U2ELEMENT_TYPE_U2
System.Int32 ELEMENT_TYPE_I4ELEMENT_TYPE_I4
System.UInt32 ELEMENT_TYPE_U4ELEMENT_TYPE_U4
System.Int64 ELEMENT_TYPE_I8ELEMENT_TYPE_I8
System.UInt64 ELEMENT_TYPE_U8ELEMENT_TYPE_U8
System.Single ELEMENT_TYPE_R4ELEMENT_TYPE_R4
System.Double ELEMENT_TYPE_R8ELEMENT_TYPE_R8
System.String ELEMENT_TYPE_STRINGELEMENT_TYPE_STRING
System.IntPtr ELEMENT_TYPE_IELEMENT_TYPE_I
System.UIntPtr ELEMENT_TYPE_UELEMENT_TYPE_U

System 名前空間にある他の値型は、処理が異なります。Some other value types in the System namespace are handled differently. アンマネージ コードではこれらの型の形式が既に確立されているため、マーシャラーには、それらをマーシャリングするための特別な規則があります。Because the unmanaged code already has well-established formats for these types, the marshaler has special rules for marshaling them. 次の表では、System 名前空間にある特殊な値型、およびそれらがマーシャリングされるアンマネージ型を一覧で示します。The following table lists the special value types in the System namespace, as well as the unmanaged type they are marshaled to.

システムの値型System value type IDL 型IDL type
System.DateTime DATEDATE
System.Decimal DECIMALDECIMAL
System.Guid GUIDGUID
System.Drawing.Color OLE_COLOROLE_COLOR

次のコードでは、Stdole2 タイプ ライブラリにあるアンマネージ型の DATEGUIDDECIMAL、および OLE_COLOR の定義を示します。The following code shows the definition of the unmanaged types DATE, GUID, DECIMAL, and OLE_COLOR in the Stdole2 type library.

タイプ ライブラリの表現Type library representation

typedef double DATE;  
typedef DWORD OLE_COLOR;  
  
typedef struct tagDEC {  
    USHORT    wReserved;  
    BYTE      scale;  
    BYTE      sign;  
    ULONG     Hi32;  
    ULONGLONG Lo64;  
} DECIMAL;  
  
typedef struct tagGUID {  
    DWORD Data1;  
    WORD  Data2;  
    WORD  Data3;  
    BYTE  Data4[ 8 ];  
} GUID;  

次のコードでは、マネージド IValueTypes インターフェイスでの対応する定義を示します。The following code shows the corresponding definitions in the managed IValueTypes interface.

Public Interface IValueTypes  
   Sub M1(d As System.DateTime)  
   Sub M2(d As System.Guid)  
   Sub M3(d As System.Decimal)  
   Sub M4(d As System.Drawing.Color)  
End Interface  
public interface IValueTypes {  
   void M1(System.DateTime d);  
   void M2(System.Guid d);  
   void M3(System.Decimal d);  
   void M4(System.Drawing.Color d);  
}  

タイプ ライブラリの表現Type library representation

[…]  
interface IValueTypes : IDispatch {  
   HRESULT M1([in] DATE d);  
   HRESULT M2([in] GUID d);  
   HRESULT M3([in] DECIMAL d);  
   HRESULT M4([in] OLE_COLOR d);  
};  

関連項目See also