2

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

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

我希望 DLL 在运行时将字符串更新发布回调用应用程序。当前,非托管 DLL 将输出写入标准输出。本质上,我需要在 UI 中捕获此输出。

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

我没有选择使用 P/Invoke 调用 DLL 或将其作为 exe 外壳,因为互操作层执行非原始类型的基本编组。非托管 DLL 没有 CLR 支持,必须保持这种方式。

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

理想情况下,我想定义一个接受非托管字符串的类,并且可以将这些转换为托管并回调到 UI 层,但是如果此类对托管字符串具有必要的支持,则不能将其传递给非托管代码。

我可能错过了一个简单的重定向技巧,它允许在不在层之间传递字符串的情况下捕获标准输出(例如,从通过委托接收的 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;

    };
}

提前致谢。

4

1 回答 1

8

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

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

按 F5。Presto,现在您已经拥有了一个控制台窗口,显示来自 DLL 的调试输出。还有你的常规 GUI。

于 2012-10-06T00:49:10.423 回答