Share via

OutputDebugStringA not working at all

Andrew Mercer 546 Reputation points
2026-03-14T14:00:59.79+00:00

Neither OutputDebugStringA nor OutputDebugStringB (ODS) are working in my environment, Windows 11, dell intel machine, Visual Studio Community 2022 64-bit. The symptom is that the call is made and returns without error, but the output does not show up in the debug pane of the output window. My objective is to insert ODS calls in a C dll (release config) P/Invoked from a VB forms program (debug or release config), and if running in the VS debugger, I want to see the output. If not in the debugger, I don't care what happens, but best is to noop the call. I don't mind checking this - the C dll can tell if a debugger is attached or not.

After a lot of trial and error with the C dll, I found that the VB program could not successfully use ODS either. A minimal test program exhibiting the problem is shown below. There are 5 Trace.Writeline lines and 4 different hacks at ODS. All that makes it to the output window are the Trace.Writeline calls. Same effect if I run VS as administrator, so I doubt it is a security issue.

So, what I want is to call a function from the dll (not C++, and no clr) that will do what Trace.Writeline actually does, or equivalently, does what OutputDebugStringA is documented to actually do.

Public Class Form1

  Private Declare Sub OutputDebugStringA Lib "kernel32" (ByRef OutputString As Byte)
  Private Declare Sub OutputDebugStringW Lib "kernel32" (ByRef OutputString As Char)

  Private Declare Sub OutputDebugStringS1 Lib "kernel32" Alias "OutputDebugStringW" (ByVal OutputString As String)

  <Runtime.InteropServices.DllImport("kernel32.dll", CharSet:=Runtime.InteropServices.CharSet.Unicode, EntryPoint:="OutputDebugStringW")>
  Private Shared Sub OutputDebugStringS2(ByVal OutputString As String)
  End Sub

  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    Dim s As String = "yyyy" & ChrW(0)
    Dim a() As Byte = System.Text.Encoding.ASCII.GetBytes(s) ' s as ascii bytes
    Dim w() As Char = s.ToCharArray ' s as unicode chars
    ' only Trace.Writeline shows up in the debug pane output window
    Trace.WriteLine("xxxx")
    OutputDebugStringA(a(0))
    Trace.WriteLine("xxxx")
    OutputDebugStringW(w(0))
    Trace.WriteLine("xxxx")
    OutputDebugStringS1(s) ' message CA2101, P/Invoke marshaling
    Trace.WriteLine("xxxx")
    OutputDebugStringS2(s)
    Trace.WriteLine("xxxx")
  End Sub

End Class

Windows development | Windows API - Win32
0 comments No comments
{count} votes

Answer accepted by question author
  1. Viorel 126.8K Reputation points
    2026-03-14T19:21:49.4433333+00:00

    In order to view the output of OutputDebugStringA, try to select the “Enable native code debugging” option in Project Properties (Debug tab). It is available for both .NET and .NET Framework. This seems to work:

    <DllImport("kernel32", CharSet:=CharSet.Ansi, EntryPoint:="OutputDebugStringA")>
    Private Shared Sub OutputDebugStringA(ByVal OutputString As String)
    End Sub
    
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
       OutputDebugStringA("My Test 1" & vbCrLf)
    
       Debug.WriteLine("My Test 2") ' works too
    
    End Sub
    

    Should work in case of C DLL too.

    If the program is launched without debugging, then the output of OutputDebugStringA can be viewed using the Debug View tool (dbgview64.exe) from Sysinternals Suite, even in case of Release configuration.

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Q&A Assist
    2026-03-14T14:01:18.5366667+00:00
    AI generated content. This question contains an answer created with AI from Q&A Assist. Learn more

    OutputDebugString is working as designed, but Visual Studio is not the only consumer of that API, and the way it is called from VB in the sample is incorrect.

    Key points from the platform behavior:

    • OutputDebugStringA/W send a string to the debugger of the calling process. If no debugger is attached and no system debugger is active, the call is effectively a no-op.
    • In user mode, OutputDebugString simply sends a null-terminated string to the debugger; it does not format or buffer like printf.
    • If there is no debugger, and the system debugger is not active, OutputDebugString does nothing.

    Relevant details:

    • The official prototype is:
        VOID OutputDebugString(
           LPCTSTR lpOutputString
        );
      
      which is a pointer to a null-terminated string.
    • In VB, the P/Invoke must pass a pointer to a null-terminated string, not a single Byte or Char by reference.

    In the VB sample:

    Private Declare Sub OutputDebugStringA Lib "kernel32" (ByRef OutputString As Byte)
    Private Declare Sub OutputDebugStringW Lib "kernel32" (ByRef OutputString As Char)
    

    These signatures pass a single element (a(0) or w(0)) by reference, which does not match the expected LPSTR/LPWSTR pointer to a null-terminated string. The marshaler is not providing a proper C-style string pointer, so the native function does not receive valid text to send to the debugger.

    The correct approach in VB is to declare the function with a String parameter and let the runtime marshal it as a null-terminated ANSI or Unicode string, for example:

    <DllImport("kernel32.dll", CharSet:=CharSet.Ansi, EntryPoint:="OutputDebugStringA", _
               SetLastError:=False)>
    Private Shared Sub OutputDebugStringA(ByVal lpOutputString As String)
    End Sub
    
    <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, EntryPoint:="OutputDebugStringW", _
               SetLastError:=False)>
    Private Shared Sub OutputDebugStringW(ByVal lpOutputString As String)
    End Sub
    

    Then call:

    OutputDebugStringA("Test from ANSI")
    OutputDebugStringW("Test from Unicode")
    

    With a debugger attached to the VB process, these strings are sent as an OUTPUT_DEBUG_STRING_EVENT to the debugger and should appear in the debugger’s output view (subject to how the specific Visual Studio version chooses to display them).

    For the C DLL scenario:

    • In the DLL, call OutputDebugStringA/OutputDebugStringW directly with a valid null-terminated string.
    • If the DLL should only emit output when a debugger is attached, call IsDebuggerPresent first and skip the call when it returns false.

    If Visual Studio is not attached, but debug output still needs to be captured, a tool such as DebugView can be used. DebugView captures:

    • Win32 OutputDebugString
    • Kernel-mode DbgPrint and its variants

    This allows viewing debug output without a debugger attached.


    References:


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.