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 // ------------------------------------
413 // We are in the case of opening a pipe
414 inheritHandles
= FALSE
;
415 if (handler
&& handler
->NeedPipe()) {
416 SECURITY_ATTRIBUTES security
;
418 security
.nLength
= sizeof(security
);
419 security
.lpSecurityDescriptor
= NULL
;
420 security
.bInheritHandle
= TRUE
;
422 if (! ::CreatePipe(&h_readPipe
[0], &h_readPipe
[1], &security
, 0) ) {
423 wxLogSysError(_T("Can't create the inter-process read pipe"));
428 if (! ::CreatePipe(&h_writePipe
[0], &h_writePipe
[1], &security
, 0) ) {
429 wxLogSysError(_T("Can't create the inter-process read pipe"));
434 // We need to save the old stdio handles to restore them after the call
436 h_oldreadPipe
= GetStdHandle(STD_INPUT_HANDLE
);
437 h_oldwritePipe
= GetStdHandle(STD_OUTPUT_HANDLE
);
439 SetStdHandle(STD_INPUT_HANDLE
, h_readPipe
[0]);
440 SetStdHandle(STD_OUTPUT_HANDLE
, h_writePipe
[1]);
442 inheritHandles
= TRUE
;
445 // create the process
451 PROCESS_INFORMATION pi
;
453 if ( ::CreateProcess(
454 NULL
, // application name (use only cmd line)
455 (wxChar
*)command
.c_str(), // full command line
456 NULL
, // security attributes: defaults for both
457 NULL
, // the process and its main thread
458 inheritHandles
, // don't inherit handles
459 CREATE_DEFAULT_ERROR_MODE
|
460 CREATE_SUSPENDED
, // flags
461 NULL
, // environment (use the same)
462 NULL
, // current directory (use the same)
463 &si
, // startup info (unused here)
467 if (inheritHandles
) {
468 ::CloseHandle(h_writePipe
[0]);
469 ::CloseHandle(h_writePipe
[1]);
470 ::CloseHandle(h_readPipe
[0]);
471 ::CloseHandle(h_readPipe
[1]);
473 wxLogSysError(_("Execution of command '%s' failed"), command
.c_str());
478 // Restore the old stdio handles
479 if (inheritHandles
) {
480 SetStdHandle(STD_INPUT_HANDLE
, h_oldreadPipe
);
481 SetStdHandle(STD_OUTPUT_HANDLE
, h_oldwritePipe
);
483 ::CloseHandle(h_writePipe
[1]);
484 ::CloseHandle(h_readPipe
[0]);
485 // We can now initialize the wxStreams
486 wxInputStream
*processOutput
= new wxPipeInputStream(h_writePipe
[0]);
487 wxOutputStream
*processInput
= new wxPipeOutputStream(h_readPipe
[1]);
489 handler
->SetPipeStreams(processOutput
, processInput
);
492 // register the class for the hidden window used for the notifications
493 if ( !gs_classForHiddenWindow
)
495 gs_classForHiddenWindow
= _T("wxHiddenWindow");
498 wxZeroMemory(wndclass
);
499 wndclass
.lpfnWndProc
= (WNDPROC
)wxExecuteWindowCbk
;
500 wndclass
.hInstance
= wxGetInstance();
501 wndclass
.lpszClassName
= gs_classForHiddenWindow
;
503 if ( !::RegisterClass(&wndclass
) )
505 wxLogLastError("RegisterClass(hidden window)");
509 // create a hidden window to receive notification about process
511 HWND hwnd
= ::CreateWindow(gs_classForHiddenWindow
, NULL
,
514 (HMENU
)NULL
, wxGetInstance(), 0);
515 wxASSERT_MSG( hwnd
, wxT("can't create a hidden window for wxExecute") );
518 wxExecuteData
*data
= new wxExecuteData
;
519 data
->hProcess
= pi
.hProcess
;
520 data
->dwProcessId
= pi
.dwProcessId
;
525 wxASSERT_MSG( !handler
, wxT("wxProcess param ignored for sync execution") );
527 data
->handler
= NULL
;
531 // may be NULL or not
532 data
->handler
= handler
;
536 HANDLE hThread
= ::CreateThread(NULL
,
538 (LPTHREAD_START_ROUTINE
)wxExecuteThread
,
543 // resume process we created now - whether the thread creation succeeded or
545 if ( ::ResumeThread(pi
.hThread
) == (DWORD
)-1 )
547 // ignore it - what can we do?
548 wxLogLastError("ResumeThread in wxExecute");
551 // close unneeded handle
552 if ( !::CloseHandle(pi
.hThread
) )
553 wxLogLastError("CloseHandle(hThread)");
557 wxLogLastError("CreateThread in wxExecute");
562 // the process still started up successfully...
563 return pi
.dwProcessId
;
567 // second part of DDE hack: now establish the DDE conversation with the
568 // just launched process
572 wxConnectionBase
*conn
= client
.MakeConnection(_T(""),
575 if ( !conn
|| !conn
->Execute(ddeCommand
) )
577 wxLogError(_("Couldn't launch DDE server '%s'."), command
.c_str());
584 // clean up will be done when the process terminates
587 return pi
.dwProcessId
;
590 // waiting until command executed (disable everything while doing it)
593 wxEnableTopLevelWindows(FALSE
);
596 while ( data
->state
)
600 wxEnableTopLevelWindows(TRUE
);
604 DWORD dwExitCode
= data
->dwExitCode
;
607 // return the exit code
611 long instanceID
= WinExec((LPCSTR
) WXSTRINGCAST command
, SW_SHOW
);
612 if (instanceID
< 32) return(0);
618 running
= GetModuleUsage((HINSTANCE
)instanceID
);
626 long wxExecute(char **argv
, bool sync
, wxProcess
*handler
)
630 while ( *argv
!= NULL
)
632 command
<< *argv
++ << ' ';
635 command
.RemoveLast();
637 return wxExecute(command
, sync
, handler
);
640 // ----------------------------------------------------------------------------
642 // ----------------------------------------------------------------------------
644 extern void PixelToHIMETRIC(LONG
*x
, LONG
*y
)
648 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
649 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
650 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
651 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
653 *x
*= (iWidthMM
* 100);
655 *y
*= (iHeightMM
* 100);
659 extern void HIMETRICToPixel(LONG
*x
, LONG
*y
)
663 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
664 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
665 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
666 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
669 *x
/= (iWidthMM
* 100);
671 *y
/= (iHeightMM
* 100);