У меня есть приложение C #, вызывающее родную C ++ DLL через некоторый код маршаллинга C ++ / CLI:
C # -> C ++ / CLI -> C ++ (без CLR)
Я хочу, чтобы DLL отправляла обновления строк обратно вызывающему приложению во время его работы. В настоящее время неуправляемая DLL записывает вывод в стандартный вывод. По сути, мне нужно зафиксировать этот вывод в пользовательском интерфейсе.
В других случаях, когда я обстреливаю неуправляемый exe, это может быть достигнуто путем простого перенаправления stdout от вызываемого к строковому буферу в данных пользовательского интерфейса, привязанных к текстовой панели.
У меня нет возможности вызвать DLL с помощью P / Invoke или обработать ее как exe, поскольку уровень взаимодействия выполняет существенную сортировку непримитивных типов. Неуправляемая DLL не имеет поддержки среды CLR и должна оставаться такой.
У меня был ограниченный успех с использованием делегатов (http://msdn.microsoft.com/en-us/library/367eeye0%28v=vs.100%29.aspx), поскольку всегда есть место, где управляемый и неуправляемый миры сталкиваются. Взяв пример в ссылке, передача управляемого делегата из C ++ / CLI, маскирующегося под собственный указатель функции на DLL, работает, но обратный вызов определяется вне области действия класса C ++ / CLI и, следовательно, не может получить доступ к управляемому делегату, переданному из вызывающий слой (C #).
В идеале я хотел бы определить класс, который принимает неуправляемые строки и может преобразовывать их в управляемые и вызывать обратно на уровень пользовательского интерфейса, но если этот класс имеет необходимую поддержку управляемых строк, его нельзя передать неуправляемому коду.
Возможно, мне не хватает простого трюка с перенаправлением, который позволил бы захватить stdout без передачи строк между слоями (например, перенаправление stdout из C ++ / CLI, полученного через делегата). Если это невозможно, может ли кто-нибудь предложить альтернативный метод?
Управляемый C ++:
using namespace System::Runtime::InteropServices;
using namespace System;
namespace BusinessObjectInterop
{
typedef void (__stdcall *UnmanagedFP)(std::string);
//Callback function
public delegate void SetProgressDelegate(std::string);
void SetProgress(std::string s) {
Console::WriteLine(s);
//set m_progress - could use managed delegate passed from UI and exposed in static method in CIntermediate?
}
public ref class CIntermediate
{
public:
//Invoked by managed (C#) UI
void ^ CallBusinessObject(Object ^ data, String ^ progress)
{
//Do some data marshalling...
//...
m_progress = progress;
//Create wrapper for managed delegate
SetProgressDelegate^ fp = gcnew SetProgressDelegate(SetProgress);
GCHandle gch = GCHandle::Alloc(fp);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp);
UnmanagedFP cb = static_cast<UnmanagedFP>(ip.ToPointer());
//Call unmanaged DLL
BusinessObject::DoStuff(cb);
gch.Free();
}
private:
String ^ m_progress;
};
}
Заранее спасибо.