2

C++/CLI マーシャリング コードを介してネイティブ C++ DLL を呼び出す C# アプリケーションがあります。

C# --> C++/CLI --> C++ (CLR なし)

実行中に、DLL が文字列の更新を呼び出し元のアプリケーションにポストするようにします。現在、アンマネージ DLL は出力を stdout に書き込みます。基本的に、UI でこの出力をキャプチャする必要があります。

アンマネージ exe をシェルしている他のケースでは、テキスト パネルにバインドされた UI データ内の文字列バッファーに呼び出し先から stdout をリダイレクトするだけで実現できます。

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 レイヤーにコールバックできるクラスを定義したいと考えていますが、このクラスがマネージド文字列を必要に応じてサポートしている場合、それをアンマネージド コードに渡すことはできません。

レイヤー間で文字列を渡さずに stdout をキャプチャできるリダイレクトの簡単なトリックを見逃している可能性があります (たとえば、デリゲート経由で受信した C++/CLI から stdout をリダイレクトするなど)。これが不可能な場合、誰かが代替手法を提案できますか?

マネージ 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 は stdout を所有しておらず、プロセスが所有しています。また、プロセスはGUIアプリであるため作成されません。また、別のプロセスが必要なため、リダイレクトも機能しません。

回避策は簡単です。デバッグ構成が選択されていることを確認してください。プロジェクト、プロパティ、リンカー、システムを右クリックします。サブシステムの設定を「コンソール (/SUBSYSTEM:CONSOLE)」アプリケーション タブに変更します。出力タイプの設定を「コンソールアプリケーション」に変更します。

F5 を押します。これで、DLL からのデバッグ出力を表示する両方のコンソール ウィンドウができました。そしてあなたの通常のGUI。

于 2012-10-06T00:49:10.423 に答える