先來介紹兩個預處理指令:
#pragma unmanaged
#pragma managed
這兩個預處理指令,控制函數編譯成托管函數,還是非托管函數。是函數級別的預控制指令。
1. 托管函數傳送字符串給非托管函數
分三步走
a.先調用StringToHGlobalAnsi將string轉換成IntPtr類型變量,(IntPtr是Net framework用于表示指針或句柄的平臺特定類型。) 這個轉換過程就是將托管 String 中的內容復制到非托管內存,并在復制時轉換為 ANSI 格式。此處,并不是將托管內存傳遞出來,而是,在非托管堆中分配內存并返回地址。所以,這塊內存需要自己釋放。
b.通過ToPointer方法將IntPtr實例的值轉換為指向未指定的類型的指針(void *)。
c.使用完后調用FreeHGlobal 釋放a步中的非托管內存。
看一個完整的例子:
// MarshalANSI1.cpp
// compile with: /clr
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace System;
using namespace System::Runtime::InteropServices;
#pragma unmanaged
void NativeTakesAString(const char* p) {
printf_s("(native) received '%s'\n", p);
}
#pragma managed
int main() {
String^ s = gcnew String("sample string");
IntPtr ip = Marshal::StringToHGlobalAnsi(s);
const char* str = static_cast<const char*>(ip.ToPointer());
Console::WriteLine("(managed) passing string
");
NativeTakesAString( str );
Marshal::FreeHGlobal( ip );
}
2. 非托管函數傳遞字符串給托管函數
這個簡單的多了。只需要調用Marshal::PtrToStringAnsi把傳統的c字符串轉換成托管字符串即可。
例子:
// MarshalANSI2.cpp
// compile with: /clr
#include <iostream>
#include <vcclr.h>
using namespace std;
using namespace System;
using namespace System::Runtime::InteropServices;
#pragma managed
void ManagedStringFunc(char* s) {
String^ ms = Marshal::PtrToStringAnsi(static_cast<IntPtr>(s));
Console::WriteLine("(managed): received '{0}'", ms);
}
#pragma unmanaged
void NativeProvidesAString() {
cout << "(native) calling managed func
\n";
ManagedStringFunc("test string");
}
#pragma managed
int main() {
NativeProvidesAString();
}