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/process.h"
43 #include "wx/msw/private.h"
47 #if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__)
54 #if defined(__GNUWIN32__) && !defined(__TWIN32__)
55 #include <sys/unistd.h>
59 #if defined(__WIN32__) && !defined(__WXWINE__)
71 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
78 #include "wx/dde.h" // for WX_DDE hack in wxExecute
81 // ----------------------------------------------------------------------------
83 // ----------------------------------------------------------------------------
85 // this message is sent when the process we're waiting for terminates
86 #define wxWM_PROC_TERMINATED (WM_USER + 10000)
88 // ----------------------------------------------------------------------------
89 // this module globals
90 // ----------------------------------------------------------------------------
92 // we need to create a hidden window to receive the process termination
93 // notifications and for this we need a (Win) class name for it which we will
94 // register the first time it's needed
95 static const wxChar
*gs_classForHiddenWindow
= NULL
;
97 // ----------------------------------------------------------------------------
99 // ----------------------------------------------------------------------------
101 // structure describing the process we're being waiting for
108 if ( !::CloseHandle(hProcess
) )
110 wxLogLastError("CloseHandle(hProcess)");
115 HWND hWnd
; // window to send wxWM_PROC_TERMINATED to
116 HANDLE hProcess
; // handle of the process
117 DWORD dwProcessId
; // pid of the process
119 DWORD dwExitCode
; // the exit code of the process
120 bool state
; // set to FALSE when the process finishes
123 // ============================================================================
125 // ============================================================================
128 static DWORD
wxExecuteThread(wxExecuteData
*data
)
130 WaitForSingleObject(data
->hProcess
, INFINITE
);
133 if ( !GetExitCodeProcess(data
->hProcess
, &data
->dwExitCode
) )
135 wxLogLastError("GetExitCodeProcess");
138 wxASSERT_MSG( data
->dwExitCode
!= STILL_ACTIVE
,
139 wxT("process should have terminated") );
141 // send a message indicating process termination to the window
142 SendMessage(data
->hWnd
, wxWM_PROC_TERMINATED
, 0, (LPARAM
)data
);
147 // window procedure of a hidden window which is created just to receive
148 // the notification message when a process exits
149 LRESULT APIENTRY _EXPORT
wxExecuteWindowCbk(HWND hWnd
, UINT message
,
150 WPARAM wParam
, LPARAM lParam
)
152 if ( message
== wxWM_PROC_TERMINATED
)
154 DestroyWindow(hWnd
); // we don't need it any more
156 wxExecuteData
*data
= (wxExecuteData
*)lParam
;
159 data
->handler
->OnTerminate((int)data
->dwProcessId
,
160 (int)data
->dwExitCode
);
165 // we're executing synchronously, tell the waiting thread
166 // that the process finished
171 // asynchronous execution - we should do the clean up
179 return DefWindowProc(hWnd
, message
, wParam
, lParam
);
184 long wxExecute(const wxString
& cmd
, bool sync
, wxProcess
*handler
)
186 wxCHECK_MSG( !!cmd
, 0, wxT("empty command in wxExecute") );
190 // DDE hack: this is really not pretty, but we need to allow this for
191 // transparent handling of DDE servers in wxMimeTypesManager. Usually it
192 // returns the command which should be run to view/open/... a file of the
193 // given type. Sometimes, however, this command just launches the server
194 // and an additional DDE request must be made to really open the file. To
195 // keep all this well hidden from the application, we allow a special form
196 // of command: WX_DDE:<command>:DDE_SERVER:DDE_TOPIC:DDE_COMMAND in which
197 // case we execute just <command> and process the rest below
198 wxString ddeServer
, ddeTopic
, ddeCommand
;
199 static const size_t lenDdePrefix
= 7; // strlen("WX_DDE:")
200 if ( cmd
.Left(lenDdePrefix
) == _T("WX_DDE#") )
202 const wxChar
*p
= cmd
.c_str() + 7;
203 while ( *p
&& *p
!= _T('#') )
215 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
218 while ( *p
&& *p
!= _T('#') )
230 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
233 while ( *p
&& *p
!= _T('#') )
245 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
260 #if defined(__WIN32__) && !defined(__TWIN32__)
261 // the old code is disabled because we really need a process handle
262 // if we want to execute it asynchronously or even just get its
263 // return code and for this we must use CreateProcess() and not
266 // isolate command and arguments
267 wxString commandName
;
268 bool insideQuotes
= FALSE
;
270 for ( pc
= command
.c_str(); *pc
!= '\0'; pc
++ )
281 insideQuotes
= !insideQuotes
;
286 continue; // skip the next break
289 // only reached for space not inside quotes
293 wxString commandArgs
= pc
;
295 wxWindow
*winTop
= wxTheApp
->GetTopWindow();
296 HWND hwndTop
= (HWND
)(winTop
? winTop
->GetHWND() : 0);
300 result
= ShellExecute(hwndTop
,
301 (const wchar_t)"open",
302 (const wchar_t)commandName
,
303 (const wchar_t)commandArgs
,
307 result
= ShellExecute(hwndTop
, "open", commandName
,
308 commandArgs
, NULL
, SW_SHOWNORMAL
);
311 if ( ((long)result
) <= 32 )
312 wxLogSysError(_("Can't execute command '%s'"), command
.c_str());
317 // create the process
323 PROCESS_INFORMATION pi
;
325 if ( ::CreateProcess(
326 NULL
, // application name (use only cmd line)
327 (wxChar
*)command
.c_str(), // full command line
328 NULL
, // security attributes: defaults for both
329 NULL
, // the process and its main thread
330 FALSE
, // don't inherit handles
331 CREATE_DEFAULT_ERROR_MODE
|
332 CREATE_SUSPENDED
, // flags
333 NULL
, // environment (use the same)
334 NULL
, // current directory (use the same)
335 &si
, // startup info (unused here)
339 wxLogSysError(_("Execution of command '%s' failed"), command
.c_str());
344 // register the class for the hidden window used for the notifications
345 if ( !gs_classForHiddenWindow
)
347 gs_classForHiddenWindow
= _T("wxHiddenWindow");
350 wxZeroMemory(wndclass
);
351 wndclass
.lpfnWndProc
= (WNDPROC
)wxExecuteWindowCbk
;
352 wndclass
.hInstance
= wxGetInstance();
353 wndclass
.lpszClassName
= gs_classForHiddenWindow
;
355 if ( !::RegisterClass(&wndclass
) )
357 wxLogLastError("RegisterClass(hidden window)");
361 // create a hidden window to receive notification about process
363 HWND hwnd
= ::CreateWindow(gs_classForHiddenWindow
, NULL
,
366 (HMENU
)NULL
, wxGetInstance(), 0);
367 wxASSERT_MSG( hwnd
, wxT("can't create a hidden window for wxExecute") );
370 wxExecuteData
*data
= new wxExecuteData
;
371 data
->hProcess
= pi
.hProcess
;
372 data
->dwProcessId
= pi
.dwProcessId
;
377 wxASSERT_MSG( !handler
, wxT("wxProcess param ignored for sync execution") );
379 data
->handler
= NULL
;
383 // may be NULL or not
384 data
->handler
= handler
;
388 HANDLE hThread
= ::CreateThread(NULL
,
390 (LPTHREAD_START_ROUTINE
)wxExecuteThread
,
395 // resume process we created now - whether the thread creation succeeded or
397 if ( ::ResumeThread(pi
.hThread
) == (DWORD
)-1 )
399 // ignore it - what can we do?
400 wxLogLastError("ResumeThread in wxExecute");
403 // close unneeded handle
404 if ( !::CloseHandle(pi
.hThread
) )
405 wxLogLastError("CloseHandle(hThread)");
409 wxLogLastError("CreateThread in wxExecute");
414 // the process still started up successfully...
415 return pi
.dwProcessId
;
419 // second part of DDE hack: now establish the DDE conversation with the
420 // just launched process
424 wxConnectionBase
*conn
= client
.MakeConnection(_T(""),
427 if ( !conn
|| !conn
->Execute(ddeCommand
) )
429 wxLogError(_("Couldn't launch DDE server '%s'."), command
.c_str());
436 // clean up will be done when the process terminates
439 return pi
.dwProcessId
;
442 // waiting until command executed (disable everything while doing it)
445 wxEnableTopLevelWindows(FALSE
);
448 while ( data
->state
)
452 wxEnableTopLevelWindows(TRUE
);
456 DWORD dwExitCode
= data
->dwExitCode
;
459 // return the exit code
463 long instanceID
= WinExec((LPCSTR
) WXSTRINGCAST command
, SW_SHOW
);
464 if (instanceID
< 32) return(0);
470 running
= GetModuleUsage((HINSTANCE
)instanceID
);
478 long wxExecute(char **argv
, bool sync
, wxProcess
*handler
)
482 while ( *argv
!= NULL
)
484 command
<< *argv
++ << ' ';
487 command
.RemoveLast();
489 return wxExecute(command
, sync
, handler
);
492 // ----------------------------------------------------------------------------
494 // ----------------------------------------------------------------------------
496 extern void PixelToHIMETRIC(LONG
*x
, LONG
*y
)
500 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
501 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
502 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
503 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
505 *x
*= (iWidthMM
* 100);
507 *y
*= (iHeightMM
* 100);
511 extern void HIMETRICToPixel(LONG
*x
, LONG
*y
)
515 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
516 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
517 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
518 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
521 *x
/= (iWidthMM
* 100);
523 *y
/= (iHeightMM
* 100);