Comportamento de marshaling padrãoDefault Marshaling Behavior

O marshaling de interoperabilidade opera em regras que determinam como os dados associados aos parâmetros de método se comportam, conforme eles passam entre a memória gerenciada e não gerenciada.Interop marshaling operates on rules that dictate how data associated with method parameters behaves as it passes between managed and unmanaged memory. Essas regras internas controlam atividades de marshaling como transformações de tipo de dados, se um receptor pode alterar os dados passados para ele e retornar essas alterações ao chamador e em quais circunstâncias o marshaler fornece otimizações de desempenho.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.

Esta seção identifica as características comportamentais padrão do serviço de marshaling de interoperabilidade.This section identifies the default behavioral characteristics of the interop marshaling service. Ela apresenta informações detalhadas sobre o marshaling de matrizes, tipos boolianos, tipos char, representantes, classes, objetos, cadeias de caracteres e estruturas.It presents detailed information on marshaling arrays, Boolean types, char types, delegates, classes, objects, strings, and structures.

Observação

Não há suporte para o marshaling de tipos genéricos.Marshaling of generic types is not supported. Para obter mais informações, consulte Interoperando com tipos genéricos.For more information see, Interoperating Using Generic Types.

Gerenciamento de memória com o marshaler de interoperabilidadeMemory management with the interop marshaler

O marshaler de interoperabilidade sempre tenta liberar a memória alocada pelo código não gerenciado.The interop marshaler always attempts to free memory allocated by unmanaged code. Esse comportamento está em conformidade com as regras de gerenciamento da memória COM, mas é diferente das regras que regem o C++ nativo.This behavior complies with COM memory management rules, but differs from the rules that govern native C++.

Poderá haver confusão se você antecipar o comportamento do C++ nativo (sem liberação de memória) ao usar a invocação de plataforma, que libera a memória para ponteiros automaticamente.Confusion can arise if you anticipate native C++ behavior (no memory freeing) when using platform invoke, which automatically frees memory for pointers. Por exemplo, a chamada do método não gerenciado a seguir em uma DLL do C++ não libera qualquer memória automaticamente.For example, calling the following unmanaged method from a C++ DLL does not automatically free any memory.

Assinatura não gerenciadaUnmanaged signature

BSTR MethodOne (BSTR b) {  
     return b;  
}  

No entanto, se você definir o método como um protótipo de invocação de plataforma, substituir cada tipo BSTR por um tipo String e chamar MethodOne, o Common Language Runtime tentará liberar b duas vezes.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. Altere o comportamento de marshaling usando tipos IntPtr, em vez de tipos String.You can change the marshaling behavior by using IntPtr types rather than String types.

O tempo de execução sempre usa o método CoTaskMemFree para liberar memória.The runtime always uses the CoTaskMemFree method to free memory. Se a memória com a qual você está trabalhando não foi alocada com o método CoTaskMemAlloc, use um IntPtr e libere a memória manualmente usando o método apropriado.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. Da mesma forma, evite a liberação automática de memória em situações em que a memória nunca deve ser liberada, como ao usar a função GetCommandLine no Kernel32.dll, que retorna um ponteiro para a memória do kernel.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. Para obter detalhes sobre como liberar a memória manualmente, consulte a Amostra de buffers.For details on manually freeing memory, see the Buffers Sample.

Marshaling padrão para classesDefault marshaling for classes

As classes podem ter o marshaling realizado somente pela interoperabilidade COM e sempre têm o marshaling realizado como interfaces.Classes can be marshaled only by COM interop and are always marshaled as interfaces. Em alguns casos, a interface usada para realizar marshaling da classe é conhecida como a interface de classe.In some cases the interface used to marshal the class is known as the class interface. Para obter informações sobre como substituir a interface de classe por uma interface de sua preferência, confira Apresentando a interface de classe.For information about overriding the class interface with an interface of your choice, see Introducing the class interface.

Passando classes para o COMPassing Classes to COM

Quando uma classe gerenciada é passada para o COM, o marshaler de interoperabilidade encapsula a classe automaticamente com um proxy COM e passa a interface de classe produzida pelo proxy para a chamada de método 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. Em seguida, o proxy delega todas as chamadas na interface de classe novamente para o objeto gerenciado.The proxy then delegates all calls on the class interface back to the managed object. O proxy também expõe interfaces que não são implementadas pela classe explicitamente.The proxy also exposes other interfaces that are not explicitly implemented by the class. O proxy implementa automaticamente interfaces como IUnknown e IDispatch em nome da classe.The proxy automatically implements interfaces such as IUnknown and IDispatch on behalf of the class.

Passando classes para o código do .NETPassing Classes to .NET Code

As coclasses não são normalmente usadas como argumentos de método no COM.Coclasses are not typically used as method arguments in COM. Em vez disso, uma interface padrão geralmente é passada no lugar da coclass.Instead, a default interface is usually passed in place of the coclass.

Quando uma interface é passada para um código gerenciado, o marshaler de interoperabilidade é responsável por encapsular a interface com o wrapper apropriado e passar o wrapper para o método gerenciado.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. Pode ser difícil determinar quais wrapper usar.Determining which wrapper to use can be difficult. Cada instância de um objeto COM tem um único wrapper exclusivo, não importa quantas interfaces são implementadas pelo objeto.Every instance of a COM object has a single, unique wrapper, no matter how many interfaces the object implements. Por exemplo, um único objeto COM que implementa cinco interfaces distintas tem apenas um wrapper.For example, a single COM object that implements five distinct interfaces has only one wrapper. O mesmo wrapper expõe todas as cinco interfaces.The same wrapper exposes all five interfaces. Se duas instâncias do objeto COM são criadas, duas instâncias do wrapper são criadas.If two instances of the COM object are created, then two instances of the wrapper are created.

Para que o wrapper mantenha o mesmo tipo em todo seu tempo de vida, o marshaler de interoperabilidade deve identificar o wrapper correto na primeira vez que uma interface exposta pelo objeto é passada por meio do marshaler.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. O marshaler identifica o objeto examinando uma das interfaces implementadas pelo objeto.The marshaler identifies the object by looking at one of the interfaces the object implements.

Por exemplo, o marshaler determina que o wrapper de classe deve ser usado para encapsular a interface que foi passada para o código gerenciado.For example, the marshaler determines that the class wrapper should be used to wrap the interface that was passed into managed code. Quando a interface é passada pelo marshaler pela primeira vez, o marshaler verifica se a interface está sendo recebida de um objeto conhecido.When the interface is first passed through the marshaler, the marshaler checks whether the interface is coming from a known object. Essa verificação ocorre em duas situações:This check occurs in two situations:

  • Uma interface está sendo implementada por outro objeto gerenciado que foi passado para o COM em outro lugar.An interface is being implemented by another managed object that was passed to COM elsewhere. O marshaler pode identificar prontamente as interfaces expostas pelos objetos gerenciados e pode fazer a correspondência da interface com o objeto gerenciado que fornece a implementação.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. Em seguida, o objeto gerenciado é passado para o método e nenhum wrapper é necessário.The managed object is then passed to the method and no wrapper is needed.

  • Um objeto que já foi encapsulado está implementando a interface.An object that has already been wrapped is implementing the interface. Para determinar se esse é o caso, o marshaler consulta o objeto em busca de sua interface IUnknown e compara a interface retornada com as interfaces de outros objetos que já estão encapsulados.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. Se a interface for a mesma de outro wrapper, os objetos terão a mesma identidade e o wrapper existente será passado para o método.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.

Se uma interface não for de um objeto conhecido, o marshaler fará o seguinte:If an interface is not from a known object, the marshaler does the following:

  1. O marshaler consulta o objeto em busca da interface IProvideClassInfo2.The marshaler queries the object for the IProvideClassInfo2 interface. Se for fornecido, o marshaler usará o CLSID retornado de IProvideClassInfo2.GetGUID para identificar a coclass que fornece a interface.If provided, the marshaler uses the CLSID returned from IProvideClassInfo2.GetGUID to identify the coclass providing the interface. Com o CLSID, o marshaler pode localizar o wrapper no Registro, caso o assembly já tenha sido registrado anteriormente.With the CLSID, the marshaler can locate the wrapper from the registry if the assembly has previously been registered.

  2. O marshaler consulta a interface em busca da interface IProvideClassInfo.The marshaler queries the interface for the IProvideClassInfo interface. Se for fornecido, o marshaler usará o ITypeInfo retornado de IProvideClassInfo.GetClassinfo para determinar o CLSID da classe que expõe a interface.If provided, the marshaler uses the ITypeInfo returned from IProvideClassInfo.GetClassinfo to determine the CLSID of the class exposing the interface. O marshaler pode usar o CLSID para localizar os metadados do wrapper.The marshaler can use the CLSID to locate the metadata for the wrapper.

  3. Se o marshaler ainda não puder identificar a classe, ele encapsulará a interface com uma classe wrapper genérica chamada System.__ComObject.If the marshaler still cannot identify the class, it wraps the interface with a generic wrapper class called System.__ComObject.

Marshaling padrão para representantesDefault marshaling for delegates

Um representante gerenciado tem o marshaling realizado como uma interface COM ou como um ponteiro de função, com base no mecanismo de chamada:A managed delegate is marshaled as a COM interface or as a function pointer, based on the calling mechanism:

  • Para a invocação de plataforma, um representante tem o marshaling realizado como um ponteiro de função não gerenciada, por padrão.For platform invoke, a delegate is marshaled as an unmanaged function pointer by default.

  • Para a interoperabilidade COM, um representante tem o marshaling realizado como uma interface COM do tipo _Delegate, por padrão.For COM interop, a delegate is marshaled as a COM interface of type _Delegate by default. A interface _Delegate é definida na biblioteca de tipos Mscorlib.tlb e contém o método Delegate.DynamicInvoke, que permite chamar o método referenciado pelo representante.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.

A tabela a seguir mostra as opções de marshaling para o tipo de dados do representante gerenciado.The following table shows the marshaling options for the managed delegate data type. O atributo MarshalAsAttribute fornece vários valores de enumeração UnmanagedType para realizar marshaling de representantes.The MarshalAsAttribute attribute provides several UnmanagedType enumeration values to marshal delegates.

Tipo de enumeraçãoEnumeration type Descrição do formato não gerenciadoDescription of unmanaged format
UnmanagedType.FunctionPtrUnmanagedType.FunctionPtr Um ponteiro de função não gerenciada.An unmanaged function pointer.
UnmanagedType.InterfaceUnmanagedType.Interface Uma interface do tipo _Delegate, conforme definido em Mscorlib.tlb.An interface of type _Delegate, as defined in Mscorlib.tlb.

Considere o código de exemplo a seguir, no qual os métodos da DelegateTestInterface são exportados para uma biblioteca de tipos COM.Consider the following example code in which the methods of DelegateTestInterface are exported to a COM type library. Observe que apenas os representantes marcados com a palavra-chave ref (ou ByRef) são passados como parâmetros de Entrada/Saída.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);     
}  

Representação da biblioteca de tiposType 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);  
   };  

Um ponteiro de função pode ser desreferenciado, assim como qualquer outro ponteiro de função não gerenciada pode ser desreferenciado.A function pointer can be dereferenced, just as any other unmanaged function pointer can be dereferenced.

Neste exemplo, quando os dois representantes realizam marshal como UnmanagedType.FunctionPtr, o resultado é um int e um ponteiro para um int.In this example, when the two delegates are marshaled as UnmanagedType.FunctionPtr, the result is an int and a pointer to an int. Como os tipos de delegado estão realizando marshal, int representa um ponteiro para um void (void*), que é o endereço do delegado na memória.Because delegate types are being marshaled, int here represents a pointer to a void (void*), which is the address of the delegate in memory. Em outras palavras, esse resultado só ocorre em sistemas Windows de 32 bits, pois int representa o tamanho do ponteiro de função.In other words, this result is specific to 32-bit Windows systems, since int here represents the size of the function pointer.

Observação

Uma referência ao ponteiro de função para um representante gerenciado mantido por um código não gerenciado não impede o Common Language Runtime de executar a coleta de lixo no objeto gerenciado.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.

Por exemplo, o código a seguir está incorreto porque a referência ao objeto cb, passado para o método SetChangeHandler, não mantém cb ativo além da vida útil do método Test.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. Depois que o objeto cb é coletado como lixo, o ponteiro de função passado para SetChangeHandler não é mais válido.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));     
   }  
}  

Para compensar a coleta de lixo inesperada, o chamador deve garantir que o objeto cb é mantido ativo enquanto o ponteiro de função não gerenciada está em uso.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. Opcionalmente, você pode fazer com que o código não gerenciado notifique o código gerenciado quando o ponteiro de função não é mais necessário, como mostra o exemplo a seguir.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;  
   }  
}  

Marshaling padrão para tipos de valorDefault marshaling for value types

A maioria dos tipos de valor, como inteiros e números de ponto flutuante, é blittable e não exige marshaling.Most value types, such as integers and floating-point numbers, are blittable and do not require marshaling. Outros tipos não blittable têm diferentes representações na memória gerenciada e não gerenciada e exigem marshaling.Other non-blittable types have dissimilar representations in managed and unmanaged memory and do require marshaling. Além disso, outros tipos de exigem a formatação explícita no limite de interoperabilidade.Still other types require explicit formatting across the interoperation boundary.

Esta seção fornece informações sobre os seguintes tipos de valor formatados:This section provides information on the following formatted value types:

Além de descrever os tipos formatados, este tópico identifica os tipos de valor do sistema que têm um comportamento de marshaling incomum.In addition to describing formatted types, this topic identifies System Value Types that have unusual marshaling behavior.

Um tipo formatado é um tipo complexo que contém informações que controlam explicitamente o layout de seus membros na memória.A formatted type is a complex type that contains information that explicitly controls the layout of its members in memory. As informações de layout de membro são fornecidas usando o atributo StructLayoutAttribute.The member layout information is provided using the StructLayoutAttribute attribute. O layout pode ser um dos seguintes valores de enumeração LayoutKind:The layout can be one of the following LayoutKind enumeration values:

  • LayoutKind.AutomaticLayoutKind.Automatic

    Indica que o Common Language Runtime está livre para reordenar os membros do tipo para eficiência.Indicates that the common language runtime is free to reorder the members of the type for efficiency. No entanto, quando um tipo de valor é passado para um código não gerenciado, o layout dos membros é previsível.However, when a value type is passed to unmanaged code, the layout of the members is predictable. Uma tentativa de realizar marshaling de uma estrutura como essa causa uma exceção automaticamente.An attempt to marshal such a structure automatically causes an exception.

  • LayoutKind.SequentialLayoutKind.Sequential

    Indica que os membros do tipo devem ser dispostos na memória não gerenciada na mesma ordem em que aparecem na definição de tipo gerenciado.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

    Indica que os membros são dispostos de acordo com o FieldOffsetAttribute fornecido com cada campo.Indicates that the members are laid out according to the FieldOffsetAttribute supplied with each field.

Tipos de valor usados na invocação de plataformaValue Types Used in Platform Invoke

No exemplo a seguir, os tipos Point e Rect fornecem informações de layout de membro usando o 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;  
}  

Ao ter o marshaling realizado para um código não gerenciado, esses tipos formatados têm o marshaling realizado como estruturas C-style.When marshaled to unmanaged code, these formatted types are marshaled as C-style structures. Isso fornece uma maneira fácil de chamar uma API não gerenciada que tem argumentos de estrutura.This provides an easy way of calling an unmanaged API that has structure arguments. Por exemplo, as estruturas POINT e RECT podem ser passadas para a função PtInRect da API do Microsoft Windows da seguinte maneira: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);  

Passe estruturas usando a seguinte definição de invocação de plataforma: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);
}

O tipo de valor Rect deve ser passado por referência porque a API não gerenciada está esperando que um ponteiro para um RECT seja passado para a função.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. O tipo de valor Point é passado por valor porque a API não gerenciada espera que POINT seja passado na pilha.The Point value type is passed by value because the unmanaged API expects the POINT to be passed on the stack. Essa diferença sutil é muito importante.This subtle difference is very important. As referências são passadas para um código não gerenciado como ponteiros.References are passed to unmanaged code as pointers. Os valores são passados para um código não gerenciado na pilha.Values are passed to unmanaged code on the stack.

Observação

Quando um tipo formatado tem o marshaling realizado como uma estrutura, apenas os campos no tipo são acessíveis.When a formatted type is marshaled as a structure, only the fields within the type are accessible. Se o tipo tiver métodos, propriedades ou eventos, eles poderão ser acessados por meio do código não gerenciado.If the type has methods, properties, or events, they are inaccessible from unmanaged code.

As classes também podem ter o marshaling realizado para um código não gerenciado como estruturas C-style, desde que tenham um layout de membro fixo.Classes can also be marshaled to unmanaged code as C-style structures, provided they have fixed member layout. As informações de layout de membro de uma classe também são fornecidas com o atributo StructLayoutAttribute.The member layout information for a class is also provided with the StructLayoutAttribute attribute. A principal diferença entre os tipos de valor com layout fixo e classes com layout fixo é a maneira na qual eles tem o marshaling realizado para um código não gerenciado.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. Os tipos de valor são passados por valor (na pilha) e, consequentemente, as alterações feitas nos membros do tipo pelo receptor não são vistas pelo chamador.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. Os tipos de referência são passados por referência (uma referência ao tipo é passada na pilha); consequentemente, todas as alterações feitas nos membros do tipo blittable de um tipo pelo receptor são vistas pelo chamador.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.

Observação

Se um tipo de referência tiver membros de tipos não blittable, a conversão será necessária duas vezes: na primeira vez, em que um argumento é passado para o lado não gerenciado e, na segunda, após o retorno da chamada.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. Devido a essa sobrecarga agregada, os parâmetros de Entrada/Saída devem ser aplicados explicitamente a um argumento se o chamador deseja ver as alterações feitas pelo receptor.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.

No exemplo a seguir, a classe SystemTime tem um layout de membro sequencial e pode ser passada para a função GetSystemTime da API do 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;   
}  

A função GetSystemTime é definida da seguinte maneira:The GetSystemTime function is defined as follows:

void GetSystemTime(SYSTEMTIME* SystemTime);  

A definição equivalente de invocação de plataforma para GetSystemTime é a seguinte: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);
}

Observe que o argumento SystemTime não é digitado como um argumento de referência porque SystemTime é uma classe, não um tipo de valor.Notice that the SystemTime argument is not typed as a reference argument because SystemTime is a class, not a value type. Ao contrário dos tipos de valor, as classes são sempre passadas por referência.Unlike value types, classes are always passed by reference.

O exemplo de código a seguir mostra outra classe Point que tem um método chamado SetXY.The following code example shows a different Point class that has a method called SetXY. Como o tipo tem um layout sequencial, ele pode ser passado para um código não gerenciado e ter o marshaling realizado como uma estrutura.Because the type has sequential layout, it can be passed to unmanaged code and marshaled as a structure. No entanto, o membro SetXY não pode ser chamado em um código não gerenciado, mesmo que o objeto seja passado por referência.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;  
   }  
}  

Tipos de valor usados na interoperabilidade COMValue Types Used in COM Interop

Os tipos formatados também podem ser passados para chamadas de método da interoperabilidade COM.Formatted types can also be passed to COM interop method calls. Na verdade, quando exportados para uma biblioteca de tipos, os tipos de valor são convertidos em estruturas automaticamente.In fact, when exported to a type library, value types are automatically converted to structures. Como mostra o exemplo a seguir, o tipo de valor Point se torna uma definição de tipo (typedef) com o nome Point.As the following example shows, the Point value type becomes a type definition (typedef) with the name Point. Todas as referências ao tipo de valor Point em outros lugares da biblioteca de tipos são substituídas pela typedef Point.All references to the Point value type elsewhere in the type library are replaced with the Point typedef.

Representação da biblioteca de tiposType 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)  
}  

As mesmas regras usadas para realizar marshaling de valores e de referências para chamadas de invocação de plataforma são usadas durante o marshaling por meio de interfaces COM.The same rules used to marshal values and references to platform invoke calls are used when marshaling through COM interfaces. Por exemplo, quando uma instância do tipo de valor Point é passada do .NET Framework para o COM, o Point é passado por valor.For example, when an instance of the Point value type is passed from the .NET Framework to COM, the Point is passed by value. Se o tipo de valor Point é passado por referência, um ponteiro para um Point é passado na pilha.If the Point value type is passed by reference, a pointer to a Point is passed on the stack. O marshaler de interoperabilidade não dá suporte a níveis mais altos de indireção (Ponto **) em qualquer direção.The interop marshaler does not support higher levels of indirection (Point **) in either direction.

Observação

Estruturas que têm o valor de enumeração LayoutKind definido como Explicit não podem ser usadas na interoperabilidade COM porque a biblioteca de tipos exportada não pode expressar um layout explícito.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.

Tipos de valor do sistemaSystem Value Types

O namespace System tem vários tipos de valor que representam o formato demarcado dos tipos primitivos de tempo de execução.The System namespace has several value types that represent the boxed form of the runtime primitive types. Por exemplo, a estrutura System.Int32 do tipo de valor representa o formato demarcado de ELEMENT_TYPE_I4.For example, the value type System.Int32 structure represents the boxed form of ELEMENT_TYPE_I4. Em vez de realizar marshaling desses tipos como estruturas, assim como ocorre com outros tipos formatados, realize marshaling deles da mesma maneira como os tipos primitivos demarcados por eles.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. Portanto, System.Int32 tem o marshaling realizado como ELEMENT_TYPE_I4, em vez de como uma estrutura que contém um único membro do tipo long.System.Int32 is therefore marshaled as ELEMENT_TYPE_I4 instead of as a structure containing a single member of type long. A tabela a seguir contém uma lista dos tipos de valor no namespace System que são representações demarcadas de tipos primitivos.The following table contains a list of the value types in the System namespace that are boxed representations of primitive types.

Tipo de valor do sistemaSystem value type Tipo de elementoElement 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

Alguns outros tipos de valor no namespace System são manipulados de maneira diferente.Some other value types in the System namespace are handled differently. Como o código não gerenciado já tem formatos bem estabelecidos para esses tipos, o marshaler tem regras especiais para realizar marshaling deles.Because the unmanaged code already has well-established formats for these types, the marshaler has special rules for marshaling them. A tabela a seguir lista os tipos de valor especiais no namespace System, bem como o tipo não gerenciado para o qual eles tem o marshaling realizado.The following table lists the special value types in the System namespace, as well as the unmanaged type they are marshaled to.

Tipo de valor do sistemaSystem value type Tipo de IDLIDL type
System.DateTime DATEDATE
System.Decimal DECIMALDECIMAL
System.Guid GUIDGUID
System.Drawing.Color OLE_COLOROLE_COLOR

O código a seguir mostra a definição dos tipos não gerenciados DATE, GUID, DECIMAL e OLE_COLOR na biblioteca de tipos Stdole2.The following code shows the definition of the unmanaged types DATE, GUID, DECIMAL, and OLE_COLOR in the Stdole2 type library.

Representação da biblioteca de tiposType 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;  

O código a seguir mostra as definições correspondentes na interface IValueTypes gerenciada.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);  
}  

Representação da biblioteca de tiposType 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);  
};  

Consulte tambémSee also