Como: seqüências de empacotamento usando PInvoke
Este tópico explica como nativas funções que aceitam seqüências de caracteres de estilo c pode ser chamado usar o tipo de string do CLR System usando.Suporte de invocação de plataforma do NET Framework.Programadores do Visual C++ são incentivados a usar os recursos de interoperabilidade de C++ em vez disso (quando possível) porque P/Invoke fornece relatórios de erro em tempo de compilar pouco, não é tipo seguro e pode ser entediante implementar.Se a API não gerenciada é empacotada como uma DLL e o código-fonte não está disponível, P/Invoke é a única opção, mas caso contrário, consulte Usando interoperabilidade C++ (PInvoke implícita).
Gerenciado e seqüências de caracteres são dispostas diferente na memória, portanto passar seqüências de gerenciado para não gerenciadas funções requer o MarshalAsAttribute atributo para instruir o compilador a inserir os mecanismos de conversão necessária para empacotamento de dados de seqüência de caracteres corretamente e com segurança.
Como com funções que usam somente tipos de dados intrínseco, DllImportAttribute é usado para declarar os pontos de entrada gerenciado em funções nativas, mas – para passar cadeias de caracteres – em vez de definir esses pontos de entrada a obtenção de seqüências de caracteres de estilo C, um identificador para o String tipo pode ser usado em vez disso.Isso solicita que o compilador a inserir o código que executa a conversão necessária.Para cada argumento de função em uma função não gerenciada que usa uma seqüência de MarshalAsAttribute atributo deve ser usado para indicar que o objeto de seqüência de caracteres deve ser empacotado para a função nativa como uma seqüência de caracteres de estilo C.
Exemplo
O código a seguir consiste em uma não gerenciado e um módulo gerenciado.O módulo não gerenciado é uma DLL que define uma função chamada TakesAString que aceita uma seqüência ANSI de estilo c na forma de um char *.O módulo gerenciado é um aplicativo de linha de comando que importa a função TakesAString, mas define como tirar string gerenciado em vez de um char *.O MarshalAsAttribute atributo é usado para indicar como a cadeia gerenciada deve ser empacotada TakesAString é chamado.
O módulo gerenciado é compilado com /clr, mas /clr: pura funciona bem.
// 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);
}
// 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 faz com que uma cópia da seqüência a ser construído no heap não gerenciada, para que as alterações feitas pela função nativa a seqüência de caracteres não serão refletidas na cópia da seqüência de caracteres gerenciada.
Observe que nenhuma parte da DLL é exposto para código gerenciado via # tradicional incluir diretiva.Na verdade, a DLL é acessada no tempo de execução somente para problemas com funções importados com DllImport não serão detectados em tempo de compilação.