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:
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: