PInvoke SetStdHandle для использования с неуправляемой особенностью DLL на основе конфигурации сборки (VisualStudio) - PullRequest
2 голосов
/ 26 января 2012

Я испытываю странное поведение при попытке PInvoke SetStdHandle () перенаправить stdout / stderr из неуправляемой DLL. А именно, с данной DLL она работает ТОЛЬКО при сборках Debug (не Release).

Соответствующий код выглядит так:

    [System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true)]
    public static extern int SetStdHandle(int device, IntPtr handle);

    const int STD_OUTPUT_HANDLE = -11;
    const int STD_ERROR_HANDLE = -12;

    static System.IO.FileStream outFileStream;
    static System.IO.FileStream errFileStream;
    public static void TestStdRedirect()
    {
        outFileStream = System.IO.File.Open("C:\\stdout.txt", System.IO.FileMode.Create);
        if (0 == SetStdHandle(-11, outFileStream.SafeFileHandle.DangerousGetHandle()))
            System.Windows.Forms.MessageBox.Show("HANDLE REASSIGNMENT FAILED!");
        errFileStream = System.IO.File.Open("C:\\stderr.txt", System.IO.FileMode.Create);
        if (0 == SetStdHandle(-12, errFileStream.SafeFileHandle.DangerousGetHandle()))
            System.Windows.Forms.MessageBox.Show("HANDLE REASSIGNMENT FAILED!");
    }

    public static void EndTestStdRedirect()
    {
        Console.OpenStandardOutput().Flush();
        Console.OpenStandardError().Flush();
        outFileStream.Flush();
        outFileStream.Close();
        errFileStream.Flush();
        errFileStream.Close();
    }

Теперь, когда я делаю следующее, всегда работает (независимо от выпуска или отладочной сборки) - операторы печати перенаправляются в c: \ stdout.txt и c: \ stderr.txt, как и ожидалось.

        TestStdRedirect();
        byte[] buf = Console.OutputEncoding.GetBytes(DateTime.Now.ToString() + ") Start Test StdOut" + Console.Out.NewLine);
        Console.OpenStandardOutput().Write(buf, 0, buf.Length);
        buf = Console.OutputEncoding.GetBytes(DateTime.Now.ToString() + ") Start Test StdErr" + Console.Out.NewLine);
        Console.OpenStandardError().Write(buf, 0, buf.Length);
        EndTestStdRedirect();

Однако делаем следующее:

    [System.Runtime.InteropServices.DllImport("SomeDLL.dll")]
    static extern void FxnFromUnmanagedDLL();

    TestStdRedirect();
    FxnFromUnmanagedDLL();
    EndTestStdRedirect();

где FxnFromUnmanagedDLL выводит в stdout / stderr через fprintf, вывод перенаправляется в файл только , когда проект создается как «Отладка». Если он построен как Release, вывод идет прямо на панель вывода Visual Studio.

... Другими словами, это:

    TestStdRedirect();
    FxnFromUnmanagedDLL();
    byte[] buf = Console.OutputEncoding.GetBytes("blah" + Console.Out.NewLine);
    Console.OpenStandardOutput().Write(buf, 0, buf.Length);
    EndTestStdRedirect();

перенаправляет «бла» в файл, но вывод неуправляемой DLL направляется на консоль. Я гуглил и гуглил и не могу понять, что происходит; Моей первой мыслью было, что DLL делает что-то напуганное, например, открывание или переназначение потоков, но я ничего не могу найти по этому поводу (у меня есть доступ к исходному коду неуправляемой библиотеки DLL).

Заранее спасибо за ваши идеи ...

...