1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/utilsexec.cpp
3 // Purpose: Various utilities
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
40 #include "wx/stream.h"
41 #include "wx/process.h"
44 #include "wx/msw/private.h"
48 #if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__)
55 #if defined(__GNUWIN32__) && !defined(__TWIN32__)
56 #include <sys/unistd.h>
60 #if defined(__WIN32__) && !defined(__WXWINE__)
72 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
79 #include "wx/dde.h" // for WX_DDE hack in wxExecute
82 // ----------------------------------------------------------------------------
84 // ----------------------------------------------------------------------------
86 // this message is sent when the process we're waiting for terminates
87 #define wxWM_PROC_TERMINATED (WM_USER + 10000)
89 // ----------------------------------------------------------------------------
90 // this module globals
91 // ----------------------------------------------------------------------------
93 // we need to create a hidden window to receive the process termination
94 // notifications and for this we need a (Win) class name for it which we will
95 // register the first time it's needed
96 static const wxChar
*gs_classForHiddenWindow
= NULL
;
98 // ----------------------------------------------------------------------------
100 // ----------------------------------------------------------------------------
102 // structure describing the process we're being waiting for
109 if ( !::CloseHandle(hProcess
) )
111 wxLogLastError("CloseHandle(hProcess)");
116 HWND hWnd
; // window to send wxWM_PROC_TERMINATED to
117 HANDLE hProcess
; // handle of the process
118 DWORD dwProcessId
; // pid of the process
120 DWORD dwExitCode
; // the exit code of the process
121 bool state
; // set to FALSE when the process finishes
126 // ----------------------------------------------------------------------------
128 // ----------------------------------------------------------------------------
130 class wxPipeInputStream
: public wxInputStream
{
132 wxPipeInputStream(HANDLE hInput
);
133 ~wxPipeInputStream();
136 size_t OnSysRead(void *buffer
, size_t len
);
142 class wxPipeOutputStream
: public wxOutputStream
{
144 wxPipeOutputStream(HANDLE hOutput
);
145 ~wxPipeOutputStream();
148 size_t OnSysWrite(const void *buffer
, size_t len
);
154 // ==================
156 // ==================
158 wxPipeInputStream::wxPipeInputStream(HANDLE hInput
)
163 wxPipeInputStream::~wxPipeInputStream()
165 ::CloseHandle(m_hInput
);
168 size_t wxPipeInputStream::OnSysRead(void *buffer
, size_t len
)
172 m_lasterror
= wxSTREAM_NOERROR
;
173 if (! ::ReadFile(m_hInput
, buffer
, len
, &bytesRead
, NULL
) ) {
174 if (GetLastError() == ERROR_BROKEN_PIPE
)
175 m_lasterror
= wxSTREAM_EOF
;
177 m_lasterror
= wxSTREAM_READ_ERROR
;
182 // ==================
183 // wxPipeOutputStream
184 // ==================
186 wxPipeOutputStream::wxPipeOutputStream(HANDLE hOutput
)
191 wxPipeOutputStream::~wxPipeOutputStream()
193 ::CloseHandle(m_hOutput
);
196 size_t wxPipeOutputStream::OnSysWrite(const void *buffer
, size_t len
)
200 m_lasterror
= wxSTREAM_NOERROR
;
201 if (! ::WriteFile(m_hOutput
, buffer
, len
, &bytesRead
, NULL
) ) {
202 if (GetLastError() == ERROR_BROKEN_PIPE
)
203 m_lasterror
= wxSTREAM_EOF
;
205 m_lasterror
= wxSTREAM_READ_ERROR
;
212 // ============================================================================
214 // ============================================================================
217 static DWORD
wxExecuteThread(wxExecuteData
*data
)
219 WaitForSingleObject(data
->hProcess
, INFINITE
);
222 if ( !GetExitCodeProcess(data
->hProcess
, &data
->dwExitCode
) )
224 wxLogLastError("GetExitCodeProcess");
227 wxASSERT_MSG( data
->dwExitCode
!= STILL_ACTIVE
,
228 wxT("process should have terminated") );
230 // send a message indicating process termination to the window
231 SendMessage(data
->hWnd
, wxWM_PROC_TERMINATED
, 0, (LPARAM
)data
);
236 // window procedure of a hidden window which is created just to receive
237 // the notification message when a process exits
238 LRESULT APIENTRY _EXPORT
wxExecuteWindowCbk(HWND hWnd
, UINT message
,
239 WPARAM wParam
, LPARAM lParam
)
241 if ( message
== wxWM_PROC_TERMINATED
)
243 DestroyWindow(hWnd
); // we don't need it any more
245 wxExecuteData
*data
= (wxExecuteData
*)lParam
;
248 data
->handler
->OnTerminate((int)data
->dwProcessId
,
249 (int)data
->dwExitCode
);
254 // we're executing synchronously, tell the waiting thread
255 // that the process finished
260 // asynchronous execution - we should do the clean up
268 return DefWindowProc(hWnd
, message
, wParam
, lParam
);
273 long wxExecute(const wxString
& cmd
, bool sync
, wxProcess
*handler
)
275 wxCHECK_MSG( !!cmd
, 0, wxT("empty command in wxExecute") );
279 // DDE hack: this is really not pretty, but we need to allow this for
280 // transparent handling of DDE servers in wxMimeTypesManager. Usually it
281 // returns the command which should be run to view/open/... a file of the
282 // given type. Sometimes, however, this command just launches the server
283 // and an additional DDE request must be made to really open the file. To
284 // keep all this well hidden from the application, we allow a special form
285 // of command: WX_DDE:<command>:DDE_SERVER:DDE_TOPIC:DDE_COMMAND in which
286 // case we execute just <command> and process the rest below
287 wxString ddeServer
, ddeTopic
, ddeCommand
;
288 static const size_t lenDdePrefix
= 7; // strlen("WX_DDE:")
289 if ( cmd
.Left(lenDdePrefix
) == _T("WX_DDE#") )
291 const wxChar
*p
= cmd
.c_str() + 7;
292 while ( *p
&& *p
!= _T('#') )
304 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
307 while ( *p
&& *p
!= _T('#') )
319 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
322 while ( *p
&& *p
!= _T('#') )
334 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
349 #if defined(__WIN32__) && !defined(__TWIN32__)
350 // the old code is disabled because we really need a process handle
351 // if we want to execute it asynchronously or even just get its
352 // return code and for this we must use CreateProcess() and not
355 // isolate command and arguments
356 wxString commandName
;
357 bool insideQuotes
= FALSE
;
359 for ( pc
= command
.c_str(); *pc
!= '\0'; pc
++ )
370 insideQuotes
= !insideQuotes
;
375 continue; // skip the next break
378 // only reached for space not inside quotes
381 wxString commandArgs
= pc
;
383 wxWindow
*winTop
= wxTheApp
->GetTopWindow();
384 HWND hwndTop
= (HWND
)(winTop
? winTop
->GetHWND() : 0);
388 result
= ShellExecute(hwndTop
,
389 (const wchar_t)"open",
390 (const wchar_t)commandName
,
391 (const wchar_t)commandArgs
,
395 result
= ShellExecute(hwndTop
, "open", commandName
,
396 commandArgs
, NULL
, SW_SHOWNORMAL
);
399 if ( ((long)result
) <= 32 )
400 wxLogSysError(_("Can't execute command '%s'"), command
.c_str());
406 HANDLE hpipeWrite
[2];
407 HANDLE hStdIn
= INVALID_HANDLE_VALUE
;
408 HANDLE hStdOut
= INVALID_HANDLE_VALUE
;
410 // we need to inherit handles in the child process if we want to redirect
412 BOOL inheritHandles
= FALSE
;
414 // open the pipes to which child process IO will be redirected if needed
415 if ( handler
&& handler
->IsRedirected() )
417 SECURITY_ATTRIBUTES security
;
419 security
.nLength
= sizeof(security
);
420 security
.lpSecurityDescriptor
= NULL
;
421 security
.bInheritHandle
= TRUE
;
423 if ( !::CreatePipe(&hpipeRead
[0], &hpipeRead
[1], &security
, 0) )
425 wxLogSysError(_("Can't create the inter-process read pipe"));
430 if ( !::CreatePipe(&hpipeWrite
[0], &hpipeWrite
[1], &security
, 0) )
432 ::CloseHandle(hpipeRead
[0]);
433 ::CloseHandle(hpipeRead
[1]);
435 wxLogSysError(_("Can't create the inter-process write pipe"));
440 // We need to save the old stdio handles to restore them after the call
442 hStdIn
= ::GetStdHandle(STD_INPUT_HANDLE
);
443 hStdOut
= ::GetStdHandle(STD_OUTPUT_HANDLE
);
445 if ( !::SetStdHandle(STD_INPUT_HANDLE
, hpipeRead
[0]) ||
446 !::SetStdHandle(STD_OUTPUT_HANDLE
, hpipeWrite
[1]) )
448 wxLogDebug(_T("Failed to change stdin/out handles"));
451 inheritHandles
= TRUE
;
454 // create the process
460 PROCESS_INFORMATION pi
;
462 if ( ::CreateProcess(
463 NULL
, // application name (use only cmd line)
464 (wxChar
*)command
.c_str(), // full command line
465 NULL
, // security attributes: defaults for both
466 NULL
, // the process and its main thread
467 inheritHandles
, // inherit handles if we need pipes
468 CREATE_DEFAULT_ERROR_MODE
|
469 CREATE_SUSPENDED
, // flags
470 NULL
, // environment (use the same)
471 NULL
, // current directory (use the same)
472 &si
, // startup info (unused here)
476 if ( inheritHandles
)
478 ::CloseHandle(hpipeWrite
[0]);
479 ::CloseHandle(hpipeWrite
[1]);
480 ::CloseHandle(hpipeRead
[0]);
481 ::CloseHandle(hpipeRead
[1]);
484 wxLogSysError(_("Execution of command '%s' failed"), command
.c_str());
489 // Restore the old stdio handles
490 if ( inheritHandles
)
492 if ( !::SetStdHandle(STD_INPUT_HANDLE
, hStdIn
) ||
493 !::SetStdHandle(STD_OUTPUT_HANDLE
, hStdOut
) )
495 wxLogDebug(_T("Failed to restore old stdin/out handles"));
498 // they're still opened in child process
499 ::CloseHandle(hpipeWrite
[1]);
500 ::CloseHandle(hpipeRead
[0]);
502 // We can now initialize the wxStreams
503 wxInputStream
*inStream
= new wxPipeInputStream(hpipeWrite
[0]);
504 wxOutputStream
*outStream
= new wxPipeOutputStream(hpipeRead
[1]);
506 handler
->SetPipeStreams(inStream
, outStream
);
509 // register the class for the hidden window used for the notifications
510 if ( !gs_classForHiddenWindow
)
512 gs_classForHiddenWindow
= _T("wxHiddenWindow");
515 wxZeroMemory(wndclass
);
516 wndclass
.lpfnWndProc
= (WNDPROC
)wxExecuteWindowCbk
;
517 wndclass
.hInstance
= wxGetInstance();
518 wndclass
.lpszClassName
= gs_classForHiddenWindow
;
520 if ( !::RegisterClass(&wndclass
) )
522 wxLogLastError("RegisterClass(hidden window)");
526 // create a hidden window to receive notification about process
528 HWND hwnd
= ::CreateWindow(gs_classForHiddenWindow
, NULL
,
531 (HMENU
)NULL
, wxGetInstance(), 0);
532 wxASSERT_MSG( hwnd
, wxT("can't create a hidden window for wxExecute") );
535 wxExecuteData
*data
= new wxExecuteData
;
536 data
->hProcess
= pi
.hProcess
;
537 data
->dwProcessId
= pi
.dwProcessId
;
542 // handler may be !NULL for capturing program output, but we don't use
543 // it wxExecuteData struct in this case
544 data
->handler
= NULL
;
548 // may be NULL or not
549 data
->handler
= handler
;
553 HANDLE hThread
= ::CreateThread(NULL
,
555 (LPTHREAD_START_ROUTINE
)wxExecuteThread
,
560 // resume process we created now - whether the thread creation succeeded or
562 if ( ::ResumeThread(pi
.hThread
) == (DWORD
)-1 )
564 // ignore it - what can we do?
565 wxLogLastError("ResumeThread in wxExecute");
568 // close unneeded handle
569 if ( !::CloseHandle(pi
.hThread
) )
570 wxLogLastError("CloseHandle(hThread)");
574 wxLogLastError("CreateThread in wxExecute");
579 // the process still started up successfully...
580 return pi
.dwProcessId
;
584 // second part of DDE hack: now establish the DDE conversation with the
585 // just launched process
589 wxConnectionBase
*conn
= client
.MakeConnection(_T(""),
592 if ( !conn
|| !conn
->Execute(ddeCommand
) )
594 wxLogError(_("Couldn't launch DDE server '%s'."), command
.c_str());
601 // clean up will be done when the process terminates
604 return pi
.dwProcessId
;
607 // waiting until command executed (disable everything while doing it)
615 while ( data
->state
)
622 DWORD dwExitCode
= data
->dwExitCode
;
625 // return the exit code
629 long instanceID
= WinExec((LPCSTR
) WXSTRINGCAST command
, SW_SHOW
);
630 if (instanceID
< 32) return(0);
636 running
= GetModuleUsage((HINSTANCE
)instanceID
);
644 long wxExecute(char **argv
, bool sync
, wxProcess
*handler
)
648 while ( *argv
!= NULL
)
650 command
<< *argv
++ << ' ';
653 command
.RemoveLast();
655 return wxExecute(command
, sync
, handler
);
658 // ----------------------------------------------------------------------------
660 // ----------------------------------------------------------------------------
662 extern void PixelToHIMETRIC(LONG
*x
, LONG
*y
)
666 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
667 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
668 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
669 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
671 *x
*= (iWidthMM
* 100);
673 *y
*= (iHeightMM
* 100);
677 extern void HIMETRICToPixel(LONG
*x
, LONG
*y
)
681 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
682 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
683 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
684 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
687 *x
/= (iWidthMM
* 100);
689 *y
/= (iHeightMM
* 100);