none
Redirect Console Output From DLL?

    Question

  • The web is littered with similar questions, so please read carefully before answering with the standard/simple answer.  :-)

    What sets this question apart is:

    • The console output is coming from an unmanaged DLL, NOT an external application or process.  The code is running "in-process".
    • The DLL is using "printf" or an equivalent, which, from the research I've done, seems to be different from "stdout".

    Now for a simple description of the problem.  I have an external DLL that I want to use in C#.  The DLL is written in Fortran, though I don't think that's salient.  The DLL writes information to the console.  I want to capture the console output and make it visible to the user.

    I have tried a LOT of different combinations and permutations with no success.  The most common and obvious solution, and the one you'll find in numerous similar threads, depends in one form or another on "Console.SetOut".  Unless I'm doing something completely wrong, this does not work in the scenario I've described.  (It works great when launching a separate application, but not for something in-process.)

    Any help would be greatly appreciated!

    Thanks!

    Brad.

    Tuesday, April 25, 2017 10:00 PM

All replies

  • It looks like, despite struggling with this for the better part of two days, I posted an hour too soon!  I believe I have a fix that works for me:

    [System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true)]
    public static extern int SetStdHandle(int device, IntPtr handle);
    
    const int STD_OUTPUT_HANDLE = -11;
    
    [DllImport("MyExternal.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void HelloWorld();
    
    private void CaptureOutput()
    {
        using (var fileStream = new FileStream("Test.txt", FileMode.Create))
        {
            SetStdHandle(STD_OUTPUT_HANDLE, fileStream.SafeFileHandle.DangerousGetHandle());
    
            HelloWorld();
    
            Console.OpenStandardOutput().Flush();
            fileStream.Flush();
        }
    }
    

    I still need to do more testing, but my initial tests worked like a charm.  Obviously the above code needs more error checking, etc., but it seems to be doing exactly what I wanted.

    If it works, I will:

    • Give credit to this post.
    • Come back and mark this as the answer.

    Brad.

    Wednesday, April 26, 2017 12:38 AM
  • What I'm struggling with now is that I don't want to have to wait until the DLL call finishes before displaying something to the user.  The DLL call can, in this case, take quite a while to complete.  Ideally what I'd like is that for each "printf" in the DLL I display the line for the user.  However, I haven't figured out a way to do that yet.  It's not like the "fileStream" has events I can tie into!  I assume I'll have to multi-thread to get the results I'm after, but I haven't worked through that yet, so if you have ideas on the topic, I'd love to hear them!

    Thanks!

    Brad.

    Wednesday, April 26, 2017 7:04 AM
  • Hi Pletzky,

    You could try Parallel to display something to the user quickly.

    I assume that there are four parts in the dll with WriteConsole function. You could use Parallel to invoke four parts parallel. When you "printf" first part, the second, third, forth will "printf" as well. It is more quicker than asynchronous thread.

    If your question has been solved, please mark your previous reply as answer.

    If you have something else, please post a new thread.

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, May 18, 2017 8:33 AM
    Moderator