将 BSTR 字符串作为托管代码和非托管代码之间的边界传递(COM 互操作)

Posted

技术标签:

【中文标题】将 BSTR 字符串作为托管代码和非托管代码之间的边界传递(COM 互操作)【英文标题】:passing BSTR string as a perimeter between managed and unmanaged code (COM interop) 【发布时间】:2019-01-09 10:13:17 【问题描述】:

在处理 com interop 时,我按照link 上的教程进行操作。代码运行良好,因为我根据我的要求做了一些修改,但是在处理字符串时出现了问题。我在这里使用 BSTR 字符串作为这里的周边。 这是我从 c++ 调用的 c# 中的函数

  public  string ShowDialog([MarshalAs(UnmanagedType.BStr)] string stringToPrint)
    
      //  Console.WriteLine(" Enter TOTP input:");
       // stringToPrint = Console.ReadLine();

        if (stringToPrint == "111111")
        

            MessageBox.Show("true");



        
        else
        
            MessageBox.Show("false");

        

        return stringToPrint;
    

这是我正在调用的代码的 C++ 主函数部分

CoInitialize(NULL);

MyInterop::IMyDotNetInterfacePtr pDotNetCOMPtr;

HRESULT hRes = pDotNetCOMPtr.CreateInstance(MyInterop::CLSID_MyDotNetClass);
if (hRes == S_OK)


    BSTR lResult ;

    cout << "enter TOTP input" << endl;

    _bstr_t bstrStatus = SysAllocString(L"111111");

    pDotNetCOMPtr->ShowDialog(bstrStatus,&lResult);

    SysFreeString(bstrStatus);




CoUninitialize();

system("pause");

这是输出

我面临的问题如下:

虽然我在 c# 中使用了返回函数,但从 c++ 代码传递 BSTR 字符串后,控制台上没有返回它 是否可以在控制台上动态插入输入,因为我在这里使用 SysAllocString(""),这使得它有点硬编码。

【问题讨论】:

您的意思是 parameter 而不是 perimeter?也完全不清楚你在问我什么。 是的!对此感到抱歉,我的意思是“参数”。我只想在控制台上询问输入,而不是使用 SysAllocString,并希望在将输入传递给 c# 函数后将其返回给 c++。 我不知道你说的 perimeter 是什么意思,抱歉。 确定它的“参数”.my bad 除此之外,我仍然不知道你在问什么。您拥有的代码看起来很好。 【参考方案1】:

当您使用 Visual Studio 和 #import 指令时,生成的代码使用 _bstr_t,它是 BSTR(原始 Windows 类型)之上的智能包装类。

因此,您不必使用 SysAllocString 或 SysFreeString,您可以非常自然地使用 _bstr_t。例如,在您的情况下,如果您的 C# 方法签名是这样的:

public string ShowDialog(string stringToPrint) // you don't need the MarshalAs here, the TLB will build it as a BSTR

那么你可以使用这样的 C++ 代码:

... other imports or includes
// import mscorlib so we have a full generated cool code (I recommend not to use raw_interfaces_only)
// we rename 'or' to something that doesn't pose problems. Your mileage can vary depending on your building context...
#import "C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb" rename("or","whatever")
#import "C:\myPath\MyClassLibrary1.tlb" // adapt to your path

int main()

  CoInitialize(NULL);
  
    MyClassLibrary1::_Class1Ptr ptr;
    HRESULT hr = ptr.CreateInstance(__uuidof(MyClassLibrary1::Class1)); // should return S_OK/0

    _bstr_t input = L"111111";
    _bstr_t res = ptr->ShowDialog(input); // assign the return string
    wprintf(L"res:%s\n", res.GetBSTR()); // output (unicode) result to console
  
  CoUninitialize();

你也可以直接这样写:

_bstr_t res = ptr->ShowDialog(L"111111");

// 或 this(自动 ansi 到 unicode 转换)

_bstr_t res = ptr->ShowDialog("111111");

所有 _bstr_t 都会自动分配和释放。

【讨论】:

hay @Simon .thanx 为答案,但“ptr->ShowDialog(input)”部分需要第二个参数,因为 c# 中定义的函数是返回类型。 @ShahnawazKhanNiazi - 不。仔细阅读我的答案,如果您不相信我,请测试一下。 我尝试了很长时间,但“res”变量每次都返回“0”值。知道可能出了什么问题吗?因为我完全按照你上面解释的。 尝试在某处发布一个复制项目(.zip),以便我们查看。

以上是关于将 BSTR 字符串作为托管代码和非托管代码之间的边界传递(COM 互操作)的主要内容,如果未能解决你的问题,请参考以下文章

如何在托管 (C#) 和非托管 (C++) 代码之间来回传递数组内容

在托管代码和非托管代码之间传递非托管结构的安全数组

在 C# 和非托管 C++ 之间传递自定义对象

托管代码和非托管代码

托管和非托管代码是啥意思? [复制]

托管代码和非托管代码的区别