dllimport stdout gets eaten

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • not_a_commie

    dllimport stdout gets eaten

    I changed the stdout in my C# app using Console.SetOut. It works fine
    for all my Console.Out.Wri te calls and with log4net. However, I don't
    see any output from native dlls that write to stdout. What am I doing
    wrong?
  • =?ISO-8859-1?Q?Arne_Vajh=F8j?=

    #2
    Re: dllimport stdout gets eaten

    not_a_commie wrote:
    I changed the stdout in my C# app using Console.SetOut. It works fine
    for all my Console.Out.Wri te calls and with log4net. However, I don't
    see any output from native dlls that write to stdout. What am I doing
    wrong?
    Nothing.

    Why should changing something inside the Console class
    change what some native code does ?

    You need to do something in your native code to
    get output where you want it.

    Arne

    Comment

    • Ben Voigt [C++ MVP]

      #3
      Re: dllimport stdout gets eaten

      Arne Vajhøj wrote:
      not_a_commie wrote:
      >I changed the stdout in my C# app using Console.SetOut. It works fine
      >for all my Console.Out.Wri te calls and with log4net. However, I don't
      >see any output from native dlls that write to stdout. What am I doing
      >wrong?
      >
      Nothing.
      >
      Why should changing something inside the Console class
      change what some native code does ?
      If for example, that managed code was a wrapper around SetStdHandle. But
      it's not, it changes Console.Out rather than changing stdout underneath.
      >
      You need to do something in your native code to
      get output where you want it.
      SetStdHandle, most likely. And then it doesn't have to be a change to the
      native code, as long as it's called from the same process.
      >
      Arne

      Comment

      • =?ISO-8859-1?Q?Arne_Vajh=F8j?=

        #4
        Re: dllimport stdout gets eaten

        Ben Voigt [C++ MVP] wrote:
        Arne Vajhøj wrote:
        >not_a_commie wrote:
        >>I changed the stdout in my C# app using Console.SetOut. It works fine
        >>for all my Console.Out.Wri te calls and with log4net. However, I don't
        >>see any output from native dlls that write to stdout. What am I doing
        >>wrong?
        >Nothing.
        >>
        >Why should changing something inside the Console class
        >change what some native code does ?
        >
        If for example, that managed code was a wrapper around SetStdHandle. But
        it's not, it changes Console.Out rather than changing stdout underneath.
        I can not see how it could be a wrapper around SetStdHandle. Out is a
        TextWriter. If I write my own class that extends TextWriter and call
        SetOut with it. There are no handle to pass to native and no way
        for the native code to call my class.
        >You need to do something in your native code to
        >get output where you want it.
        >
        SetStdHandle, most likely. And then it doesn't have to be a change to the
        native code, as long as it's called from the same process.
        I was thinking freopen, but if it is documented that SetStdHandle
        interacts "nicely" with the C RTL, then that can obviously be
        used.

        Arne

        Comment

        • not_a_commie

          #5
          Re: dllimport stdout gets eaten

          I got this to work. The setvbuf is critical. Here's my test code.
          First, the dll:

          #include <stdio.h>

          __declspec(dlle xport) void PrintMsg();

          void PrintMsg()
          {
          setvbuf(stdout, NULL, _IONBF, 0);
          printf("blah blah blah\n");
          }

          Second, the C# code:

          using System;
          using System.Diagnost ics;
          using System.IO;
          using System.IO.Pipes ;
          using System.Runtime. InteropServices ;
          using System.Threadin g;
          using System.Windows;
          using System.Windows. Controls;

          namespace TestPrintf
          {
          class Program
          {
          [DllImport("kern el32.dll", SetLastError = true)]
          protected static extern bool SetStdHandle(in t nStdHandle, IntPtr
          hConsoleOutput) ;

          [DllImport("Prin tDll.dll", CallingConventi on =
          CallingConventi on.Cdecl)]
          protected static extern void PrintMsg();

          [STAThread]
          public static void Main(string[] args)
          {
          var id = Process.GetCurr entProcess().Id ; // make this instance
          unique
          var serverPipe = new NamedPipeServer Stream("console Redirect" + id,
          PipeDirection.I n, 1);
          var clientPipe = new NamedPipeClient Stream(".", "consoleRedirec t" +
          id, PipeDirection.O ut, PipeOptions.Wri teThrough);
          ThreadPool.Queu eUserWorkItem(s tate =>
          {
          serverPipe.Wait ForConnection() ;
          using (var stm = new StreamReader(se rverPipe))
          {
          while (serverPipe.IsC onnected)
          {
          try
          {
          var txt = stm.ReadLine();
          if (!string.IsNull OrEmpty(txt))
          MessageBox.Show ("Got stdout with: " + txt);
          }
          catch (IOException)
          {
          break; // normal disconnect
          }
          }
          }
          }, null);
          clientPipe.Conn ect();
          var hr11 = new HandleRef(clien tPipe,
          clientPipe.Safe PipeHandle.Dang erousGetHandle( ));
          SetStdHandle(-11, hr11.Handle); // redirect stdout to my pipe


          var app = new Application();
          var win = new Window { Width = 300, Height = 200 };
          var sp = new StackPanel { Orientation = Orientation.Hor izontal };
          win.Content = sp;
          var b1 = new Button { Content = "Direct", Width = 100 };
          sp.Children.Add (b1);
          var b2 = new Button { Content = "Indirect", Width = 100 };
          sp.Children.Add (b2);
          var b3 = new Button { Content = "DllImport" , Width = 100 };
          sp.Children.Add (b3);

          b1.Click += (sender, e) =Console.Out.Wr iteLine("Direct Button was
          clicked");
          b2.Click += (sender, e) =>
          {
          using (var stdout = Console.OpenSta ndardOutput())
          {
          var bytes = Console.OutputE ncoding.GetByte s("Indirect Button
          was clicked" + Console.Out.New Line);
          stdout.Write(by tes, 0, bytes.Length);
          }
          };
          b3.Click += (sender, e) =PrintMsg();

          app.Run(win);
          clientPipe.Disp ose();
          serverPipe.Disp ose();
          }

          }
          }

          Comment

          • Ben Voigt [C++ MVP]

            #6
            Re: dllimport stdout gets eaten

            Arne Vajhøj wrote:
            Ben Voigt [C++ MVP] wrote:
            >Arne Vajhøj wrote:
            >>not_a_commi e wrote:
            >>>I changed the stdout in my C# app using Console.SetOut. It works
            >>>fine for all my Console.Out.Wri te calls and with log4net. However,
            >>>I don't see any output from native dlls that write to stdout. What
            >>>am I doing wrong?
            >>Nothing.
            >>>
            >>Why should changing something inside the Console class
            >>change what some native code does ?
            >>
            >If for example, that managed code was a wrapper around SetStdHandle.
            >But it's not, it changes Console.Out rather than changing stdout
            >underneath.
            >
            I can not see how it could be a wrapper around SetStdHandle. Out is a
            TextWriter. If I write my own class that extends TextWriter and call
            SetOut with it. There are no handle to pass to native and no way
            for the native code to call my class.
            I agree. I was just trying to show that it wasn't an entirely unreasonable
            expectation though, by mentioning a function that would behave as the OP
            expected. And, as you point out, it is limited to redirecting to an OS
            handle, not an arbitrary TextWriter.
            >
            >>You need to do something in your native code to
            >>get output where you want it.
            >>
            >SetStdHandle , most likely. And then it doesn't have to be a change
            >to the native code, as long as it's called from the same process.
            >
            I was thinking freopen, but if it is documented that SetStdHandle
            interacts "nicely" with the C RTL, then that can obviously be
            used.
            I didn't see any assurance that the native code was written in C, or that
            the OP knew which RTL was being used. If the DLL was statically linked, it
            would be next-thing-to-impossible to call the "right" freopen.
            >
            Arne

            Comment

            • =?ISO-8859-1?Q?Arne_Vajh=F8j?=

              #7
              Re: dllimport stdout gets eaten

              Ben Voigt [C++ MVP] wrote:
              Arne Vajhøj wrote:
              >Ben Voigt [C++ MVP] wrote:
              >>Arne Vajhøj wrote:
              >>>You need to do something in your native code to
              >>>get output where you want it.
              >>SetStdHandl e, most likely. And then it doesn't have to be a change
              >>to the native code, as long as it's called from the same process.
              >I was thinking freopen, but if it is documented that SetStdHandle
              >interacts "nicely" with the C RTL, then that can obviously be
              >used.
              >
              I didn't see any assurance that the native code was written in C, or that
              the OP knew which RTL was being used. If the DLL was statically linked, it
              would be next-thing-to-impossible to call the "right" freopen.
              Good point.

              Arne

              Comment

              Working...