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))
77 #include "wx/dde.h" // for WX_DDE hack in wxExecute
79 // ----------------------------------------------------------------------------
81 // ----------------------------------------------------------------------------
83 // this message is sent when the process we're waiting for terminates
84 #define wxWM_PROC_TERMINATED (WM_USER + 10000)
86 // ----------------------------------------------------------------------------
87 // this module globals
88 // ----------------------------------------------------------------------------
90 // we need to create a hidden window to receive the process termination
91 // notifications and for this we need a (Win) class name for it which we will
92 // register the first time it's needed
93 static const wxChar
*gs_classForHiddenWindow
= NULL
;
95 // ----------------------------------------------------------------------------
97 // ----------------------------------------------------------------------------
99 // structure describing the process we're being waiting for
106 if ( !::CloseHandle(hProcess
) )
108 wxLogLastError("CloseHandle(hProcess)");
113 HWND hWnd
; // window to send wxWM_PROC_TERMINATED to
114 HANDLE hProcess
; // handle of the process
115 DWORD dwProcessId
; // pid of the process
117 DWORD dwExitCode
; // the exit code of the process
118 bool state
; // set to FALSE when the process finishes
121 // ============================================================================
123 // ============================================================================
126 static DWORD
wxExecuteThread(wxExecuteData
*data
)
128 WaitForSingleObject(data
->hProcess
, INFINITE
);
131 if ( !GetExitCodeProcess(data
->hProcess
, &data
->dwExitCode
) )
133 wxLogLastError("GetExitCodeProcess");
136 wxASSERT_MSG( data
->dwExitCode
!= STILL_ACTIVE
,
137 wxT("process should have terminated") );
139 // send a message indicating process termination to the window
140 SendMessage(data
->hWnd
, wxWM_PROC_TERMINATED
, 0, (LPARAM
)data
);
145 // window procedure of a hidden window which is created just to receive
146 // the notification message when a process exits
147 LRESULT APIENTRY _EXPORT
wxExecuteWindowCbk(HWND hWnd
, UINT message
,
148 WPARAM wParam
, LPARAM lParam
)
150 if ( message
== wxWM_PROC_TERMINATED
)
152 DestroyWindow(hWnd
); // we don't need it any more
154 wxExecuteData
*data
= (wxExecuteData
*)lParam
;
157 data
->handler
->OnTerminate((int)data
->dwProcessId
,
158 (int)data
->dwExitCode
);
163 // we're executing synchronously, tell the waiting thread
164 // that the process finished
169 // asynchronous execution - we should do the clean up
177 return DefWindowProc(hWnd
, message
, wParam
, lParam
);
182 long wxExecute(const wxString
& cmd
, bool sync
, wxProcess
*handler
)
184 wxCHECK_MSG( !!cmd
, 0, wxT("empty command in wxExecute") );
186 // DDE hack: this is really not pretty, but we need to allow this for
187 // transparent handling of DDE servers in wxMimeTypesManager. Usually it
188 // returns the command which should be run to view/open/... a file of the
189 // given type. Sometimes, however, this command just launches the server
190 // and an additional DDE request must be made to really open the file. To
191 // keep all this well hidden from the application, we allow a special form
192 // of command: WX_DDE:<command>:DDE_SERVER:DDE_TOPIC:DDE_COMMAND in which
193 // case we execute just <command> and process the rest below
194 wxString command
, ddeServer
, ddeTopic
, ddeCommand
;
195 static const size_t lenDdePrefix
= 7; // strlen("WX_DDE:")
196 if ( cmd
.Left(lenDdePrefix
) == _T("WX_DDE#") )
198 const wxChar
*p
= cmd
.c_str() + 7;
199 while ( *p
&& *p
!= _T('#') )
211 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
214 while ( *p
&& *p
!= _T('#') )
226 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
229 while ( *p
&& *p
!= _T('#') )
241 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
255 #if defined(__WIN32__) && !defined(__TWIN32__)
256 // the old code is disabled because we really need a process handle
257 // if we want to execute it asynchronously or even just get its
258 // return code and for this we must use CreateProcess() and not
261 // isolate command and arguments
262 wxString commandName
;
263 bool insideQuotes
= FALSE
;
265 for ( pc
= command
.c_str(); *pc
!= '\0'; pc
++ )
276 insideQuotes
= !insideQuotes
;
281 continue; // skip the next break
284 // only reached for space not inside quotes
288 wxString commandArgs
= pc
;
290 wxWindow
*winTop
= wxTheApp
->GetTopWindow();
291 HWND hwndTop
= (HWND
)(winTop
? winTop
->GetHWND() : 0);
295 result
= ShellExecute(hwndTop
,
296 (const wchar_t)"open",
297 (const wchar_t)commandName
,
298 (const wchar_t)commandArgs
,
302 result
= ShellExecute(hwndTop
, "open", commandName
,
303 commandArgs
, NULL
, SW_SHOWNORMAL
);
306 if ( ((long)result
) <= 32 )
307 wxLogSysError(_("Can't execute command '%s'"), command
.c_str());
312 // create the process
318 PROCESS_INFORMATION pi
;
320 if ( ::CreateProcess(
321 NULL
, // application name (use only cmd line)
322 (wxChar
*)command
.c_str(), // full command line
323 NULL
, // security attributes: defaults for both
324 NULL
, // the process and its main thread
325 FALSE
, // don't inherit handles
326 CREATE_DEFAULT_ERROR_MODE
|
327 CREATE_SUSPENDED
, // flags
328 NULL
, // environment (use the same)
329 NULL
, // current directory (use the same)
330 &si
, // startup info (unused here)
334 wxLogSysError(_("Execution of command '%s' failed"), command
.c_str());
339 // register the class for the hidden window used for the notifications
340 if ( !gs_classForHiddenWindow
)
342 gs_classForHiddenWindow
= _T("wxHiddenWindow");
345 wxZeroMemory(wndclass
);
346 wndclass
.lpfnWndProc
= (WNDPROC
)wxExecuteWindowCbk
;
347 wndclass
.hInstance
= wxGetInstance();
348 wndclass
.lpszClassName
= gs_classForHiddenWindow
;
350 if ( !::RegisterClass(&wndclass
) )
352 wxLogLastError("RegisterClass(hidden window)");
356 // create a hidden window to receive notification about process
358 HWND hwnd
= ::CreateWindow(gs_classForHiddenWindow
, NULL
,
361 (HMENU
)NULL
, wxGetInstance(), 0);
362 wxASSERT_MSG( hwnd
, wxT("can't create a hidden window for wxExecute") );
365 wxExecuteData
*data
= new wxExecuteData
;
366 data
->hProcess
= pi
.hProcess
;
367 data
->dwProcessId
= pi
.dwProcessId
;
372 wxASSERT_MSG( !handler
, wxT("wxProcess param ignored for sync execution") );
374 data
->handler
= NULL
;
378 // may be NULL or not
379 data
->handler
= handler
;
383 HANDLE hThread
= ::CreateThread(NULL
,
385 (LPTHREAD_START_ROUTINE
)wxExecuteThread
,
390 // resume process we created now - whether the thread creation succeeded or
392 if ( ::ResumeThread(pi
.hThread
) == (DWORD
)-1 )
394 // ignore it - what can we do?
395 wxLogLastError("ResumeThread in wxExecute");
398 // close unneeded handle
399 if ( !::CloseHandle(pi
.hThread
) )
400 wxLogLastError("CloseHandle(hThread)");
404 wxLogLastError("CreateThread in wxExecute");
409 // the process still started up successfully...
410 return pi
.dwProcessId
;
413 // second part of DDE hack: now establish the DDE conversation with the
414 // just launched process
418 wxConnectionBase
*conn
= client
.MakeConnection(_T(""),
421 if ( !conn
|| !conn
->Execute(ddeCommand
) )
423 wxLogError(_("Couldn't launch DDE server '%s'."), command
.c_str());
429 // clean up will be done when the process terminates
432 return pi
.dwProcessId
;
435 // waiting until command executed (disable everything while doing it)
438 wxEnableTopLevelWindows(FALSE
);
441 while ( data
->state
)
445 wxEnableTopLevelWindows(TRUE
);
449 DWORD dwExitCode
= data
->dwExitCode
;
452 // return the exit code
456 long instanceID
= WinExec((LPCSTR
) WXSTRINGCAST command
, SW_SHOW
);
457 if (instanceID
< 32) return(0);
463 running
= GetModuleUsage((HINSTANCE
)instanceID
);
471 long wxExecute(char **argv
, bool sync
, wxProcess
*handler
)
475 while ( *argv
!= NULL
)
477 command
<< *argv
++ << ' ';
480 command
.RemoveLast();
482 return wxExecute(command
, sync
, handler
);
485 // ----------------------------------------------------------------------------
487 // ----------------------------------------------------------------------------
489 extern void PixelToHIMETRIC(LONG
*x
, LONG
*y
)
493 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
494 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
495 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
496 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
498 *x
*= (iWidthMM
* 100);
500 *y
*= (iHeightMM
* 100);
504 extern void HIMETRICToPixel(LONG
*x
, LONG
*y
)
508 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
509 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
510 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
511 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
514 *x
/= (iWidthMM
* 100);
516 *y
/= (iHeightMM
* 100);