Jump to content
Tuts 4 You

How to handle console window in GUI?


LCF-AT

Recommended Posts

Hi guys,

today I would like to ask something about CMD / console windows so I have again a little problem and need some help.

Problem: I am trying to create a new GUI app and using a library from a commandline app.So everything ok so far so I can normaly use the functions of that library for my GUI app.Only problem I have now is that the original commandline app does also LOG informations into the console window and I just use a GUI without console window yet.I also see that the library still does LOG everything but I dont have a console window to see that infos into etc you know.

My question is how to start a simple console window and what to use to see that LOG infos inside?

In the library I can see at the LOG API that it used fprintf API with a streamhandle like that..

/CALL to fprintf
|stream = msvcrt.75E62940
|format = "%s: %s"
|<%s> = "DEBUG"
\<%s> = "Parsing..."

So what can I do now?Starting a new console window anyhow (by button press in GUI) and then I should get / have a handle of console window and should I then just change the used stream handle with my started console window handle to get then the LOG infos to see inside?I am not really sure about that so maybe you have some ideas how it could work etc.Or are there better / easier ways like starting a console window + giving then the handle above etc?As I said the library does LOG already everything and I just need to start a console + xy to see that logs then in that console anyhow.

Thank you

Link to comment

Hi,

ok but how to get now the LOG datas inside the window now by the called APIs like fputs /  fprintf?So somehow I have to set the window to get the Log datas inside.Any idea?

greetz

Link to comment

Hi again,

I found something like that...

#include<stdio.h>
#include<windows.h>
#include<fcntl.h>
#include<io.h>
 
int __stdcall WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
    AllocConsole();
    *stdout = *_fdopen(_open_osfhandle((long) GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT), "w");
 
    printf("aaa");
 
    FreeConsole();
    return 0;
}

I tried this in my code....

	invoke AllocConsole
	invoke GetStdHandle,STD_OUTPUT_HANDLE
	mov edi,eax
	invoke crt__open_osfhandle,edi,4000h ;_O_TEXT
	invoke crt__fdopen,eax,chr$("w")
	printf("aaa");
	invoke FreeConsole

....but I get nothing into the window.

Only thing I could do is hooking the output APIs like fputs / fprintf etc to catch the logged datas and to send them via WriteConsole into my allocconsole window but thats just a stupid idea.So somehow it should work else but how is the question. :(

PS: Main goal is it to start a CMD window and to get the APIs like fputs / fprintf working with that CMD window = text should shown then in that CMD window I did started.

greetz

Link to comment

Hi,

so for the moment I tried to hook fprintf API to my code where I do make a wsprintfA call and send then the datas via WriteConsole into CMD window.Seems to work so far but the problem is if I close the CMD window via mouse then it also close my GUI app too!?Why this now?So the CMD window should get closed by user itself without using freeconsole in that case.Has anyone some more hints for me?

greetz

Link to comment

There is also 'AttachConsole' API you can use by passing it the current process id of itself. The other std handles you can use to change the output to the console are:

freopen("CONIN$", "r", stdin); 
freopen("CONOUT$", "w", stdout); 
freopen("CONOUT$", "w", stderr); 

 

  • Like 1
Link to comment
VirtualPuppet
1 hour ago, LCF-AT said:

Hi,

so for the moment I tried to hook fprintf API to my code where I do make a wsprintfA call and send then the datas via WriteConsole into CMD window.Seems to work so far but the problem is if I close the CMD window via mouse then it also close my GUI app too!?Why this now?So the CMD window should get closed by user itself without using freeconsole in that case.Has anyone some more hints for me?

greetz

You want to use the following for Windows (example taken from one of my old HackShield bypasses):

AllocConsole();
SetConsoleTitle("HackShield Bypass");
AttachConsole(GetCurrentProcessId());

FILE* file = nullptr;
freopen_s(&file, "CON", "r", stdin);
freopen_s(&file, "CON", "w", stdout);
freopen_s(&file, "CON", "w", stderr);

 

Now all io-functionality will be printed/parsed through CON (file descriptor for console), instead of stdin, stdout and stderr. However, when doing this (AllocConsole in general), you're binding the console to the lifetime of the current process, and manually closing the console will also terminate the process. I haven't looked for a way to circumvent this, as I haven't had the need to, but I don't think Windows intended for such functionality.

  • Like 1
Link to comment

Hi again,

AttachConsole dosent work with process ID and get ERROR_ACCESS_DENIED.

As I said,I dont want that my main app does terminate if I close the console window via mouse.Is there not a way to let call just freeconsole API if I press close in the console app?

Ok,so if it dosent work using console window as I want then I need to show any own window the user can see & close without closing the main app.The problem in that case is I dont what I should use for that (similar control as console).Only control I could use is a listbox where I can send data into which also keeps inside.For edit control I can not add new lines into etc you know what I mean.So what for a control could I use then?

greetz

Link to comment
VirtualPuppet
8 minutes ago, LCF-AT said:

Hi again,

AttachConsole dosent work with process ID and get ERROR_ACCESS_DENIED.

As I said,I dont want that my main app does terminate if I close the console window via mouse.Is there not a way to let call just freeconsole API if I press close in the console app?

Ok,so if it dosent work using console window as I want then I need to show any own window the user can see & close without closing the main app.The problem in that case is I dont what I should use for that (similar control as console).Only control I could use is a listbox where I can send data into which also keeps inside.For edit control I can not add new lines into etc you know what I mean.So what for a control could I use then?

greetz

You should use a listbox or listview depending on the data you output. If it has specific format, you would use a listview with columns, if it's just formatted strings, you should use a listbox (with custom-draw/owner-draw if you want it to look like a console).

  • Like 1
Link to comment

Hi,

so the data output is already done by the library I do use for console window and I just need to output same data to any control what should look same as in console.The datas to output also using CLRF I cant just use with a listview.For listbox I dont know it yet whether I could send such datas directly into it.So I also just wanna send same datas to any control to let show it without to reformat the datas etc.Also I dont wanna have that single selection of a LB and the scrolling of LBs is also bad (dont wanna disable Win option).

Do you have any example code / file to check that out?

greetz

Link to comment
VirtualPuppet
20 minutes ago, LCF-AT said:

Hi,

so the data output is already done by the library I do use for console window and I just need to output same data to any control what should look same as in console.The datas to output also using CLRF I cant just use with a listview.For listbox I dont know it yet whether I could send such datas directly into it.So I also just wanna send same datas to any control to let show it without to reformat the datas etc.Also I dont wanna have that single selection of a LB and the scrolling of LBs is also bad (dont wanna disable Win option).

Do you have any example code / file to check that out?

greetz

Well, it wouldn't be very nice to immitate that on a Listbox, as it is also row-divided like a listview (has independent rows). If you want to use CLRF like a Console, you'd need to either use a modified RICH EDIT control, with some kind of "append"-function or something that emulates the input/output functions. You could probably even force the input/output of printf, etc. to some custom hook that adds the data to an edit-control. You can look at this page for inspiration or help:

https://www.codeproject.com/Articles/335909/Embedding-a-Console-in-a-C-Application

 

Alternatively, you can disable the close-button for the console alltogether:

HWND hWndConsole = GetConsoleWindow();

if (hWndConsole != NULL)
{
    HMENU hMenu = GetSystemMenu(hWndConsole, FALSE);

    if (hMenu != NULL) 
		DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
}

 

  • Like 1
Link to comment

Hi again,

so I found that DeleteMenu also now on internet and tried it.So exit button is disabled now in console window.Seems to be good so far.Now I have created 2 test buttons in a test GUI.One does create the console with disabled close button and one button does free console = working.Now I checked that issue using Handler routine for the CTRL commands and the handler routine works too to get the commands and I can also catch CTRL_CLOSE_EVENT if I press close on console window but here I cant disable closing process.Also it happens automatically after few seconds.My question now is whether I could also stop the close event anyhow if I catch it in my handler routine?If yes then I dont need to disable the close function in console window and the user could also close the console without closing my GUI too.

	.elseif uMsg == WM_COMMAND
		.if	wParam == IDB_EXIT
			invoke	SendMessage, hWnd, WM_CLOSE, 0, 0
			;..................
		
		.elseif wParam == 1030
		    
		    
	invoke AllocConsole
	invoke GetStdHandle,STD_OUTPUT_HANDLE
	mov edi,eax
	invoke GetConsoleWindow	
	mov esi,eax
	invoke GetSystemMenu,esi,FALSE
	mov ebx,eax
	invoke DeleteMenu,ebx,SC_CLOSE,MF_BYCOMMAND	
	invoke WriteConsole, edi, chr$("TEST ETS"), 8, addr FREE2, NULL	    
	invoke SetConsoleCtrlHandler, ADDR HandlerRoutine, TRUE	    
		    
		 .elseif wParam == 1031   
		    invoke FreeConsole

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
HandlerRoutine proc dwCtrlType:DWORD

    .IF dwCtrlType == CTRL_CLOSE_EVENT
        invoke MessageBox,0,chr$("CTRL_CLOSE_EVENT!"),chr$("Problem!"),MB_ICONWARNING
        invoke FreeConsole
        mov eax,TRUE
        ret    
    .elseif dwCtrlType == CTRL_C_EVENT
        invoke MessageBox,0,chr$("CTRL_C_EVENT!"),chr$("Problem!"),MB_ICONWARNING
        invoke FreeConsole
        mov eax,TRUE
        ret
    .elseif dwCtrlType == CTRL_BREAK_EVENT
        invoke MessageBox,0,chr$("CTRL_BREAK_EVENT!"),chr$("Problem!"),MB_ICONWARNING
    .elseif dwCtrlType == CTRL_LOGOFF_EVENT
        invoke MessageBox,0,chr$("CTRL_LOGOFF_EVENT!"),chr$("Problem!"),MB_ICONWARNING
    .elseif dwCtrlType == CTRL_SHUTDOWN_EVENT
        invoke MessageBox,0,chr$("CTRL_SHUTDOWN_EVENT!"),chr$("Problem!"),MB_ICONWARNING
    .endif
    xor eax,eax
	Ret
HandlerRoutine endp

So on the other hand the user can press Strg+C to close console and GUI keeps running.

AddOn question: Can I also set a new entry or context menu in that console window where I could choose "close window" ?Then I could do a freeconsole call after user did choose it etc you know.

greetz

Link to comment
VirtualPuppet
18 minutes ago, LCF-AT said:

< long quote >

Sadly, there's no actual way of intercepting or intervening with the closing-process. According to some information by Microsoft, that I googled my way to, the data used internally by the Console is already freed and deallocated before the event routine is being called, so the window is already partially destroyed when you are notified of the event, and as such there's no way to stop it half-way through (as it would be dangerous to keep the window while much of the data has been deallocated).

If you want to intercept the contextmenu, you're gonna have to do API hooks, cause the console window runs in a sub-system to your current process.

  • Like 1
Link to comment

Ah ok thanks for the infos so far.So I think at the moment I can live with that solution to disable close in console and using Strg+c & or extra button in GUI itself to free console.So I did some tests with that in my main project and it seems to work all good so far. :) Just bad that I need to hook the msvcrt APIs which do send datas to output to output them via WriteConsole.Anyway,so long the detour does work its also ok.

One more question: So I see if I create a console window then my mouse scroller wheel isnt working in that console window.On internet I found that...

Try SetConsoleMode and disable ENABLE_MOUSE_INPUT and use ENABLE_PROCESSED_INPUT.

something like

GetConsoleMode(hConsoleHandle, &lpMode);
SetConsoleMode(hConsoleHandle, lpMode & ~ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);

...but isnt working anyhow.So I use AllocConsole / GetStdHandle STD_OUTPUT_HANDLE.Have I to use that handle I get from GetStdHandle?I tried and I get 3 back (ENABLE_PROCESSED_INPUT & ENABLE_LINE_INPUT) but if I use SetConsoleMode for that handle then it fails.

	invoke AllocConsole
	invoke GetStdHandle,STD_OUTPUT_HANDLE
	mov edi,eax
	invoke GetConsoleMode,edi,addr FREE2
	invoke SetConsoleMode,edi,ENABLE_MOUSE_INPUT or ENABLE_PROCESSED_INPUT

Some invalid Paramter I get in lasterror register and eax 0.So whats wrong here?Just dont wanna change anything etc just enabling the mouse wheel to scroll up / down in console you know.

Thanks again

Link to comment
VirtualPuppet
16 minutes ago, LCF-AT said:

Ah ok thanks for the infos so far.So I think at the moment I can live with that solution to disable close in console and using Strg+c & or extra button in GUI itself to free console.So I did some tests with that in my main project and it seems to work all good so far. :) Just bad that I need to hook the msvcrt APIs which do send datas to output to output them via WriteConsole.Anyway,so long the detour does work its also ok.

One more question: So I see if I create a console window then my mouse scroller wheel isnt working in that console window.On internet I found that...


Try SetConsoleMode and disable ENABLE_MOUSE_INPUT and use ENABLE_PROCESSED_INPUT.

something like

GetConsoleMode(hConsoleHandle, &lpMode);
SetConsoleMode(hConsoleHandle, lpMode & ~ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);

...but isnt working anyhow.So I use AllocConsole / GetStdHandle STD_OUTPUT_HANDLE.Have I to use that handle I get from GetStdHandle?I tried and I get 3 back (ENABLE_PROCESSED_INPUT & ENABLE_LINE_INPUT) but if I use SetConsoleMode for that handle then it fails.


	invoke AllocConsole
	invoke GetStdHandle,STD_OUTPUT_HANDLE
	mov edi,eax
	invoke GetConsoleMode,edi,addr FREE2
	invoke SetConsoleMode,edi,ENABLE_MOUSE_INPUT or ENABLE_PROCESSED_INPUT

Some invalid Paramter I get in lasterror register and eax 0.So whats wrong here?Just dont wanna change anything etc just enabling the mouse wheel to scroll up / down in console you know.

Thanks again

I've never tried altering the input-types for Console windows, so I can't help you there :P

Link to comment

Hi,

anyway,so I checked CMD file what it does set for STD_INPUT_HANDLE.Just need these (ENABLE_PROCESSED_INPUT or ENABLE_LINE_INPUT or ENABLE_ECHO_INPUT) to get scrolling working. :) Now it works.

greetz

  • Thanks 1
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...