Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
As funções nativas que aceitam strings no estilo C podem ser chamadas usando o tipo System::String de cadeia de caracteres CLR através do suporte de invocação de plataforma (P/Invoke) do .NET Framework. Recomendamos que você use os recursos de interoperabilidade C++ em vez de P/Invoke quando possível. porque P/Invoke fornece poucos relatórios de erros em tempo de compilação, não é seguro para digitação e pode ser tedioso de implementar. Se a API não gerenciada for empacotada como uma DLL e o código-fonte não estiver disponível, P/Invoke será a única opção. Caso contrário, consulte Usando interoperabilidade C++ (P/Invoke implícito).
As cadeias de caracteres gerenciadas e não gerenciadas são dispostas de forma diferente na memória, portanto, a passagem de cadeias de caracteres de funções gerenciadas para não gerenciadas requer que o MarshalAsAttribute atributo instrua o compilador a inserir os mecanismos de conversão necessários para empacotar os dados da cadeia de caracteres corretamente e com segurança.
Tal como acontece com funções que usam apenas tipos de dados intrínsecos, DllImportAttribute é usado para declarar pontos de entrada gerenciados nas funções nativas. As funções que passam cadeias de caracteres podem usar um identificador para o String tipo em vez de definir esses pontos de entrada como tendo cadeias de caracteres no estilo C. O uso desse tipo solicita que o compilador insira o código que executa a conversão necessária. Para cada argumento de função numa função não gerida que usa uma cadeia de caracteres, utilize o atributo MarshalAsAttribute para indicar que o objeto String deve ser convertido para a função nativa como uma cadeia de caracteres no estilo C.
O marshaler encapsula a chamada para a função não gerenciada em uma rotina de encapsulamento oculta. A rotina do wrapper fixa e copia a cadeia de caracteres gerenciada em uma cadeia de caracteres alocada localmente no contexto não gerenciado. A cópia local é então passada para a função não gerenciada. Quando a função não gerenciada retorna, o wrapper exclui o recurso. Ou, se estava na pilha, é recuperado quando o invólucro sai do escopo. A função não gerenciada não é responsável por essa memória. O código não gerenciado apenas cria e exclui memória na pilha configurada por seu próprio CRT, portanto, nunca há um problema com o marshaller usando uma versão CRT diferente.
Se sua função não gerenciada retornar uma cadeia de caracteres, como um valor de retorno ou um parâmetro out, o empacotador a copiará em uma nova cadeia de caracteres gerenciada e, em seguida, liberará a memória. Para obter mais informações, consulte Comportamento de marshaling padrão e Marshaling Data with Platform Invoke.
Exemplo
O código a seguir consiste em um módulo não gerenciado e um módulo gerenciado. O módulo não gerenciado é uma DLL que define uma função chamada TakesAString.
TakesAString aceita uma cadeia de caracteres estreita no estilo C na forma de um char*.
// TraditionalDll2.cpp
// compile with: /LD /EHsc
#include <windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif
extern "C" {
TRADITIONALDLL_API void TakesAString(char*);
}
void TakesAString(char* p) {
printf_s("[unmanaged] %s\n", p);
}
O módulo gerido é uma aplicação de linha de comando que importa a função TakesAString, mas define-a como recebendo um System.String gerido em vez de um char*. O MarshalAsAttribute atributo é usado para indicar como a cadeia de caracteres gerenciada deve ser empacotada quando TakesAString é chamada.
// MarshalString.cpp
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;
value struct TraditionalDLL
{
[DllImport("TraditionalDLL2.dll")]
static public void
TakesAString([MarshalAs(UnmanagedType::LPStr)]String^);
};
int main() {
String^ s = gcnew String("sample string");
Console::WriteLine("[managed] passing managed string to unmanaged function...");
TraditionalDLL::TakesAString(s);
Console::WriteLine("[managed] {0}", s);
}
Essa técnica constrói uma cópia da cadeia de caracteres no heap não gerenciado, de modo que as alterações feitas na cadeia de caracteres pela função nativa não serão refletidas na cópia gerenciada da cadeia de caracteres.
Nenhuma parte da DLL é exposta ao código gerenciado pela diretiva tradicional #include . Na verdade, a DLL é acessada apenas em tempo de execução, portanto, problemas em funções importadas usando DllImport não são detetados em tempo de compilação.