Výchozí chování zařazováníDefault Marshaling Behavior

Zařazování Interop funguje s pravidly, která určují, jak se data přidružená k parametrům metody chovají při průchodu mezi spravovanou a nespravovanou pamětí.Interop marshaling operates on rules that dictate how data associated with method parameters behaves as it passes between managed and unmanaged memory. Tato Vestavěná pravidla řídí tyto aktivity zařazování jako transformace datových typů, ať už volaný může změnit předaných dat a vracet tyto změny volajícímu a za kterých okolnosti zařazování poskytuje optimalizace výkonu.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.

Tato část identifikuje výchozí charakteristiky chování služby interop marshaling.This section identifies the default behavioral characteristics of the interop marshaling service. Zobrazuje podrobné informace o zařazovacích polích, logických typech, typech znaků, delegátů, třídách, objektech, řetězcích a strukturách.It presents detailed information on marshaling arrays, Boolean types, char types, delegates, classes, objects, strings, and structures.

Poznámka

Zařazování obecných typů se nepodporuje.Marshaling of generic types is not supported. Další informace najdete v tématu spolupráce pomocí obecných typů.For more information see, Interoperating Using Generic Types.

Správa paměti pomocí zařazovacího modulu spolupráceMemory management with the interop marshaler

Zařazování Interop se vždy pokouší uvolnit paměť přidělenou nespravovaným kódem.The interop marshaler always attempts to free memory allocated by unmanaged code. Toto chování je v souladu s pravidly správy paměti modelu COM, ale liší se od pravidel, C++která se řídí nativním.This behavior complies with COM memory management rules, but differs from the rules that govern native C++.

K záměně může dojít, pokud při C++ použití vyvolání platformy očekáváte nativní chování (bez uvolnění paměti), které automaticky uvolňuje paměť pro ukazatele.Confusion can arise if you anticipate native C++ behavior (no memory freeing) when using platform invoke, which automatically frees memory for pointers. Například volání následující nespravované metody z C++ knihovny DLL automaticky neuvolní žádnou paměť.For example, calling the following unmanaged method from a C++ DLL does not automatically free any memory.

Nespravovaný podpisUnmanaged signature

BSTR MethodOne (BSTR b) {  
     return b;  
}  

Pokud však definujete metodu jako prototyp vyvolání platformy, nahradíte každý typ BSTR typem String a zavoláte MethodOne, modul CLR (Common Language Runtime) se pokusí uvolnit b dvakrát.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. Chování zařazování lze změnit pomocí IntPtrch typů namísto řetězcových typů.You can change the marshaling behavior by using IntPtr types rather than String types.

Modul runtime vždy používá metodu CoTaskMemFree k uvolnění paměti.The runtime always uses the CoTaskMemFree method to free memory. Pokud paměť, se kterou pracujete, nebyla přidělena pomocí metody CoTaskMemAlloc , musíte použít IntPtr a uvolnit paměť ručně pomocí vhodné metody.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. Podobně se můžete vyhnout automatickému uvolňování paměti v situacích, kdy by paměť neměla být nikdy uvolněna, například při použití funkce GetCommandLine z Kernel32. dll, která vrací ukazatel na paměť jádra.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. Podrobnosti o ručním uvolnění paměti najdete v ukázce vyrovnávací paměti.For details on manually freeing memory, see the Buffers Sample.

Výchozí zařazování pro třídyDefault marshaling for classes

Třídy lze zařadit pouze pomocí zprostředkovatele komunikace s objekty COM a jsou vždy zařazeny jako rozhraní.Classes can be marshaled only by COM interop and are always marshaled as interfaces. V některých případech je rozhraní použité k zařazení třídy známé jako rozhraní třídy.In some cases the interface used to marshal the class is known as the class interface. Informace o přepsání rozhraní třídy s rozhraním dle vašeho výběru naleznete v tématu Představujeme rozhraní třídy.For information about overriding the class interface with an interface of your choice, see Introducing the class interface.

Předávání tříd do modelu COMPassing Classes to COM

Když je do modelu COM předána spravovaná třída, zařazovací služba interoperability automaticky zabalí třídu s proxy COM a předá rozhraní třídy vytvořené proxy serverem volání metody 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. Proxy potom deleguje všechna volání rozhraní třídy zpátky do spravovaného objektu.The proxy then delegates all calls on the class interface back to the managed object. Proxy také zveřejňuje jiná rozhraní, která nejsou explicitně implementována třídou.The proxy also exposes other interfaces that are not explicitly implemented by the class. Proxy automaticky implementuje rozhraní, jako je IUnknown a IDispatch jménem třídy.The proxy automatically implements interfaces such as IUnknown and IDispatch on behalf of the class.

Předávání tříd do kódu .NETPassing Classes to .NET Code

Třídy coclass nejsou obvykle používány jako argumenty metody v modelu COM.Coclasses are not typically used as method arguments in COM. Místo toho je obvykle předán výchozí rozhraní místo třídy typu coclass.Instead, a default interface is usually passed in place of the coclass.

Když je rozhraní předáno do spravovaného kódu, zařazovací modul Interop zodpovídá za balení rozhraní se správnou obálkou a předání obálky spravované metodě.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. Určení, která obálka se má použít, může být obtížné.Determining which wrapper to use can be difficult. Každá instance objektu COM má jedinou jedinečnou obálku bez ohledu na to, kolik rozhraní objekt implementuje.Every instance of a COM object has a single, unique wrapper, no matter how many interfaces the object implements. Například jeden objekt COM, který implementuje pět různých rozhraní, má pouze jednu obálku.For example, a single COM object that implements five distinct interfaces has only one wrapper. Stejná obálka zpřístupňuje všechna pět rozhraní.The same wrapper exposes all five interfaces. Pokud se vytvoří dvě instance objektu COM, vytvoří se dvě instance obálky.If two instances of the COM object are created, then two instances of the wrapper are created.

Aby obálka zachovala stejný typ během své životnosti, musí zařazovací modul Interop identifikovat správnou obálku, když je rozhraní vystavené objektem předáno prostřednictvím zařazovacího modulu.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. Zařazovací modul identifikuje objekt tím, že prohlíží jedno z rozhraní, které objekt implementuje.The marshaler identifies the object by looking at one of the interfaces the object implements.

Například zařazovací modul určí, že obálka třídy by měla být použita k zabalení rozhraní, které bylo předáno do spravovaného kódu.For example, the marshaler determines that the class wrapper should be used to wrap the interface that was passed into managed code. Když je rozhraní nejprve předáno prostřednictvím zařazovacího modulu, zařazovací modul zkontroluje, zda rozhraní přichází ze známého objektu.When the interface is first passed through the marshaler, the marshaler checks whether the interface is coming from a known object. Tato kontrolu probíhá ve dvou situacích:This check occurs in two situations:

  • Rozhraní je implementováno jiným spravovaným objektem, který byl předán do modelu COM jinde.An interface is being implemented by another managed object that was passed to COM elsewhere. Zařazovací modul může snadno identifikovat rozhraní vystavená spravovanými objekty a může odpovídat rozhraní se spravovaným objektem, který poskytuje implementaci.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. Spravovaný objekt je pak předán metodě a není nutná žádná obálka.The managed object is then passed to the method and no wrapper is needed.

  • Objekt, který již byl zabalen, implementuje rozhraní.An object that has already been wrapped is implementing the interface. Chcete-li zjistit, zda se jedná o tento případ, zařazovací modul dotazuje objekt pro jeho rozhraní IUnknown a porovná vrácené rozhraní s rozhraními jiných objektů, které jsou již zabaleny.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. Pokud je rozhraní stejné jako jiné obálky, objekty mají stejnou identitu a stávající obálka je předána metodě.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.

Pokud rozhraní nepochází ze známého objektu, zařazovací modul provede následující:If an interface is not from a known object, the marshaler does the following:

  1. Zařazovací modul se dotazuje objektu pro rozhraní IProvideClassInfo2 .The marshaler queries the object for the IProvideClassInfo2 interface. Pokud je k dispozici, zařazovací modul používá identifikátor CLSID vrácený z IProvideClassInfo2. GetGUID k identifikaci třídy coclass poskytující rozhraní.If provided, the marshaler uses the CLSID returned from IProvideClassInfo2.GetGUID to identify the coclass providing the interface. S identifikátorem CLSID může zařazovací modul najít obálku z registru, pokud bylo sestavení dříve registrováno.With the CLSID, the marshaler can locate the wrapper from the registry if the assembly has previously been registered.

  2. Zařazovací modul vyžádá rozhraní pro rozhraní IProvideClassInfo .The marshaler queries the interface for the IProvideClassInfo interface. Pokud je k dispozici, zařazovací modul používá volání ITypeInfo vrácenou z IProvideClassInfo. GetClassInfo k určení identifikátoru CLSID třídy, která toto rozhraní zveřejňuje.If provided, the marshaler uses the ITypeInfo returned from IProvideClassInfo.GetClassinfo to determine the CLSID of the class exposing the interface. Zařazovací modul může pomocí identifikátoru CLSID najít metadata pro obálku.The marshaler can use the CLSID to locate the metadata for the wrapper.

  3. Pokud zařazovací modul stále nemůže identifikovat třídu, zabalí rozhraní s obecnou obálkovou třídou s názvem System. __ComObject.If the marshaler still cannot identify the class, it wraps the interface with a generic wrapper class called System.__ComObject.

Výchozí zařazování pro delegátyDefault marshaling for delegates

Spravovaný delegát je zařazen jako rozhraní modelu COM nebo jako ukazatel na funkci na základě volajícího mechanismu:A managed delegate is marshaled as a COM interface or as a function pointer, based on the calling mechanism:

  • V případě vyvolání platformy je delegát ve výchozím nastavení zařazen jako nespravovaný ukazatel na funkci.For platform invoke, a delegate is marshaled as an unmanaged function pointer by default.

  • Pro zprostředkovatele komunikace s objekty COM je delegát ve výchozím nastavení zařazen jako rozhraní COM typu _Delegate .For COM interop, a delegate is marshaled as a COM interface of type _Delegate by default. Rozhraní _Delegate je definováno v knihovně typů mscorlib. tlb a obsahuje metodu Delegate.DynamicInvoke, která umožňuje volat metodu, na kterou odkazuje delegát.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.

V následující tabulce jsou uvedeny možnosti zařazování pro datový typ spravovaného delegáta.The following table shows the marshaling options for the managed delegate data type. Atribut MarshalAsAttribute poskytuje několik hodnot UnmanagedType výčtu pro zařazení delegátů.The MarshalAsAttribute attribute provides several UnmanagedType enumeration values to marshal delegates.

Typ výčtuEnumeration type Popis nespravovaného formátuDescription of unmanaged format
UnmanagedType. typem FunctionPtrUnmanagedType.FunctionPtr Nespravovaný ukazatel na funkci.An unmanaged function pointer.
UnmanagedType. InterfaceUnmanagedType.Interface Rozhraní typu _Delegate, jak je definováno v mscorlib. tlb.An interface of type _Delegate, as defined in Mscorlib.tlb.

Vezměte v úvahu následující příklad kódu, ve kterém jsou metody DelegateTestInterface exportovány do knihovny typů modelu COM.Consider the following example code in which the methods of DelegateTestInterface are exported to a COM type library. Všimněte si, že jako vstupně-výstupní parametry jsou předány pouze Delegáti označeni klíčovým slovem ref (nebo ByRef).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);     
}  

Reprezentace knihovny typů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);  
   };  

Na ukazatel na funkci lze odkázat stejným způsobem, jako jakýkoli jiný nespravovaný ukazatel na funkci lze odkázat.A function pointer can be dereferenced, just as any other unmanaged function pointer can be dereferenced.

V tomto příkladu, když jsou dva Delegáti zařazeni jako UnmanagedType.FunctionPtr, je výsledkem int a ukazatel na int.In this example, when the two delegates are marshaled as UnmanagedType.FunctionPtr, the result is an int and a pointer to an int. Vzhledem k tomu, že typy delegátů jsou zařazování, int zde představuje ukazatel na void (void*), což je adresa delegáta v paměti.Because delegate types are being marshaled, int here represents a pointer to a void (void*), which is the address of the delegate in memory. Jinými slovy, tento výsledek je specifický pro 32 systémy Windows, protože int tady představuje velikost ukazatele na funkci.In other words, this result is specific to 32-bit Windows systems, since int here represents the size of the function pointer.

Poznámka

Odkaz na ukazatel funkce na spravovaný delegát, který uchovává nespravovaný kód, nebrání modulu Common Language Runtime v provádění uvolňování paměti ve spravovaném objektu.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.

Například následující kód je nesprávný, protože odkaz na objekt cb předaný metodě SetChangeHandler nezachová cb po dobu životnosti Test metody.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. Jakmile je objekt cb uvolněn z paměti, ukazatel na funkci předaný do SetChangeHandler již není platný.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));     
   }  
}  

Aby bylo možné kompenzovat neočekávané uvolňování paměti, volající musí zajistit, že objekt cb zůstane aktivní, dokud se nepoužívá ukazatel nespravované funkce.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. V případě potřeby může být nespravovaný kód upozorněn na spravovaný kód, pokud ukazatel na funkci již není potřeba, jak ukazuje následující příklad.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;  
   }  
}  

Výchozí zařazování pro typy hodnotDefault marshaling for value types

Většina typů hodnot, jako jsou celá čísla a čísla s plovoucí desetinnou čárkou, jsou přenositelná a nevyžadují zařazování.Most value types, such as integers and floating-point numbers, are blittable and do not require marshaling. Jiné nepřenositelní typy mají odlišné reprezentace ve spravované a nespravované paměti a vyžadují zařazování.Other non-blittable types have dissimilar representations in managed and unmanaged memory and do require marshaling. Stále jiné typy vyžadují explicitní formátování napříč hranicí vzájemných operací.Still other types require explicit formatting across the interoperation boundary.

Tato část poskytuje informace o následujících formátovaných hodnotách:This section provides information on the following formatted value types:

Kromě popisných formátovaných typů toto téma identifikuje typy systémových hodnot , které mají neobvyklé chování při zařazování.In addition to describing formatted types, this topic identifies System Value Types that have unusual marshaling behavior.

Zformátovaný typ je komplexní typ, který obsahuje informace, které explicitně řídí rozložení jeho členů v paměti.A formatted type is a complex type that contains information that explicitly controls the layout of its members in memory. Informace o rozložení členů jsou k dispozici pomocí atributu StructLayoutAttribute.The member layout information is provided using the StructLayoutAttribute attribute. Rozložení může být jedna z následujících hodnot LayoutKind výčtu:The layout can be one of the following LayoutKind enumeration values:

  • LayoutKind. AutomaticLayoutKind.Automatic

    Označuje, že modul CLR (Common Language Runtime) je bezplatný pro změnu pořadí členů typu pro zajištění efektivity.Indicates that the common language runtime is free to reorder the members of the type for efficiency. Pokud je však typ hodnoty předán nespravovanému kódu, je rozložení členů předvídatelné.However, when a value type is passed to unmanaged code, the layout of the members is predictable. Pokus o zařazení takové struktury automaticky způsobí výjimku.An attempt to marshal such a structure automatically causes an exception.

  • LayoutKind. sekvenčníLayoutKind.Sequential

    Označuje, že členové typu mají být rozloženi v nespravované paměti ve stejném pořadí, v jakém jsou uvedeny v definici spravovaného typu.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

    Označuje, že jsou členové rozloženi podle FieldOffsetAttribute dodaných s každým polem.Indicates that the members are laid out according to the FieldOffsetAttribute supplied with each field.

Typy hodnot používané při vyvolání platformyValue Types Used in Platform Invoke

V následujícím příkladu typy Point a Rect poskytují informace o rozložení členů pomocí 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;  
}  

Při zařazení do nespravovaného kódu jsou tyto formátované typy zařazeny jako struktury ve stylu jazyka C.When marshaled to unmanaged code, these formatted types are marshaled as C-style structures. To poskytuje snadný způsob volání nespravovaného rozhraní API, které má argumenty struktury.This provides an easy way of calling an unmanaged API that has structure arguments. Například POINT a RECT struktury lze předat funkci PtInRect rozhraní API systému Microsoft Windows následujícím způsobem: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);  

Struktury můžete předat pomocí následující definice vyvolání platformy:You can pass structures using the following platform invoke definition:

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

Typ hodnoty Rect musí být předán odkazem, protože nespravované rozhraní API očekává ukazatel na RECT, který se má předat funkci.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. Typ hodnoty Point je předán podle hodnoty, protože nespravované rozhraní API očekává, že POINT předat do zásobníku.The Point value type is passed by value because the unmanaged API expects the POINT to be passed on the stack. Tento drobný rozdíl je velmi důležitý.This subtle difference is very important. Odkazy jsou předány nespravovanému kódu jako ukazatelé.References are passed to unmanaged code as pointers. Hodnoty jsou předány nespravovanému kódu v zásobníku.Values are passed to unmanaged code on the stack.

Poznámka

Při zařazování formátovaného typu jako struktury jsou k dispozici pouze pole v rámci tohoto typu.When a formatted type is marshaled as a structure, only the fields within the type are accessible. Pokud typ obsahuje metody, vlastnosti nebo události, jsou nepřístupné z nespravovaného kódu.If the type has methods, properties, or events, they are inaccessible from unmanaged code.

Třídy lze také zařadit do nespravovaného kódu jako struktury ve stylu jazyka C za předpokladu, že mají pevně dané rozložení členů.Classes can also be marshaled to unmanaged code as C-style structures, provided they have fixed member layout. Informace o rozložení členů pro třídu jsou také k dispozici s atributem StructLayoutAttribute.The member layout information for a class is also provided with the StructLayoutAttribute attribute. Hlavní rozdíl mezi typy hodnot s pevným rozložením a třídami s pevným rozložením je způsob, jakým jsou zařazeny do nespravovaného kódu.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. Typy hodnot jsou předávány hodnotou (v zásobníku) a v důsledku toho se žádné změny provedené u členů typu volaného nevidí volajícím.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. Odkazové typy jsou předávány odkazem (odkaz na typ je předán do zásobníku); v důsledku toho volající vytvoří všechny změny provedené u členů typu přenositelné jako typ volaný.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.

Poznámka

Pokud typ odkazu obsahuje členy nepřenositelného typu, je převod požadován dvakrát: při prvním předání argumentu na nespravovanou stranu a při návratu z volání.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. Z důvodu těchto přidaných režijních nákladů musí být parametry nebo výstupy explicitně aplikovány na argument, pokud volající chce zobrazit změny provedené volaným.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.

V následujícím příkladu má třída SystemTime sekvenční rozložení členů a může být předána funkci GetSystemTime rozhraní API systému Windows.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;   
}  

Funkce GetSystemTime je definována takto:The GetSystemTime function is defined as follows:

void GetSystemTime(SYSTEMTIME* SystemTime);  

Ekvivalentní definice vyvolání platformy pro GetSystemTime je následující:The equivalent platform invoke definition for GetSystemTime is as follows:

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

Všimněte si, že argument SystemTime není zadán jako argument odkazu, protože SystemTime je třída, nikoli typ hodnoty.Notice that the SystemTime argument is not typed as a reference argument because SystemTime is a class, not a value type. Na rozdíl od hodnotových typů jsou třídy vždy předány odkazem.Unlike value types, classes are always passed by reference.

Následující příklad kódu ukazuje jinou třídu Point, která má metodu nazvanou SetXY.The following code example shows a different Point class that has a method called SetXY. Vzhledem k tomu, že typ má sekvenční rozložení, lze jej předat nespravovanému kódu a zařadit jako strukturu.Because the type has sequential layout, it can be passed to unmanaged code and marshaled as a structure. SetXY člen však nelze volat z nespravovaného kódu, i když je objekt předán odkazem.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;  
   }  
}  

Typy hodnot používané při zprostředkovateli komunikace s objekty COMValue Types Used in COM Interop

Naformátované typy lze také předat voláním metody spolupráce modelu COM.Formatted types can also be passed to COM interop method calls. Ve skutečnosti platí, že při exportu do knihovny typů jsou typy hodnot automaticky převedeny na struktury.In fact, when exported to a type library, value types are automatically converted to structures. Jak ukazuje následující příklad, typ hodnoty Point se jako definice typu (typedef) s názvem Point.As the following example shows, the Point value type becomes a type definition (typedef) with the name Point. Všechny odkazy na typ hodnoty Point jinde v knihovně typů jsou nahrazeny definicí Point.All references to the Point value type elsewhere in the type library are replaced with the Point typedef.

Reprezentace knihovny typů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)  
}  

Stejná pravidla, která se používají k zařazování hodnot a odkazů na volání vyvolání platformy, se používají při zařazování přes rozhraní COM.The same rules used to marshal values and references to platform invoke calls are used when marshaling through COM interfaces. Například pokud je instance typu hodnoty Point předána z .NET Framework do modelu COM, Point je předána hodnotou.For example, when an instance of the Point value type is passed from the .NET Framework to COM, the Point is passed by value. Pokud je typ hodnoty Point předána odkazem, je ukazatel na Point předán do zásobníku.If the Point value type is passed by reference, a pointer to a Point is passed on the stack. Zařazovací modul Interop nepodporuje v obou směrech vyšší úroveň dereference (Point **).The interop marshaler does not support higher levels of indirection (Point **) in either direction.

Poznámka

Struktury s hodnotou výčtu LayoutKind nastavenou na hodnotu Explicit nelze použít v zprostředkovatele komunikace s objekty COM, protože exportovaná knihovna typů nemůže vyjádřit explicitní rozložení.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.

Typy systémových hodnotSystem Value Types

Obor názvů System má několik typů hodnot, které reprezentují zabalený druh primitivních typů modulu runtime.The System namespace has several value types that represent the boxed form of the runtime primitive types. Například typ hodnoty System.Int32 struktura představuje podobu v podobě pole ELEMENT_TYPE_I4.For example, the value type System.Int32 structure represents the boxed form of ELEMENT_TYPE_I4. Namísto zařazování těchto typů jako struktur, jako jiné formátované typy, jste je zařadíi stejným způsobem jako primitivní typy, které jsou v poli.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. Hodnota System. Int32 je proto zařazena jako ELEMENT_TYPE_I4 namísto struktury obsahující jednoho člena typu Long.System.Int32 is therefore marshaled as ELEMENT_TYPE_I4 instead of as a structure containing a single member of type long. Následující tabulka obsahuje seznam typů hodnot v oboru názvů System , které jsou zabaleny do reprezentace primitivních typů.The following table contains a list of the value types in the System namespace that are boxed representations of primitive types.

Typ systémové hodnotySystem value type Typ elementuElement 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

Některé jiné typy hodnot v oboru názvů System jsou zpracovávány jinak.Some other value types in the System namespace are handled differently. Vzhledem k tomu, že nespravovaný kód již obsahuje dobře zavedený formát pro tyto typy, má zařazovací modul zvláštní pravidla pro jejich zařazování.Because the unmanaged code already has well-established formats for these types, the marshaler has special rules for marshaling them. V následující tabulce jsou uvedeny typy zvláštních hodnot v oboru názvů System a také nespravovaný typ, na který jsou zařazeny.The following table lists the special value types in the System namespace, as well as the unmanaged type they are marshaled to.

Typ systémové hodnotySystem value type Typ IDLIDL type
System.DateTime DatumDATE
System.Decimal NOTACIDECIMAL
System.Guid HLAVNÍCHGUID
System.Drawing.Color OLE_COLOROLE_COLOR

Následující kód ukazuje definici nespravovaných typů Date, GUID, Decimala OLE_COLOR v knihovně typů Stdole2.The following code shows the definition of the unmanaged types DATE, GUID, DECIMAL, and OLE_COLOR in the Stdole2 type library.

Reprezentace knihovny typů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;  

Následující kód ukazuje odpovídající definice ve spravovaném IValueTypes rozhraní.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);  
}  

Reprezentace knihovny typů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);  
};  

Viz také:See also