У меня есть DLL, написанная на C #, и выставлена на COM. Я использую DLL в построителе … Я могу создать экземпляр класса, но у меня возникли проблемы с маршалингом возвращаемого значения из вызовов метода C #.
C #
public string GetValue([MarshalAs(UnmanagedType.LPWStr)] string key)
{
return "value";
}
Переведенная функция по мере ее импорта в конструктор:
virtual HRESULT STDMETHODCALLTYPE GetValue(LPWSTR key/*[in]*/,
BSTR* pRetVal/*[out,retval]*/) = 0;
Я очень мало знаю о C ++. Параметр «ключ» передается нормально, потому что я могу использовать атрибут «MarshalAs» для параметра, но я либо не знаю, как объявить его для возвращаемого значения, либо не знаю, как вызвать функция на стороне C ++ (я пробовал несколько вещей, просто догадываясь).
ОБНОВЛЕНИЕ: Хорошо, я только смог решить проблему, взяв пример Антона и попробовав модификации, основанные на комментариях Ганса. Ответ Antons работает точно так, как он показывает, но из-за опасений, высказанных по поводу проблемы управления памятью, я не стал применять атрибут return в C #, а код C ++ вызывает функцию следующим образом:
BSTR result;
obj->GetValue(key, &result);
SysFreeString(key);
SysFreeString(result);
Я хотел бы отдать должное обоим ответам за помощь мне в этом, они оба были необходимы, чтобы предоставить мне информацию, в которой я нуждался.
Вы можете применить атрибут [return:], но это действительно плохая идея. Проблема с этой сигнатурой функции заключается в том, что вызываемый должен выделить буфер для строки, а вызывающий должен освободить его. Это требует, чтобы оба использовали одну и ту же кучу. Это будет не в случае, когда вы заставляете его использовать LPWSTR, CLR использует свою собственную кучу, и вы не можете получить к ней доступ из своего собственного кода, вы не можете получить требуемый дескриптор кучи.
Обе части кода должен используйте ту же кучу. И есть один специально для этого, куча COM. BSTR — это строковый тип, который использует эту кучу, CLR автоматически использует его, как вы могли бы сказать из подписи. Чтобы использовать его, просто получите доступ к указателю pRetVal после вызова, это wchar_t * под капотом. И вы должны выпустить его позже, вызовите SysFreeString ().
Чтобы применить атрибут к возвращаемому значению:
[return: MarshalAs(UnmanagedType.LPWStr)]
public string GetValue([MarshalAs(UnmanagedType.LPWStr)] string key)
{
return "value";
}
Вам нужно будет освободить строку вручную, используя (я думаю) CoTaskMemFree
:
LPWSTR result ;
if (SUCCEEDED (obj->GetValue (key, &result)))
{
// use result and free it when no longer needed
CoTaskMemFree (result) ;
}