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());
405 HANDLE h_readPipe
[2];
406 HANDLE h_writePipe
[2];
407 HANDLE h_oldreadPipe
;
408 HANDLE h_oldwritePipe
;
411 // open the pipes to which child process IO will be redirected if needed
412 inheritHandles
= FALSE
;
413 if ( handler
&& handler
->IsRedirected() )
415 SECURITY_ATTRIBUTES security
;
417 security
.nLength
= sizeof(security
);
418 security
.lpSecurityDescriptor
= NULL
;
419 security
.bInheritHandle
= TRUE
;
421 if (! ::CreatePipe(&h_readPipe
[0], &h_readPipe
[1], &security
, 0) )
423 wxLogSysError(_("Can't create the inter-process read pipe"));
428 if (! ::CreatePipe(&h_writePipe
[0], &h_writePipe
[1], &security
, 0) )
430 ::CloseHandle(h_readPipe
[0]);
431 ::CloseHandle(h_readPipe
[1]);
433 wxLogSysError(_("Can't create the inter-process write pipe"));
438 // We need to save the old stdio handles to restore them after the call
440 h_oldreadPipe
= GetStdHandle(STD_INPUT_HANDLE
);
441 h_oldwritePipe
= GetStdHandle(STD_OUTPUT_HANDLE
);
443 SetStdHandle(STD_INPUT_HANDLE
, h_readPipe
[0]);
444 SetStdHandle(STD_OUTPUT_HANDLE
, h_writePipe
[1]);
446 inheritHandles
= TRUE
;
449 // create the process
455 PROCESS_INFORMATION pi
;
457 if ( ::CreateProcess(
458 NULL
, // application name (use only cmd line)
459 (wxChar
*)command
.c_str(), // full command line
460 NULL
, // security attributes: defaults for both
461 NULL
, // the process and its main thread
462 inheritHandles
, // inherit handles if we need pipes
463 CREATE_DEFAULT_ERROR_MODE
|
464 CREATE_SUSPENDED
, // flags
465 NULL
, // environment (use the same)
466 NULL
, // current directory (use the same)
467 &si
, // startup info (unused here)
471 if ( inheritHandles
)
473 ::CloseHandle(h_writePipe
[0]);
474 ::CloseHandle(h_writePipe
[1]);
475 ::CloseHandle(h_readPipe
[0]);
476 ::CloseHandle(h_readPipe
[1]);
479 wxLogSysError(_("Execution of command '%s' failed"), command
.c_str());
484 // Restore the old stdio handles
485 if (inheritHandles
) {
486 SetStdHandle(STD_INPUT_HANDLE
, h_oldreadPipe
);
487 SetStdHandle(STD_OUTPUT_HANDLE
, h_oldwritePipe
);
489 ::CloseHandle(h_writePipe
[1]);
490 ::CloseHandle(h_readPipe
[0]);
491 // We can now initialize the wxStreams
492 wxInputStream
*processOutput
= new wxPipeInputStream(h_writePipe
[0]);
493 wxOutputStream
*processInput
= new wxPipeOutputStream(h_readPipe
[1]);
495 handler
->SetPipeStreams(processOutput
, processInput
);
498 // register the class for the hidden window used for the notifications
499 if ( !gs_classForHiddenWindow
)
501 gs_classForHiddenWindow
= _T("wxHiddenWindow");
504 wxZeroMemory(wndclass
);
505 wndclass
.lpfnWndProc
= (WNDPROC
)wxExecuteWindowCbk
;
506 wndclass
.hInstance
= wxGetInstance();
507 wndclass
.lpszClassName
= gs_classForHiddenWindow
;
509 if ( !::RegisterClass(&wndclass
) )
511 wxLogLastError("RegisterClass(hidden window)");
515 // create a hidden window to receive notification about process
517 HWND hwnd
= ::CreateWindow(gs_classForHiddenWindow
, NULL
,
520 (HMENU
)NULL
, wxGetInstance(), 0);
521 wxASSERT_MSG( hwnd
, wxT("can't create a hidden window for wxExecute") );
524 wxExecuteData
*data
= new wxExecuteData
;
525 data
->hProcess
= pi
.hProcess
;
526 data
->dwProcessId
= pi
.dwProcessId
;
531 wxASSERT_MSG( !handler
, wxT("wxProcess param ignored for sync execution") );
533 data
->handler
= NULL
;
537 // may be NULL or not
538 data
->handler
= handler
;
542 HANDLE hThread
= ::CreateThread(NULL
,
544 (LPTHREAD_START_ROUTINE
)wxExecuteThread
,
549 // resume process we created now - whether the thread creation succeeded or
551 if ( ::ResumeThread(pi
.hThread
) == (DWORD
)-1 )
553 // ignore it - what can we do?
554 wxLogLastError("ResumeThread in wxExecute");
557 // close unneeded handle
558 if ( !::CloseHandle(pi
.hThread
) )
559 wxLogLastError("CloseHandle(hThread)");
563 wxLogLastError("CreateThread in wxExecute");
568 // the process still started up successfully...
569 return pi
.dwProcessId
;
573 // second part of DDE hack: now establish the DDE conversation with the
574 // just launched process
578 wxConnectionBase
*conn
= client
.MakeConnection(_T(""),
581 if ( !conn
|| !conn
->Execute(ddeCommand
) )
583 wxLogError(_("Couldn't launch DDE server '%s'."), command
.c_str());
590 // clean up will be done when the process terminates
593 return pi
.dwProcessId
;
596 // waiting until command executed (disable everything while doing it)
604 while ( data
->state
)
611 DWORD dwExitCode
= data
->dwExitCode
;
614 // return the exit code
618 long instanceID
= WinExec((LPCSTR
) WXSTRINGCAST command
, SW_SHOW
);
619 if (instanceID
< 32) return(0);
625 running
= GetModuleUsage((HINSTANCE
)instanceID
);
633 long wxExecute(char **argv
, bool sync
, wxProcess
*handler
)
637 while ( *argv
!= NULL
)
639 command
<< *argv
++ << ' ';
642 command
.RemoveLast();
644 return wxExecute(command
, sync
, handler
);
647 // ----------------------------------------------------------------------------
649 // ----------------------------------------------------------------------------
651 extern void PixelToHIMETRIC(LONG
*x
, LONG
*y
)
655 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
656 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
657 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
658 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
660 *x
*= (iWidthMM
* 100);
662 *y
*= (iHeightMM
* 100);
666 extern void HIMETRICToPixel(LONG
*x
, LONG
*y
)
670 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
671 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
672 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
673 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
676 *x
/= (iWidthMM
* 100);
678 *y
/= (iHeightMM
* 100);