1 /********************************************************************
2 * Module: process.cpp. This is part of Visual-MinGW.
4 * Purpose: Procedures to invoke MinGW compiler.
8 * License: Visual-MinGW is covered by GNU General Public License,
9 * Copyright (C) 2001 Manu B.
10 * See license.htm for more details.
12 * Note: The following article from MSDN explanes how to handle Callback
14 * Calling All Members: Member Functions as Callbacks.
16 * Microsoft Developer Network Technology Group.
18 * http://msdn.microsoft.com/archive/default.asp
22 ********************************************************************/
33 extern CCriticalSection CriticalSection
;
34 extern CMessageBox MsgBox
;
37 // For winApp.isWinNT and winApp.Report.Append
38 extern CWinApp winApp
;
40 /********************************************************************
47 ********************************************************************/
48 CCommandDlg::CCommandDlg(){
52 CCommandDlg::~CCommandDlg(){
55 HWND
CCommandDlg::Create(void){
56 return CreateParam(&winApp
, IDD_COMMAND
, 0);
59 LRESULT CALLBACK
CCommandDlg::CDlgProc(UINT Message
, WPARAM wParam
, LPARAM lParam
){
62 return OnInitDialog((HWND
) wParam
, lParam
);
65 OnCommand(HIWORD(wParam
), LOWORD(wParam
), (HWND
) lParam
);
75 BOOL
CCommandDlg::OnInitDialog(HWND
, LPARAM
){
76 hCmdLine
= GetItem(IDC_CMDLINE
);
78 SetItemText(hCmdLine
, cmdLine
);
84 BOOL
CCommandDlg::OnCommand(WORD
, WORD wID
, HWND
){
87 GetItemText(hCmdLine
, cmdLine
, sizeof(cmdLine
));
88 //MsgBox.DisplayString(cmdLine);
89 winApp
.Process
.CommandLine(cmdLine
);
100 /********************************************************************
107 ********************************************************************/
119 /********************************************************************
126 ********************************************************************/
137 void CStack::DetachCurrent(void){
139 if (current
!= NULL
){
140 CNode
* node
= current
;
142 // Detach node from the list.
143 if (node
->next
!= NULL
)
144 node
->next
->prev
= node
->prev
;
145 if (node
->prev
!= NULL
)
146 node
->prev
->next
= node
->next
;
149 if(node
->next
!= NULL
)
150 current
= node
->next
;
152 current
= node
->prev
;
154 if (current
== NULL
){
155 // Now, the list is empty.
158 }else if (first
== node
){
159 // Detached node was first.
162 }else if (last
== node
){
163 // Detached node was last.
170 /********************************************************************
172 ********************************************************************/
173 int CStack::Push(CTask
* newTask
){
178 CTask
* CStack::Pop(void){
179 // Delete return buffer.
185 // Get first node. (FIFO stack)
186 retBuf
= (CTask
*) First();
188 // The Stack is empty ?
192 // Detach current node from the list. Return a pointer to it.
197 void CStack::Flush(void){
205 /********************************************************************
208 * Purpose: Creates needed pipes, depending on creationFlag.
209 * Like GNU Make does, we use an Handle array for our pipes.
210 * Parent Process Side is stdXXX[0] and Child Process Side is stdXXX[1].
212 * Ex: PARENT ->[0]IN_PIPE[1]-> CHILD_IO ->[1]OUT_PIPE[0]-> PARENT
213 * ->[1]ERR_PIPE[0]-> PARENT
216 ********************************************************************/
229 bool CPipes::Create(WORD creationFlag
, bool winNT
){
230 /* Create needed pipes according to creationFlag */
231 /* Parent side of pipes is [0], child side is [1] */
233 SECURITY_ATTRIBUTES sa
;
234 sa
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
235 sa
.bInheritHandle
= TRUE
;
236 sa
.lpSecurityDescriptor
= NULL
;
239 /* Create a security descriptor for Windows NT */
240 SECURITY_DESCRIPTOR sd
;
241 if (!InitializeSecurityDescriptor(&sd
, SECURITY_DESCRIPTOR_REVISION
)){
242 sprintf(errmsg
, "vm error: Process.cpp InitializeSecurityDescriptor(winNT) failed (e=%d)", (int)GetLastError());
243 winApp
.Report
.Append(errmsg
, LVOUT_ERROR
);
246 if (!SetSecurityDescriptorDacl(&sd
, TRUE
, NULL
, FALSE
)){
247 sprintf(errmsg
, "vm error: Process.cpp SetSecurityDescriptorDacl(winNT) failed (e=%d)", (int)GetLastError());
248 winApp
.Report
.Append(errmsg
, LVOUT_ERROR
);
251 sa
.lpSecurityDescriptor
= &sd
;
255 if (!CreatePipe(&hIn
[1], &hIn
[0], &sa
, 0)){
256 sprintf(errmsg
, "vm error: Process.cpp CreatePipe(In) failed (e=%d)", (int)GetLastError());
257 winApp
.Report
.Append(errmsg
, LVOUT_ERROR
);
261 if (!DuplicateHandle(GetCurrentProcess(),
267 DUPLICATE_SAME_ACCESS
)){
268 sprintf(errmsg
, "vm error: Process.cpp DuplicateHandle(In) failed (e=%d)", (int)GetLastError());
269 winApp
.Report
.Append(errmsg
, LVOUT_ERROR
);
276 if (!CreatePipe(&hOut
[0], &hOut
[1], &sa
, 0)){
277 sprintf(errmsg
, "vm error: Process.cpp CreatePipe(Out) failed (e=%d)", (int)GetLastError());
278 winApp
.Report
.Append(errmsg
, LVOUT_ERROR
);
282 if (!DuplicateHandle(GetCurrentProcess(),
288 DUPLICATE_SAME_ACCESS
)){
289 sprintf(errmsg
, "vm error: Process.cpp DuplicateHandle(Out) failed (e=%d)", (int)GetLastError());
290 winApp
.Report
.Append(errmsg
, LVOUT_ERROR
);
293 CloseHandle(hOut
[0]);
297 if (!(creationFlag
& OUTERR_PIPE
) && (creationFlag
& ERR_PIPE
)){
298 if (!CreatePipe(&hErr
[0], &hErr
[1], &sa
, 0)){
299 sprintf(errmsg
, "vm error: Process.cpp CreatePipe(Err) failed (e=%d)", (int)GetLastError());
300 winApp
.Report
.Append(errmsg
, LVOUT_ERROR
);
304 if (!DuplicateHandle(GetCurrentProcess(),
310 DUPLICATE_SAME_ACCESS
)){
311 sprintf(errmsg
, "vm error: Process.cpp DuplicateHandle(Err) failed (e=%d)", (int)GetLastError());
312 winApp
.Report
.Append(errmsg
, LVOUT_ERROR
);
315 CloseHandle(hErr
[0]);
321 bool CPipes::CloseChildSide(void){
325 bool CPipes::CloseParentSide(void){
329 bool CPipes::Close(int side
){
331 if (side
< 0 || side
> 1)
335 CloseHandle(hIn
[side
]);
340 CloseHandle(hOut
[side
]);
345 CloseHandle(hErr
[side
]);
352 /********************************************************************
359 ********************************************************************/
360 CProcess::CProcess(){
370 CProcess::~CProcess(){
373 /********************************************************************
375 ********************************************************************/
376 bool CProcess::isRunning(void){
378 MsgBox
.DisplayWarning("A process is already running !");
384 CTask
* CProcess::AddTask(char * cmdLine
, WORD creationFlag
, WORD outputFlag
){
385 CTask
* newTask
= new CTask
;
387 strcpy(newTask
->cmdLine
, cmdLine
);
388 newTask
->creationFlag
= creationFlag
;
389 newTask
->outputFlag
= outputFlag
;
394 bool CProcess::CmdCat(char * cmdLine
){
395 CTask
* task
= (CTask
*) GetCurrent();
399 strcat(task
->cmdLine
, cmdLine
);
403 /********************************************************************
404 * RunNext/Run/RunProcess.
405 ********************************************************************/
406 void __cdecl
call_thread(void * ptr
){
408 ((CProcess
*) ptr
)->Run_Thread_Internal();
411 void CProcess::Run(void){
412 // Check if something is already running before creating a thread.
414 // Call Run_Thread_Internal()
415 _beginthread(call_thread
, 1024 * 1024, (void *) this);
419 void CProcess::Run_Thread_Internal(void){
421 /* Execute each task */
423 /* If previous task returns an error code, abort */
427 // Get one task to execute.
434 /* Show command lines ?*/
435 winApp
.Report
.Append(currTask
->cmdLine
, LVOUT_NORMAL
);
437 if (RunProcess(currTask
)){
438 winApp
.Report
.Append("Abort !", LVOUT_NORMAL
);
446 winApp
.Report
.Append("Performed successfully.", LVOUT_NORMAL
);
453 bool CProcess::RunProcess(CTask
* task
){
457 bool usePipes
= task
->creationFlag
;
458 STARTUPINFO si
= {sizeof(STARTUPINFO
), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
461 /* PROCESS_INFORMATION */
467 /* Process creation with pipes */
469 /* Create needed pipes according to creationFlag */
470 if(!Pipes
.Create(task
->creationFlag
, winApp
.isWinNT
)){
471 Pipes
.CloseChildSide();
472 Pipes
.CloseParentSide();
476 si
.dwFlags
= STARTF_USESHOWWINDOW
| STARTF_USESTDHANDLES
;
477 si
.wShowWindow
= SW_HIDE
;
478 //si.wShowWindow = SW_SHOWNORMAL;
480 /* Set pipe handles */
481 if (Pipes
.hIn
[1] != NULL
&& Pipes
.hOut
[1] != NULL
){
482 si
.hStdInput
= Pipes
.hIn
[1];
483 si
.hStdOutput
= Pipes
.hOut
[1];
484 if (Pipes
.hErr
[1] == NULL
)
485 si
.hStdError
= Pipes
.hOut
[1];
487 si
.hStdError
= Pipes
.hErr
[1];
489 sprintf(errmsg
, "vm error: Process.cpp Invalid pipe handle");
490 winApp
.Report
.Append(errmsg
, LVOUT_ERROR
);
491 Pipes
.CloseChildSide();
492 Pipes
.CloseParentSide();
497 /* Create the child process */
498 Running
= CreateProcess(NULL
,
505 /*startDir[0] ? startDir :*/ NULL
,
510 /* CreateProcess failed. Close handles and return */
511 Pipes
.CloseChildSide();
512 Pipes
.CloseParentSide();
513 sprintf(errmsg
, "vm error: Process.cpp CreateProcess failed (e=%d)", (int)GetLastError());
514 winApp
.Report
.Append(errmsg
, LVOUT_ERROR
);
517 /* Close child process handles */
518 Pipes
.CloseChildSide();
520 if (!(usePipes
& IN_PIPE
)){
521 /* Don't use the Input pipe */
522 ::CloseHandle(Pipes
.hIn
[0]);
527 //sprintf(errmsg, "vm debug: enter io loop");
528 //winApp.Report.Append(errmsg, LVOUT_ERROR);
530 /* Initialize buffers */
537 bResult
= ReadStdOut(task
, Pipes
.hOut
[0]);
538 if (bResult
!= NO_ERROR
)
541 ::GetExitCodeProcess(pi
.hProcess
, &exitCode
);
542 if (exitCode
!= STILL_ACTIVE
){
547 //sprintf(errmsg, "vm debug: exit io loop");
548 //winApp.Report.Append(errmsg, LVOUT_ERROR);
550 /* The child process is running. Perform I/O until terminated */
551 ::WaitForSingleObject(pi
.hProcess
, INFINITE
);
552 /* Process terminated. Get exit code. */
553 ::GetExitCodeProcess(pi
.hProcess
, &exitCode
);
554 if (exitCode
== NO_ERROR
){
558 Pipes
.CloseParentSide();
559 ::CloseHandle(pi
.hProcess
);
561 ::CloseHandle(pi
.hThread
);
567 /********************************************************************
568 * Pipes input/output.
569 ********************************************************************/
570 void CProcess::WriteStdIn(HANDLE hPipe
, WORD
){
577 void CProcess::ReadStdErr(HANDLE hPipe
, WORD
){
584 long CProcess::ReadStdOut(CTask
* task
, HANDLE hPipe
){
586 return ERROR_INVALID_FUNCTION
;
588 /* Copy each char and output lines while there is something to read */
590 // Copy one char, return if nothing available.
591 if (!ReadOneChar(hPipe
, chr
))
601 if ((chr - outBuf) >= max_len)
604 }else if (*chr
=='\n'){
606 // Output error lines to List View.
607 if (task
->outputFlag
== STDOUT_FILE_APPEND
){
608 WriteFileAppend(task
->szFileName
, outBuf
, (chr
- outBuf
));
610 OutputLine(task
->outputFlag
, outBuf
, (chr
- outBuf
));
619 int CProcess::ReadOneChar(HANDLE hPipe
, char * chrin
){
621 DWORD bytesAvail
= 0;
623 if (!PeekNamedPipe(hPipe
, chrin
, (DWORD
)1, &bytesRead
, &bytesAvail
, NULL
))
629 if (!ReadFile(hPipe
, chrin
, (DWORD
)1, &bytesRead
, NULL
))
635 bool CProcess::CommandLine(char * cmdLine
){
638 if (!Running
|| !currTask
|| !currTask
->creationFlag
)
640 int len
= strlen(cmdLine
);
642 strcpy(inBuf
, cmdLine
);
653 if (!WriteFile(Pipes
.hIn
[0], inBuf
, strlen(inBuf
), &written
, 0))
659 bool CProcess::WriteFileAppend(char * fileName
, char * line
, int /*len*/){
663 /* Append one line of text to a file */
664 FILE * file
= fopen(fileName
, "a");
674 bool CProcess::OutputLine(WORD outputFlag
, char * line
, int /*len*/){
675 /* Output error lines to List View */
677 CriticalSection
.Enter();
678 winApp
.Report
.Append(line
, outputFlag
);
679 CriticalSection
.Leave();