Debugging Npp .exe without a debugger (beginner)
-
I’m using appveyor.com to build debug versions of notepad++, as I’m trying to understand one small part of it (who’s curious can look at https://github.com/victorel-petrovich/notepad-plus-plus_lastRecentFileList.cpp ) .
I researched today how to print to a console from a windows .exe, with
printf
orcout
statements inserted in source code, and I want to share what I found,
and maybe also I’ll find out better ways from you (while using appveyor building).So, I put the following in some initialization section (in my case - it works in lastRecentFileList.cpp,
initMenu()
):AllocConsole(); freopen("conin$","r",stdin); freopen("conout$","w",stdout); freopen("conout$","w",stderr); printf("Debugging Window\n"); printf("----------------\n");
And then insert
printf
orstd::cout
(the latter with#include <iostream>
at top of file) where I need.Another more primitive way is to insert
system("pause")
(no prerequisites needed) to get a popup window waiting for a keypress. Works as yes/no test.But maybe it’s possible better way, of specifying somewhere say in “appveyor.yml” that printing to a regular/parent console is allowed for a “debug” version…
References (after a long search):
https://stackoverflow.com/questions/2501968/visual-c-enable-console
https://stackoverflow.com/a/19406695/1558980
https://stackoverflow.com/questions/40140248/output-to-windows-cmd-prompt!
-
But maybe it’s possible better way, of specifying somewhere say in “appveyor.yml” that printing to a regular/parent console is allowed for a “debug” version…
You can achieve what you’re asking with conditional compilation.
TL;DR
#ifdef _DEBUG // . . . print to console . . . #endif
This guards a block of code at build time by checking for a preprocessor definition that should only be set in the debug configuration.
Now, as much as I admire the inventiveness of your ad hoc approach, I seriously doubt how useful it’s going to be. The extra code you’re inserting into the N++ binary may end up introducing bugs instead of detecting the ones already there.
If your adverse/unable to get Visual Studio up and running, the N++ source code is still compatible with the MinGW toolchain, which comes with a Makefile processor and the GNU Debugger utility. (At the time of writing, Windows Vista is the oldest OS that can run
notepad++.exe
images built with MinGW).Once you have the tools installed and can build N++ all by yourself, attaching the debugger should be as easy as entering:
> gdb r C:\<path>\<to>\notepad++.exe
. There’s an extensive suite of command line options for stepping through code, inspecting variables, etc. -
@rdipardo I only build debug versions to test, so I don’t need to differentiate between release vs debugs.
Instead, I was curious about was whether it was possible to make the
printf
results appear in the console cmd.exe from where I run the Npp .exe. I thought since this is debug version, maybe some compilation settings are possible to allow that. But that’s just a curiosity; above setup seems to work well.The extra code you’re inserting into the N++ binary may end up introducing bugs instead of detecting the ones already there.
I think it’s obvious / common sense that one doesn’t leave any “extra” (unnecessary) code in a PR.
I seriously doubt how useful it’s going to be
Very useful; I already tested some of my assumptions.
-
OutputDebugString() is where I’d go with it, rather than going to the trouble of getting a console. But, it’s similar, and apparently what you have going now works, so…
-
@Alan-Kilborn Thank you for answering to the point .
Everywhere I read (including 2 ref-s above , and at microsoft) they say OutputDebugString() is for when the app is run from / has a debugger .
But, it’s similar, and apparently what you have going now works, so…
Indeed.
-
@Victorel-Petrovich said in Debugging Npp .exe without a debugger (beginner):
Everywhere I read (including 2 ref-s above , and at microsoft) they say OutputDebugString() is for when the app is run from / has a debugger .
… but it is not limited to be used only by debuggers. Applications like debugview from sysinternals tools can be used to get this output.
or a pythons script like
import ctypes from ctypes.wintypes import HANDLE, DWORD, BOOL, LPVOID, LPCWSTR, LPHANDLE import mmap import struct import os from Npp import console console.show() kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) CreateEventW = kernel32.CreateEventW CreateEventW.argtypes = [LPVOID, BOOL, BOOL, LPCWSTR] CreateEventW.restype = HANDLE SetEvent = kernel32.SetEvent SetEvent.argtypes = [HANDLE] SetEvent.restype = BOOL WaitForSingleObject = kernel32.WaitForSingleObject WaitForSingleObject.argtypes = [HANDLE, DWORD] WaitForSingleObject.restype = DWORD WaitForMultipleObjects = kernel32.WaitForMultipleObjects WaitForMultipleObjects.argtypes = [DWORD, LPHANDLE, BOOL, DWORD] WaitForMultipleObjects.restype = DWORD CloseHandle = kernel32.CloseHandle CloseHandle.argtypes = [HANDLE] CloseHandle.restype = BOOL BUFFER_READY = kernel32.CreateEventW(None, 0, 0, 'DBWIN_BUFFER_READY') DATA_READY = kernel32.CreateEventW(None, 0, 0, 'DBWIN_DATA_READY') STOP_DBG_LOOP = kernel32.CreateEventW(None, 0, 0, 'STOP_DBG_LOOP') HANDLES = (HANDLE * 2)(DATA_READY, STOP_DBG_LOOP) buffer = mmap.mmap(0, 4096, "DBWIN_BUFFER", mmap.ACCESS_WRITE) CURRENT_NPP_ID = os.getpid() # Call SetEvent(STOP_DBG_LOOP) to stop the loop, # either with a second script or by calling from the PS console while True: SetEvent(BUFFER_READY) result = WaitForMultipleObjects(2, HANDLES, False, 0xFFFFFFFF) if result == 1: # STOP_DBG_LOOP received break elif result == 0: buffer.seek(0) process_id, = struct.unpack("L", buffer.read(4)) data = buffer.read(4092) if CURRENT_NPP_ID != process_id: # to prevent seeing PS's own debug strings. if b"\0" in data: data = data[:data.index(b"\0")] print("Process:[{0}] {1}".format(process_id, data.decode().strip())) else: print('ooppss: {}'.format(result)) break CloseHandle(BUFFER_READY) CloseHandle(DATA_READY) CloseHandle(STOP_DBG_LOOP) print('done')
-
@Ekopalypse you’re a wizard
-
I’ve just downloaded DebugView from sysinternals (easy to use), and read in several pages about
OutputDebugString()
.
So, yes, it’s good if you don’t want to create a console in the app withAllocConsole()
like above.
But then you usually need to prepare the formatted string in advance usingsprintf()
or similar, then pass to OutputDebugString… (Or write a special function to do it… again extra inserted code or files).
Soprintf()
is easier to use (at least for most practical cases, IMO), and already familiar. -
@Victorel-Petrovich said in Debugging Npp .exe without a debugger (beginner):
So printf() is easier to use (at least for most practical cases, IMO), and already familiar.
Really, only because you already have the “console” approach in your rearview mirror.
If someone didn’t have that, OutputDebugString is easier.
It’s just a matter of (in very simple terms):
char buf[1024];
sprintf(buf, “test”);
OutputDebugString(buf); -
@Alan-Kilborn said in Debugging Npp .exe without a debugger (beginner):
It’s just a matter of (in very simple terms):
char buf[1024];
sprintf(buf, “test”);
OutputDebugString(buf);But when you have several tens of outputs to write in every function you test… :/
-
@Victorel-Petrovich said in Debugging Npp .exe without a debugger (beginner):
But when you have several tens of outputs to write in every function you test
Hmm, no idea why that’s a problem…
I think if this is how you’re considering debugging Notepad++ changes you might make…it is going to wear you down fast and you’ll give up trying to make changes.
-
@Alan-Kilborn With column-mode editing, and duplication of lines etc, it’s not that bad.
Much harder is to understand why I don’t get the results I expect, doing lots of googling , and try again and again. -
Another option, pointed out to me by @Yaron10 on github:
printInt(int int2print)
andprintStr(const TCHAR *str2print)
Will output in a message box…
Comparable with OutputDebugString in the need to prepare the (complex) string beforehand, but doesn’t require a debugger or allocating a console.
https://github.com/notepad-plus-plus/notepad-plus-plus/blob/master/PowerEditor/src/MISC/Common/Common.cpp#L32
(The definitions also hint at how to properly pass the string). -
-
Topic moved to the newly renamed and refocused “Notepad++ & Plugin Development” category, where it naturally fits (I assumed @Victorel-Petrovich wouldn’t mind it being moved, since he was the one who wanted a specific place to ask such questions).
Personally, when I am doing a lot of print-based debugging, I write wrapper functions or #define macros that encapsulate all the formatting into the string, and then call the proper output function with that string, so that I can just have a single line of code for each inline debug print, and I let the complications of definining a dummy buffer variable and the sprintf formatting elsewhere.
But really, none of these questions are specific to debugging Notepad++, and is really a generic C/C++ “best way to debug without a debugger, without a console, or similar restriction” question.
-
@PeterJones said in Debugging Npp .exe without a debugger (beginner):
I assumed @Victorel-Petrovich wouldn’t mind it being moved
True