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") );
189 // DDE hack: this is really not pretty, but we need to allow this for
190 // transparent handling of DDE servers in wxMimeTypesManager. Usually it
191 // returns the command which should be run to view/open/... a file of the
192 // given type. Sometimes, however, this command just launches the server
193 // and an additional DDE request must be made to really open the file. To
194 // keep all this well hidden from the application, we allow a special form
195 // of command: WX_DDE:<command>:DDE_SERVER:DDE_TOPIC:DDE_COMMAND in which
196 // case we execute just <command> and process the rest below
197 wxString command
, ddeServer
, ddeTopic
, ddeCommand
;
198 static const size_t lenDdePrefix
= 7; // strlen("WX_DDE:")
199 if ( cmd
.Left(lenDdePrefix
) == _T("WX_DDE#") )
201 const wxChar
*p
= cmd
.c_str() + 7;
202 while ( *p
&& *p
!= _T('#') )
214 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
217 while ( *p
&& *p
!= _T('#') )
229 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
232 while ( *p
&& *p
!= _T('#') )
244 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
259 #if defined(__WIN32__) && !defined(__TWIN32__)
260 // the old code is disabled because we really need a process handle
261 // if we want to execute it asynchronously or even just get its
262 // return code and for this we must use CreateProcess() and not
265 // isolate command and arguments
266 wxString commandName
;
267 bool insideQuotes
= FALSE
;
269 for ( pc
= command
.c_str(); *pc
!= '\0'; pc
++ )
280 insideQuotes
= !insideQuotes
;
285 continue; // skip the next break
288 // only reached for space not inside quotes
292 wxString commandArgs
= pc
;
294 wxWindow
*winTop
= wxTheApp
->GetTopWindow();
295 HWND hwndTop
= (HWND
)(winTop
? winTop
->GetHWND() : 0);
299 result
= ShellExecute(hwndTop
,
300 (const wchar_t)"open",
301 (const wchar_t)commandName
,
302 (const wchar_t)commandArgs
,
306 result
= ShellExecute(hwndTop
, "open", commandName
,
307 commandArgs
, NULL
, SW_SHOWNORMAL
);
310 if ( ((long)result
) <= 32 )
311 wxLogSysError(_("Can't execute command '%s'"), command
.c_str());
316 // create the process
322 PROCESS_INFORMATION pi
;
324 if ( ::CreateProcess(
325 NULL
, // application name (use only cmd line)
326 (wxChar
*)command
.c_str(), // full command line
327 NULL
, // security attributes: defaults for both
328 NULL
, // the process and its main thread
329 FALSE
, // don't inherit handles
330 CREATE_DEFAULT_ERROR_MODE
|
331 CREATE_SUSPENDED
, // flags
332 NULL
, // environment (use the same)
333 NULL
, // current directory (use the same)
334 &si
, // startup info (unused here)
338 wxLogSysError(_("Execution of command '%s' failed"), command
.c_str());
343 // register the class for the hidden window used for the notifications
344 if ( !gs_classForHiddenWindow
)
346 gs_classForHiddenWindow
= _T("wxHiddenWindow");
349 wxZeroMemory(wndclass
);
350 wndclass
.lpfnWndProc
= (WNDPROC
)wxExecuteWindowCbk
;
351 wndclass
.hInstance
= wxGetInstance();
352 wndclass
.lpszClassName
= gs_classForHiddenWindow
;
354 if ( !::RegisterClass(&wndclass
) )
356 wxLogLastError("RegisterClass(hidden window)");
360 // create a hidden window to receive notification about process
362 HWND hwnd
= ::CreateWindow(gs_classForHiddenWindow
, NULL
,
365 (HMENU
)NULL
, wxGetInstance(), 0);
366 wxASSERT_MSG( hwnd
, wxT("can't create a hidden window for wxExecute") );
369 wxExecuteData
*data
= new wxExecuteData
;
370 data
->hProcess
= pi
.hProcess
;
371 data
->dwProcessId
= pi
.dwProcessId
;
376 wxASSERT_MSG( !handler
, wxT("wxProcess param ignored for sync execution") );
378 data
->handler
= NULL
;
382 // may be NULL or not
383 data
->handler
= handler
;
387 HANDLE hThread
= ::CreateThread(NULL
,
389 (LPTHREAD_START_ROUTINE
)wxExecuteThread
,
394 // resume process we created now - whether the thread creation succeeded or
396 if ( ::ResumeThread(pi
.hThread
) == (DWORD
)-1 )
398 // ignore it - what can we do?
399 wxLogLastError("ResumeThread in wxExecute");
402 // close unneeded handle
403 if ( !::CloseHandle(pi
.hThread
) )
404 wxLogLastError("CloseHandle(hThread)");
408 wxLogLastError("CreateThread in wxExecute");
413 // the process still started up successfully...
414 return pi
.dwProcessId
;
418 // second part of DDE hack: now establish the DDE conversation with the
419 // just launched process
423 wxConnectionBase
*conn
= client
.MakeConnection(_T(""),
426 if ( !conn
|| !conn
->Execute(ddeCommand
) )
428 wxLogError(_("Couldn't launch DDE server '%s'."), command
.c_str());
435 // clean up will be done when the process terminates
438 return pi
.dwProcessId
;
441 // waiting until command executed (disable everything while doing it)
444 wxEnableTopLevelWindows(FALSE
);
447 while ( data
->state
)
451 wxEnableTopLevelWindows(TRUE
);
455 DWORD dwExitCode
= data
->dwExitCode
;
458 // return the exit code
462 long instanceID
= WinExec((LPCSTR
) WXSTRINGCAST command
, SW_SHOW
);
463 if (instanceID
< 32) return(0);
469 running
= GetModuleUsage((HINSTANCE
)instanceID
);
477 long wxExecute(char **argv
, bool sync
, wxProcess
*handler
)
481 while ( *argv
!= NULL
)
483 command
<< *argv
++ << ' ';
486 command
.RemoveLast();
488 return wxExecute(command
, sync
, handler
);
491 // ----------------------------------------------------------------------------
493 // ----------------------------------------------------------------------------
495 extern void PixelToHIMETRIC(LONG
*x
, LONG
*y
)
499 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
500 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
501 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
502 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
504 *x
*= (iWidthMM
* 100);
506 *y
*= (iHeightMM
* 100);
510 extern void HIMETRICToPixel(LONG
*x
, LONG
*y
)
514 int iWidthMM
= GetDeviceCaps(hdcRef
, HORZSIZE
),
515 iHeightMM
= GetDeviceCaps(hdcRef
, VERTSIZE
),
516 iWidthPels
= GetDeviceCaps(hdcRef
, HORZRES
),
517 iHeightPels
= GetDeviceCaps(hdcRef
, VERTRES
);
520 *x
/= (iWidthMM
* 100);
522 *y
/= (iHeightMM
* 100);