]> git.saurik.com Git - wxWidgets.git/blame - src/msw/utilsexc.cpp
added default icons for binary and unknown filetype
[wxWidgets.git] / src / msw / utilsexc.cpp
CommitLineData
32592631 1/////////////////////////////////////////////////////////////////////////////
b568d04f 2// Name: msw/utilsexec.cpp
32592631
GL
3// Purpose: Various utilities
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
3f4a0c5b 9// Licence: wxWindows license
32592631
GL
10/////////////////////////////////////////////////////////////////////////////
11
b568d04f
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
32592631 20#ifdef __GNUG__
b568d04f 21 #pragma implementation
32592631
GL
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
b568d04f 28 #pragma hdrstop
32592631
GL
29#endif
30
31#ifndef WX_PRECOMP
b568d04f
VZ
32 #include "wx/utils.h"
33 #include "wx/app.h"
34 #include "wx/intl.h"
32592631
GL
35#endif
36
3e64d4e1 37#include "wx/log.h"
1044a386
JS
38
39#ifdef __WIN32__
b568d04f 40 #include "wx/process.h"
1044a386 41#endif
dbeac4bd 42
32592631 43#include "wx/msw/private.h"
dbeac4bd 44
32592631
GL
45#include <ctype.h>
46
5ea105e0 47#if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__)
b568d04f 48 #include <direct.h>
17dff81c 49#ifndef __MWERKS__
b568d04f 50 #include <dos.h>
32592631 51#endif
17dff81c 52#endif
32592631 53
b568d04f
VZ
54#if defined(__GNUWIN32__) && !defined(__TWIN32__)
55 #include <sys/unistd.h>
56 #include <sys/stat.h>
57c208c5 57#endif
32592631 58
5ea105e0 59#if defined(__WIN32__) && !defined(__WXWINE__)
32592631
GL
60#include <io.h>
61
62#ifndef __GNUWIN32__
63#include <shellapi.h>
64#endif
65#endif
66
67#include <stdio.h>
68#include <stdlib.h>
69#include <string.h>
70#ifndef __WATCOMC__
3f4a0c5b
VZ
71 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
72 #include <errno.h>
73 #endif
32592631
GL
74#endif
75#include <stdarg.h>
76
5bd3a2da
VZ
77#include "wx/dde.h" // for WX_DDE hack in wxExecute
78
b568d04f
VZ
79// ----------------------------------------------------------------------------
80// constants
81// ----------------------------------------------------------------------------
82
cb6827a8
VZ
83// this message is sent when the process we're waiting for terminates
84#define wxWM_PROC_TERMINATED (WM_USER + 10000)
32592631 85
b568d04f
VZ
86// ----------------------------------------------------------------------------
87// this module globals
88// ----------------------------------------------------------------------------
89
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
93static const wxChar *gs_classForHiddenWindow = NULL;
94
95// ----------------------------------------------------------------------------
96// private types
97// ----------------------------------------------------------------------------
98
cb6827a8
VZ
99// structure describing the process we're being waiting for
100struct wxExecuteData
101{
102public:
103 ~wxExecuteData()
104 {
750b78ba 105#ifndef __WIN16__
cb6827a8
VZ
106 if ( !::CloseHandle(hProcess) )
107 {
108 wxLogLastError("CloseHandle(hProcess)");
109 }
750b78ba 110#endif
cb6827a8
VZ
111 }
112
113 HWND hWnd; // window to send wxWM_PROC_TERMINATED to
114 HANDLE hProcess; // handle of the process
115 DWORD dwProcessId; // pid of the process
116 wxProcess *handler;
117 DWORD dwExitCode; // the exit code of the process
118 bool state; // set to FALSE when the process finishes
32592631
GL
119};
120
b568d04f
VZ
121// ============================================================================
122// implementation
123// ============================================================================
5260b1c5
JS
124
125#ifdef __WIN32__
32592631
GL
126static DWORD wxExecuteThread(wxExecuteData *data)
127{
cb6827a8
VZ
128 WaitForSingleObject(data->hProcess, INFINITE);
129
130 // get the exit code
131 if ( !GetExitCodeProcess(data->hProcess, &data->dwExitCode) )
132 {
133 wxLogLastError("GetExitCodeProcess");
134 }
32592631 135
cb6827a8 136 wxASSERT_MSG( data->dwExitCode != STILL_ACTIVE,
223d09f6 137 wxT("process should have terminated") );
32592631 138
cb6827a8
VZ
139 // send a message indicating process termination to the window
140 SendMessage(data->hWnd, wxWM_PROC_TERMINATED, 0, (LPARAM)data);
e6045e08 141
cb6827a8 142 return 0;
32592631 143}
5260b1c5 144
cb6827a8
VZ
145// window procedure of a hidden window which is created just to receive
146// the notification message when a process exits
32592631
GL
147LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message,
148 WPARAM wParam, LPARAM lParam)
149{
cb6827a8
VZ
150 if ( message == wxWM_PROC_TERMINATED )
151 {
152 DestroyWindow(hWnd); // we don't need it any more
153
154 wxExecuteData *data = (wxExecuteData *)lParam;
155 if ( data->handler )
156 {
157 data->handler->OnTerminate((int)data->dwProcessId,
158 (int)data->dwExitCode);
159 }
e6045e08 160
cb6827a8
VZ
161 if ( data->state )
162 {
163 // we're executing synchronously, tell the waiting thread
164 // that the process finished
165 data->state = 0;
166 }
167 else
168 {
169 // asynchronous execution - we should do the clean up
170 delete data;
171 }
cb6827a8 172
0d7ea902
VZ
173 return 0;
174 }
175 else
176 {
177 return DefWindowProc(hWnd, message, wParam, lParam);
178 }
32592631 179}
1044a386 180#endif
32592631 181
5bd3a2da 182long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
32592631 183{
5bd3a2da
VZ
184 wxCHECK_MSG( !!cmd, 0, wxT("empty command in wxExecute") );
185
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#") )
197 {
198 const wxChar *p = cmd.c_str() + 7;
199 while ( *p && *p != _T('#') )
200 {
201 command += *p++;
202 }
203
204 if ( *p )
205 {
206 // skip '#'
207 p++;
208 }
209 else
210 {
211 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
212 }
213
214 while ( *p && *p != _T('#') )
215 {
216 ddeServer += *p++;
217 }
218
219 if ( *p )
220 {
221 // skip '#'
222 p++;
223 }
224 else
225 {
226 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
227 }
228
229 while ( *p && *p != _T('#') )
230 {
231 ddeTopic += *p++;
232 }
233
234 if ( *p )
235 {
236 // skip '#'
237 p++;
238 }
239 else
240 {
241 wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute"));
242 }
243
244 while ( *p )
245 {
246 ddeCommand += *p++;
247 }
248 }
249 else
250 {
251 // no DDE
252 command = cmd;
253 }
32592631 254
57c208c5 255#if defined(__WIN32__) && !defined(__TWIN32__)
cb6827a8
VZ
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
259 // ShellExecute()
260#if 0
261 // isolate command and arguments
262 wxString commandName;
263 bool insideQuotes = FALSE;
264 const char *pc;
265 for ( pc = command.c_str(); *pc != '\0'; pc++ )
266 {
267 switch ( *pc )
268 {
269 case ' ':
270 case '\t':
271 if ( !insideQuotes )
272 break;
273 // fall through
274
275 case '"':
276 insideQuotes = !insideQuotes;
277 // fall through
278
279 default:
280 commandName += *pc;
281 continue; // skip the next break
282 }
283
284 // only reached for space not inside quotes
285 break;
286 }
287
288 wxString commandArgs = pc;
289
290 wxWindow *winTop = wxTheApp->GetTopWindow();
291 HWND hwndTop = (HWND)(winTop ? winTop->GetHWND() : 0);
292
293 HANDLE result;
32592631 294#ifdef __GNUWIN32__
cb6827a8
VZ
295 result = ShellExecute(hwndTop,
296 (const wchar_t)"open",
297 (const wchar_t)commandName,
298 (const wchar_t)commandArgs,
299 (const wchar_t)NULL,
300 SW_SHOWNORMAL);
301#else // !GNUWIN32
302 result = ShellExecute(hwndTop, "open", commandName,
303 commandArgs, NULL, SW_SHOWNORMAL);
304#endif // GNUWIN32
e6045e08 305
cb6827a8
VZ
306 if ( ((long)result) <= 32 )
307 wxLogSysError(_("Can't execute command '%s'"), command.c_str());
308
309 return result;
310#else // 1
5bd3a2da 311
cb6827a8
VZ
312 // create the process
313 STARTUPINFO si;
11c7d5b6 314 wxZeroMemory(si);
cf0b3979 315
cb6827a8
VZ
316 si.cb = sizeof(si);
317
318 PROCESS_INFORMATION pi;
319
320 if ( ::CreateProcess(
321 NULL, // application name (use only cmd line)
837e5743 322 (wxChar *)command.c_str(), // full command line
cb6827a8
VZ
323 NULL, // security attributes: defaults for both
324 NULL, // the process and its main thread
325 FALSE, // don't inherit handles
0d7ea902
VZ
326 CREATE_DEFAULT_ERROR_MODE |
327 CREATE_SUSPENDED, // flags
cb6827a8
VZ
328 NULL, // environment (use the same)
329 NULL, // current directory (use the same)
330 &si, // startup info (unused here)
331 &pi // process info
332 ) == 0 )
333 {
334 wxLogSysError(_("Execution of command '%s' failed"), command.c_str());
335
336 return 0;
337 }
338
0d7ea902 339 // register the class for the hidden window used for the notifications
b568d04f
VZ
340 if ( !gs_classForHiddenWindow )
341 {
342 gs_classForHiddenWindow = _T("wxHiddenWindow");
343
344 WNDCLASS wndclass;
345 wxZeroMemory(wndclass);
346 wndclass.lpfnWndProc = (WNDPROC)wxExecuteWindowCbk;
347 wndclass.hInstance = wxGetInstance();
348 wndclass.lpszClassName = gs_classForHiddenWindow;
349
350 if ( !::RegisterClass(&wndclass) )
351 {
352 wxLogLastError("RegisterClass(hidden window)");
b568d04f
VZ
353 }
354 }
355
cb6827a8
VZ
356 // create a hidden window to receive notification about process
357 // termination
b568d04f 358 HWND hwnd = ::CreateWindow(gs_classForHiddenWindow, NULL,
0d7ea902
VZ
359 WS_OVERLAPPEDWINDOW,
360 0, 0, 0, 0, NULL,
cb6827a8 361 (HMENU)NULL, wxGetInstance(), 0);
223d09f6 362 wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") );
e6045e08 363
cb6827a8
VZ
364 // Alloc data
365 wxExecuteData *data = new wxExecuteData;
366 data->hProcess = pi.hProcess;
367 data->dwProcessId = pi.dwProcessId;
368 data->hWnd = hwnd;
369 data->state = sync;
e6045e08
VZ
370 if ( sync )
371 {
223d09f6 372 wxASSERT_MSG( !handler, wxT("wxProcess param ignored for sync execution") );
e6045e08
VZ
373
374 data->handler = NULL;
375 }
376 else
377 {
378 // may be NULL or not
379 data->handler = handler;
380 }
cb6827a8
VZ
381
382 DWORD tid;
383 HANDLE hThread = ::CreateThread(NULL,
384 0,
385 (LPTHREAD_START_ROUTINE)wxExecuteThread,
386 (void *)data,
387 0,
388 &tid);
389
0d7ea902
VZ
390 // resume process we created now - whether the thread creation succeeded or
391 // not
392 if ( ::ResumeThread(pi.hThread) == (DWORD)-1 )
393 {
394 // ignore it - what can we do?
395 wxLogLastError("ResumeThread in wxExecute");
396 }
397
398 // close unneeded handle
399 if ( !::CloseHandle(pi.hThread) )
400 wxLogLastError("CloseHandle(hThread)");
401
cb6827a8
VZ
402 if ( !hThread )
403 {
404 wxLogLastError("CreateThread in wxExecute");
405
406 DestroyWindow(hwnd);
407 delete data;
408
409 // the process still started up successfully...
410 return pi.dwProcessId;
411 }
e6045e08 412
5bd3a2da
VZ
413 // second part of DDE hack: now establish the DDE conversation with the
414 // just launched process
415 if ( !!ddeServer )
416 {
417 wxDDEClient client;
418 wxConnectionBase *conn = client.MakeConnection(_T(""),
419 ddeServer,
420 ddeTopic);
421 if ( !conn || !conn->Execute(ddeCommand) )
422 {
423 wxLogError(_("Couldn't launch DDE server '%s'."), command.c_str());
424 }
425 }
426
cb6827a8
VZ
427 if ( !sync )
428 {
429 // clean up will be done when the process terminates
e6045e08
VZ
430
431 // return the pid
cb6827a8
VZ
432 return pi.dwProcessId;
433 }
e6045e08 434
0d7ea902
VZ
435 // waiting until command executed (disable everything while doing it)
436#if wxUSE_GUI
437 wxBeginBusyCursor();
438 wxEnableTopLevelWindows(FALSE);
439#endif // wxUSE_GUI
440
cb6827a8
VZ
441 while ( data->state )
442 wxYield();
e6045e08 443
0d7ea902
VZ
444#if wxUSE_GUI
445 wxEnableTopLevelWindows(TRUE);
446 wxEndBusyCursor();
447#endif // wxUSE_GUI
448
e6045e08 449 DWORD dwExitCode = data->dwExitCode;
cb6827a8
VZ
450 delete data;
451
e6045e08
VZ
452 // return the exit code
453 return dwExitCode;
cb6827a8
VZ
454#endif // 0/1
455#else // Win16
456 long instanceID = WinExec((LPCSTR) WXSTRINGCAST command, SW_SHOW);
457 if (instanceID < 32) return(0);
e6045e08 458
cb6827a8
VZ
459 if (sync) {
460 int running;
461 do {
462 wxYield();
27a9bd48 463 running = GetModuleUsage((HINSTANCE)instanceID);
cb6827a8
VZ
464 } while (running);
465 }
466
467 return(instanceID);
468#endif // Win16/32
32592631 469}
c740f496
GL
470
471long wxExecute(char **argv, bool sync, wxProcess *handler)
472{
cb6827a8 473 wxString command;
e6045e08 474
cb6827a8
VZ
475 while ( *argv != NULL )
476 {
477 command << *argv++ << ' ';
478 }
479
480 command.RemoveLast();
481
482 return wxExecute(command, sync, handler);
c740f496 483}
006162a9 484
d9317fd4
VZ
485// ----------------------------------------------------------------------------
486// Metafile helpers
487// ----------------------------------------------------------------------------
488
489extern void PixelToHIMETRIC(LONG *x, LONG *y)
490{
491 ScreenHDC hdcRef;
492
493 int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE),
494 iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE),
495 iWidthPels = GetDeviceCaps(hdcRef, HORZRES),
496 iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
497
498 *x *= (iWidthMM * 100);
499 *x /= iWidthPels;
500 *y *= (iHeightMM * 100);
501 *y /= iHeightPels;
502}
503
504extern void HIMETRICToPixel(LONG *x, LONG *y)
505{
506 ScreenHDC hdcRef;
507
508 int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE),
509 iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE),
510 iWidthPels = GetDeviceCaps(hdcRef, HORZRES),
511 iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
512
513 *x *= iWidthPels;
514 *x /= (iWidthMM * 100);
515 *y *= iHeightPels;
516 *y /= (iHeightMM * 100);
517}