8

I am using a third party library that uses the function OutputDebugString(), and when reading the MSDN documentation it seems to indicate that this is for printing to the debugger.

But that is inconvenient in my case, is there a way to read this output if there is no debugger connected?

If it was my LIB, I would prefer the output to go to stdout/stderr whenever the user passes --debug or similar, but since it's not I am looking for other ways to pass this info to the console (or file) without connecting a debugger.

Ajay
  • 18,086
  • 12
  • 59
  • 105
Zitrax
  • 19,036
  • 20
  • 88
  • 110
  • 2
    try dbgview, it will capture the output string, with many other features – Tiger Hwang Jan 04 '17 at 14:24
  • 1
    if you want do this "* read this output *" programmatically - this is possible - you need set `VEX` handler and spy for `DBG_PRINTEXCEPTION_[WIDE_]C` - if you want I can paste code for redirect `OutputDebugString` to console - this is small and simply – RbMm Jan 04 '17 at 14:55
  • @RbMm sure - that could be useful. – Zitrax Jan 05 '17 at 08:26
  • Try [DebugView++](https://github.com/CobaltFusion/DebugViewPP/releases). Much faster than DebugView, and has some pretty useful formatting and filtering options. – rossmcm Dec 09 '18 at 21:56

1 Answers1

9

the OutputDebugStringA generate exception DBG_PRINTEXCEPTION_C (W version in win10 - DBG_PRINTEXCEPTION_WIDE_C) with 2 arguments - (string length in characters + 1, string pointer) - as result we can handle this exception yourself (system default handler for this exception do this).

example handler for redirect OutputDebugString to console:

LONG NTAPI VexHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
    PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord;

    switch (ExceptionRecord->ExceptionCode)
    {
    case DBG_PRINTEXCEPTION_WIDE_C:
    case DBG_PRINTEXCEPTION_C:

        if (ExceptionRecord->NumberParameters >= 2)
        {
            ULONG len = (ULONG)ExceptionRecord->ExceptionInformation[0];

            union {
                ULONG_PTR up;
                PCWSTR pwz;
                PCSTR psz;
            };

            up = ExceptionRecord->ExceptionInformation[1];

            HANDLE hOut = GetStdHandle(STD_ERROR_HANDLE);

            if (ExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C)
            {
                // localized text will be incorrect displayed, if used not CP_OEMCP encoding 
                // WriteConsoleA(hOut, psz, len, &len, 0);

                // assume CP_ACP encoding
                if (ULONG n = MultiByteToWideChar(CP_ACP, 0, psz, len, 0, 0))
                {
                    PWSTR wz = (PWSTR)alloca(n * sizeof(WCHAR));

                    if (len = MultiByteToWideChar(CP_ACP, 0, psz, len, wz, n))
                    {
                        pwz = wz;
                    }
                }
            }

            if (len)
            {
                WriteConsoleW(hOut, pwz, len - 1, &len, 0);
            }

        }
        return EXCEPTION_CONTINUE_EXECUTION;
    }

    return EXCEPTION_CONTINUE_SEARCH;
}

and for set this handler need call:

AddVectoredExceptionHandler(TRUE, VexHandler);

the system implementation of OutputDebugString like here - it really called RaiseException with exactly this arguments, only in exception handler instead MessageBox - code described here.

RbMm
  • 31,280
  • 3
  • 35
  • 56
  • your solution doesn't work. `OutputDebugString` does not generate exception you mention. – Sonny D Dec 04 '20 at 23:18
  • 1
    YOU ARE RIGHT, I WAS WRONG. INDEED `DBG_PRINTEXCEPTION_WIDE_C` IS GENERATED. I tested it again, I made mistake. Sorry. I will not delete previous comment to not confuse others. – Sonny D Dec 05 '20 at 09:34
  • 1
    @SonnyD - i almost sure that you test under debugger. exception of course generated and in this case, but debugger handle this exception and as result you not view it in code. exception handler not called – RbMm Dec 05 '20 at 19:14