在C#调用者中从非托管DLL捕获stdout [英] Capturing stdout from unmanaged DLL in C# caller

查看:128
本文介绍了在C#调用者中从非托管DLL捕获stdout的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个C#应用程序通过一些C ++ / CLI编组代码调用本地C ++ DLL:



C# - > C ++ / CLI - > C ++ )



我希望DLL在运行时将字符串更新发回调用的应用程序。当前非托管DLL将输出写入stdout。基本上我需要在UI中捕获这个输出。



在其他情况下,我正在shelling一个非托管exe,这可以通过简单地将stdout从被调用者重定向到绑定到文本面板的UI数据中的字符串缓冲区来实现。



我没有选择使用P / Invoke或shelling它作为exe调用DLL,因为interop层执行非原始类型的必要编组。



我使用代理的成功率有限( http://msdn.microsoft.com/en-us/library/367eeye0(v = vs.100).aspx ),因为总是似乎存在管理和非管理世界碰撞的地方。以链接中的示例为例,将C ++ / CLI中的托管委托传递为本地函数指针到DLL,但是回调定义在C ++ / CLI类的范围之外,因此无法访问从中传递的托管委托调用层(C#)。



理想情况下,我想定义一个类接受非托管字符串,并可以将它们转换为托管和回调到UI层,如果这个类对托管字符串有必要的支持,它不能被传递到非托管代码。



我可能缺少一个重定向的技巧,可以捕获stdout而不在层之间传递字符串(例如,通过委托接收的重定向来自C ++ / CLI的stdout)。如果这不可能,任何人都可以提出替代方法?



托管C ++:

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

namespace BusinessObjectInterop
{
typedef void(__stdcall * UnmanagedFP)(std :: string);

//回调函数
public delegate void SetProgressDelegate(std :: string);


void SetProgress(std :: string s){
Console :: WriteLine(s);

// set m_progress - 可以使用从UI传递的托管委托,并在CIntermediate的静态方法中公开?
}

public ref class CIntermediate
{
public:

//由托管(C#)UI调用
void ^ CallBusinessObject(Object ^ data,String ^ progress)
{
//进行一些数据编组...
// ...

m_progress = progress;

//为托管委托创建包装器
SetProgressDelegate ^ fp = gcnew SetProgressDelegate(SetProgress);
GCHandle gch = GCHandle :: Alloc(fp);
IntPtr ip = Marshal :: GetFunctionPointerForDelegate(fp);
UnmanagedFP cb = static_cast< UnmanagedFP>(ip.ToPointer());

//调用非托管DLL
BusinessObject :: DoStuff(cb);
gch.Free();
}

private:
String ^ m_progress;

};
}

提前感谢。

解决方案

对,这不行。一个DLL不拥有stdout,一个进程。并且您的进程不创建一个,因为它是GUI应用程序,也不能重定向工作,因为这需要另一个进程。



解决方法很简单。确保选择了调试配置。右键单击您的项目,属性,链接器,系统。将子系统设置更改为控制台(/ SUBSYSTEM:CONSOLE)应用程序选项卡。将输出类型设置更改为控制台应用程序。



按F5。 Presto,现在你有一个控制台窗口显示DLL的调试输出。和您的常规GUI。


I have a C# application calling a native C++ DLL via some C++/CLI marshalling code:

C# --> C++/CLI --> C++ (no CLR)

I want the DLL to post string updates back to the calling application while it is running. Currently the unmanaged DLL writes output to stdout. Essentially I need to capture this output in the UI.

In other cases where I am shelling an unmanaged exe this can be achieved by simply redirecting stdout from the callee to a string buffer in the UI data bound to a text panel.

I do not have the option to call the DLL using P/Invoke or shelling it as an exe, since the interop layer performs essential marshalling of non-primitive types. The unmanaged DLL has no CLR support and must remain this way.

I had limited success using delegates (http://msdn.microsoft.com/en-us/library/367eeye0(v=vs.100).aspx), as there always seems to be somewhere that the managed and unmanaged worlds collide. Taking the example in the link, passing a managed delegate from C++/CLI masquerading as a native function pointer to the DLL works, but the callback is defined outside the scope of the C++/CLI class and therefore cannot access a managed delegate passed in from the calling layer (C#).

Ideally I would like to define a class that accepts unmanaged strings, and can convert these to managed and call back into the UI layer, but if this class has the necessary support for managed strings, it cannot be passed to unmanaged code.

I may be missing a simple trick with redirection that would allow stdout to be captured without passing strings between layers (e.g redirecting stdout from C++/CLI that is received via a delegate). If this is not possible can anyone suggest an alternative technique?

Managed 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;

    };
}

Thanks in advance.

解决方案

Right, this doesn't work. A DLL doesn't own stdout, a process does. And your process doesn't create one since it is GUI app, nor can redirection work since that requires another process.

The workaround is simple. Ensure you've got the Debug configuration selected. Right-click your project, Properties, Linker, System. Change the SubSystem setting to "Console (/SUBSYSTEM:CONSOLE)" Application tab. Change the Output type setting to "Console application".

Press F5. Presto, now you've got both a console window that displays debugging output from the DLL. And your regular GUI.

这篇关于在C#调用者中从非托管DLL捕获stdout的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆