如何:使用 C++ 互操作封送 COM 字符串

本主题演示如何将 BSTR(COM 编程中支持的基本字符串格式)从托管函数传递到非托管函数,反之亦然。 若要与其他字符串类型进行互操作,请参阅以下主题:

以下代码示例使用 managed 和 unmanaged #pragma 指令在同一文件中实现托管和非托管函数,但如果这些函数在单独的文件中定义,则将以相同方式进行交互。 仅包含非托管函数的文件不需要使用 /clr(公共语言运行时编译)进行编译。

示例:将 BSTR 从托管函数传递到非托管函数

下面的示例演示如何将 BSTR(COM 编程中使用的字符串格式)从托管函数传递到非托管函数。 调用托管函数使用 StringToBSTR 获取 .NET System.String 内容的 BSTR 表示形式的地址。 该指针使用 pin_ptr (C++/CLI) 固定,以确保在非托管函数执行时,其物理地址在垃圾回收周期期间不会更改。 禁止垃圾收集器移动内存,直到 pin_ptr (C++/CLI) 超出范围。

// MarshalBSTR1.cpp
// compile with: /clr
#define WINVER 0x0502
#define _AFXDLL
#include <afxwin.h>

#include <iostream>
using namespace std;

using namespace System;
using namespace System::Runtime::InteropServices;

#pragma unmanaged

void NativeTakesAString(BSTR bstr) {
   printf_s("%S", bstr);
}

#pragma managed

int main() {
   String^ s = "test string";

   IntPtr ip = Marshal::StringToBSTR(s);
   BSTR bs = static_cast<BSTR>(ip.ToPointer());
   pin_ptr<BSTR> b = &bs;

   NativeTakesAString( bs );
   Marshal::FreeBSTR(ip);
}

示例:将 BSTR 从非托管函数传递到托管函数

下面的示例演示如何将 BSTR 从非托管函数传递到托管函数。 接收托管函数可以使用字符串作为 BSTR,也可以使用 PtrToStringBSTR 将其转换为 String 以与其他托管函数一起使用。 由于表示 BSTR 的内存是在非托管堆上分配的,因此不需要固定,因为非托管堆上没有垃圾回收。

// MarshalBSTR2.cpp
// compile with: /clr
#define WINVER 0x0502
#define _AFXDLL
#include <afxwin.h>

#include <iostream>
using namespace std;

using namespace System;
using namespace System::Runtime::InteropServices;

#pragma managed

void ManagedTakesAString(BSTR bstr) {
   String^ s = Marshal::PtrToStringBSTR(static_cast<IntPtr>(bstr));
   Console::WriteLine("(managed) convered BSTR to String: '{0}'", s);
}

#pragma unmanaged

void UnManagedFunc() {
   BSTR bs = SysAllocString(L"test string");
   printf_s("(unmanaged) passing BSTR to managed func...\n");
   ManagedTakesAString(bs);
}

#pragma managed

int main() {
   UnManagedFunc();
}

另请参阅

使用 C++ 互操作(隐式 PInvoke)