Передача строки BSTR в качестве периметра между управляемым и неуправляемым кодом (взаимодействие COM)
Работая над взаимодействием, я следовал руководству по этой ссылке. Код работает нормально, так как я сделал некоторые изменения в зависимости от моих требований, но проблема возникает при работе со строкой. Я использую здесь строку 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");
Проблемы, с которыми я сталкиваюсь, следующие:
- Строка BSTR не возвращается на консоль после того, как она передана из кода C++, хотя я использую функцию возврата в C#
- Можно ли вводить ввод динамически на консоли, поскольку я использую SysAllocString("") здесь, что делает его несколько жестко запрограммированным.
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");
// или это (с автоматическим преобразованием ANSI в Unicode)
_bstr_t res = ptr->ShowDialog("111111");
Все _bstr_t автоматически распределяются и освобождаются.