LCF-AT 2,465 Posted October 6, 2018 Share Posted October 6, 2018 Hi guys, I have again a small question about piping a CLI output to my buffer.So I just wanna start a CLI app with paramters and reading the output (content I also see in CMD window) so long till its finished.So the only problem I have so far is how to wait till its finished.Lets say the CLI app needs a while (a minute etc).My question is what function/s I need to use for that?I see I cant use WaitForSingleObject with INFINITE paramter so this dosent work because the CLI app dosent exit itself so long I didnt had reading the bytes.If I just read the bytes using PeekNamedPipe / ReadFile function then I dont get the whole content = it quits to early and the CLI app is still working. My goal is it to read the bytes on fly and checking whether the pipe / process is still working / activ or not. Below some example code: _CreatePipe PROC Local RetVal:DWORD invoke RtlZeroMemory,addr SecuAttr,sizeof SecuAttr invoke RtlZeroMemory,addr StartInfo,sizeof StartInfo invoke RtlZeroMemory,addr PI,sizeof PI mov RetVal,0 mov SecuAttr.nLength,sizeof SECURITY_ATTRIBUTES mov SecuAttr.bInheritHandle,TRUE invoke CreatePipe,addr hRead,addr hWrite,addr SecuAttr,NULL .if eax == FALSE invoke MessageBox,0,chr$("CreatePipe failed!"),chr$("Problem!"),MB_ICONWARNING mov eax,FALSE ret .endif invoke SetHandleInformation, hRead, HANDLE_FLAG_INHERIT, 0 .if eax == FALSE invoke CloseHandle,hRead invoke CloseHandle,hWrite invoke MessageBox,0,chr$("SetHandleInformation failed!"),chr$("Problem!"),MB_ICONWARNING mov eax,FALSE ret .endif mov RetVal,eax mov StartInfo.cb,sizeof StartInfo invoke GetStartupInfo,addr StartInfo xor eax,eax mov StartInfo.lpReserved,eax mov eax,hWrite mov StartInfo.hStdOutput,eax mov StartInfo.hStdError,eax mov StartInfo.dwFlags, STARTF_USESTDHANDLES mov StartInfo.wShowWindow,SW_SHOW mov eax,RetVal ret _CreatePipe endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .elseif ax == IDB_TEST invoke VirtualAlloc,0,50000h,MEM_COMMIT,PAGE_EXECUTE_READWRITE mov esi, eax push esi invoke _CreatePipe .if eax != FALSE lea edi, chr$("cmd.exe /c C:\tool.exe -t -r") invoke CreateProcess, NULL, edi, NULL,NULL,TRUE,CREATE_NO_WINDOW,NULL,NULL, addr StartInfo, addr PI .if eax != FALSE @@: invoke Sleep,300 invoke PeekNamedPipe,hRead,offset PIPEBUFFER,sizeof PIPEBUFFER,offset PIPEREADBYTES,addr AVAL,NULL .if eax != FALSE .if AVAL != 0h invoke ReadFile,hRead,esi,PIPEREADBYTES,addr BYTESREAD,0 .if eax != FALSE add esi, BYTESREAD jmp @B .else invoke MessageBox,0,chr$("ReadFile failed!"),chr$("Problem!"),MB_ICONWARNING jmp @F .endif .else pop esi push esi invoke MessageBox,0,esi,chr$("Info!"),MB_ICONINFORMATION .endif .else invoke MessageBox,0,chr$("PeekNamedPipe failed!"),chr$("Problem!"),MB_ICONWARNING .endif @@: invoke CloseHandle, [PI.hThread] invoke CloseHandle, [PI.hProcess] invoke CloseHandle, hRead invoke CloseHandle, hWrite .else invoke CloseHandle, hRead invoke CloseHandle, hWrite .endif .endif pop esi invoke VirtualFree,esi,0,MEM_RELEASE How to handle the wait operation correctly and to read all bytes / content so long the CLI app is activ / working?Maybe anyone could help a little to fix that problem. Thank you Link to post
evlncrn8 358 Posted October 6, 2018 Share Posted October 6, 2018 https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess that at least lets you check 100% if the process has exited, the rest is just polling, to check if there's input and so on also, mov StartInfo.hStdOutput,eax mov StartInfo.hStdError,eax was that intentional ? theres stdout, stdin, and stderr.. also you didnt set hread from what i saw but i didnt go through the code in detail 2 Link to post
atom0s 503 Posted October 7, 2018 Share Posted October 7, 2018 When you use CreateProcess the PROCESS_INFORMATION class gives back the main process handle and the main thread handle. You can use those to pull the exit codes of either. - GetExitCodeProcess and GetExitCodeThread Keep in mind if the application is multi-threaded, it is not guaranteed that the main thread handle will remain alive for the entire duration of the app. 1 Link to post
LCF-AT 2,465 Posted October 7, 2018 Author Share Posted October 7, 2018 Hi guys, thanks for your answers.Ok I am just checking whether the process is still active or not using GetExitCodeProcess function.Ok,so this seems to work so far and I can read while pipe content.Now I found another small problem.So if I start the CLI app and it does run for a longer while then I wanna also stop the process similar like using CRTL+C key press in CMD window.First I just tried to use TermniateProcess function with the hprocess ID of CLI app but this dosent work and CLI app keeps working in background / taskmanager and I need to wait till its finished by itself.Now I checked again the internet and found something about using GenerateConsoleCtrlEvent function to send CTRL_C_EVENT.I also found some example code like this... https://codetitans.pl/blog/post/sending-ctrl-c-signal-to-another-application-on-windows [DllImport("kernel32.dll", SetLastError = true)] static extern bool AttachConsole(uint dwProcessId); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] static extern bool FreeConsole(); [DllImport("kernel32.dll")] static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate handler, bool add); // Delegate type to be used as the Handler Routine for SCCH delegate Boolean ConsoleCtrlDelegate(CtrlTypes type); // Enumerated type for the control messages sent to the handler routine enum CtrlTypes : uint { CTRL_C_EVENT = 0, CTRL_BREAK_EVENT, CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT = 5, CTRL_SHUTDOWN_EVENT } [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId); public static void StopProgram(uint pid) { // It's impossible to be attached to 2 consoles at the same time, // so release the current one. FreeConsole(); // This does not require the console window to be visible. if (AttachConsole(pid)) { // Disable Ctrl-C handling for our program SetConsoleCtrlHandler(null, true); GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0); // Must wait here. If we don't and re-enable Ctrl-C // handling below too fast, we might terminate ourselves. Thread.Sleep(2000); FreeConsole(); // Re-enable Ctrl-C handling or any subsequently started // programs will inherit the disabled state. SetConsoleCtrlHandler(null, false); } } ...I tried this like this for testing... invoke CreateProcess, NULL,addr commandline,NULL,NULL,TRUE,CREATE_NO_WINDOW,NULL,NULL,addr StartInfo,addr PI .if eax != FALSE invoke Sleep,2000 invoke AttachConsole,PI.dwProcessId .if eax != FALSE invoke SetConsoleCtrlHandler,NULL,TRUE .if eax != FALSE invoke GenerateConsoleCtrlEvent,CTRL_C_EVENT,NULL .if eax != FALSE invoke Sleep,2000 invoke FreeConsole invoke SetConsoleCtrlHandler,NULL,FALSE .endif .endif .endif ...so it seems to work and the CLI app gets closed but I am not so sure whether this code example is good idea to use it on that way etc.In Olly it does crash after I did traced over this code after (not in outside of Olly).So is it needed to use FreeConsole & SetConsoleCtrlHandler at the end if the CLI is no more present?I dont think so or?I am using already cmd.exe /c paramter in CreateProcess function. Other issue I see is that I dont use the flag CREATE_NEW_PROCESS_GROUP (in the link above they told to use it but then CTRL_C_EVENT isnt working).Maybe you have some another little clue how I should do it correctly to send CTRL_C_EVENT & wait without to get any trouble later and I also dont wanna exit the CLI process rough you know. greetz Link to post
evlncrn8 358 Posted October 7, 2018 Share Posted October 7, 2018 https://docs.microsoft.com/en-us/windows/console/generateconsolectrlevent should do it invoke FreeConsole invoke SetConsoleCtrlHandler,NULL,FALSE it might well crash there, considering you still have the handler registered so maybe flip that code around.. setevent then freeconsole.. see what happens .. 1 Link to post
LCF-AT 2,465 Posted October 8, 2018 Author Share Posted October 8, 2018 Hi again, ok I used it so now with freeconsole & Setconsolehandler at the end.So if I dont do it then it dosent work anymore after first try.My thread code look so now... local WASATTACHED:DWORD mov WASATTACHED, 0 @@: .if STOP == 1 ; <--- stop CLI invoke GetExitCodeProcess,[PI.hProcess],addr ExitCode .if ExitCode == STILL_ACTIVE && WASATTACHED == NULL invoke AttachConsole,PI.dwProcessId mov WASATTACHED, 1 invoke SetConsoleCtrlHandler,NULL,TRUE invoke GenerateConsoleCtrlEvent,CTRL_C_EVENT,NULL .endif .endif invoke RtlZeroMemory,addr PIPEBUFFER,sizeof PIPEBUFFER invoke Sleep,30 invoke PeekNamedPipe,hRead,offset PIPEBUFFER,sizeof PIPEBUFFER-10h,offset PIPEREADBYTES,addr AVAL,NULL .if eax != FALSE .if AVAL != 0h invoke RtlZeroMemory,addr PIPEBUFFER,sizeof PIPEBUFFER invoke ReadFile,hRead,addr PIPEBUFFER,PIPEREADBYTES,addr BYTESREAD,0 .if eax != FALSE invoke SendMessage,RICHEDITHANDLE,EM_REPLACESEL,FALSE,addr PIPEBUFFER invoke RichSetPos, RICHEDITHANDLE, -1h jmp @B .else invoke MessageBox,0,chr$("ReadFile failed!"),chr$("Problem!"),MB_ICONWARNING jmp @F .endif .else invoke GetExitCodeProcess,[PI.hProcess],addr ExitCode .if ExitCode == STILL_ACTIVE jmp @B .endif .endif .else invoke MessageBox,0,chr$("PeekNamedPipe failed!"),chr$("Problem!"),MB_ICONWARNING .endif @@: invoke CloseHandle, hRead invoke CloseHandle, hWrite invoke CloseHandle, [PI.hThread] invoke CloseHandle, [PI.hProcess] .if STOP == 1 && WASATTACHED == 1 invoke FreeConsole invoke SetConsoleCtrlHandler,NULL,FALSE .endif mov STOP, 0 xor eax,eax Ret ...seems to work fine so far. Thanks again for the help. greetz Link to post
LCF-AT 2,465 Posted March 30 Author Share Posted March 30 Hi again, so I have another addon question about starting console windows,So how to manage to start more than one console instances?Lets say I wanna run a CLI app few times via CreateProcess function and I wanna also check whether they are still running and I wanna also force to exit them if I want by sending CTRL_C_EVENT (same code as above).Is that doable?In example above I have to use that functions... CreateProcess ---------------- AttachConsole SetConsoleCtrlHandler GenerateConsoleCtrlEvent GetExitCodeProcess CloseHandle FreeConsole SetConsoleCtrlHandler ...which are working for one instance without problems but now I wanna start more than one instances at same time or one by one you know.So above in code example I saw the info... // It's impossible to be attached to 2 consoles at the same time, // so release the current one. ...which tells me that there is any limit and I only can attach only one CLI.Is that right? CreateProcess ---------------- invoke AttachConsole,PI.dwProcessId <-- PID invoke SetConsoleCtrlHandler,NULL,TRUE <-- No PID invoke GenerateConsoleCtrlEvent,CTRL_C_EVENT,NULL <-- No PID invoke GetExitCodeProcess,[PI.hProcess],addr ExitCode <-- PID invoke CloseHandle, [PI.hThread] <-- PID invoke CloseHandle, [PI.hProcess] <-- PID invoke FreeConsole <-- No PID invoke SetConsoleCtrlHandler,NULL,FALSE <-- No PID Above you can see the functions I can use a PID with and some of them I can not use a specific PID.When I start more than one CLI apps at same time then I can not control all at the samt time?How to manage that problem to get access to all running CLI instances I did started to send Events into the right CLI window? Or have I just to set a lock on that attach / FreeConsole code to handle each PID seperated one by one?Some kind of "right of way" like in traffic etc?Maybe you can tell me or show some code lines how to manage that better to run more than one instances at same time.Thank you. greetz Link to post
fearless 151 Posted April 1 Share Posted April 1 https://www.codeproject.com/articles/13368/multiple-consoles-for-a-single-application https://codereview.stackexchange.com/questions/195157/using-multiple-console-windows-for-output 1 Link to post
LCF-AT 2,465 Posted April 1 Author Share Posted April 1 Hi fearless, thanks for this info but I'am not sure about that whether I could use it (as I think) and its also some C stuff (no clue about that) you know.So if I read it right then it wants to create some child processes for another CLI window/s but in my case I want to run diffrent instances seperated from each other.Otherwise lets say I do start 4 CLI windows (anyhow with that C code) then it will build child processes from first started CLI right?But what is when I have to exit the first CLI process?Then child processes get closed too or not? greetz Link to post
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now