0022484: UNICODE characters support
[occt.git] / src / OSD / OSD_signal_WNT.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <OSD.ixx>
15
16 #ifdef _WIN32
17
18 //---------------------------- Windows NT System --------------------------------
19
20 #define STRICT
21 #ifdef NOUSER
22 #undef NOUSER
23 #endif
24 #include <windows.h>
25
26 #include <OSD_Exception_ACCESS_VIOLATION.hxx>
27 #include <OSD_Exception_ARRAY_BOUNDS_EXCEEDED.hxx>
28 #include <OSD_Exception_ILLEGAL_INSTRUCTION.hxx>
29 #include <OSD_Exception_IN_PAGE_ERROR.hxx>
30 #include <OSD_Exception_INT_DIVIDE_BY_ZERO.hxx>
31 #include <OSD_Exception_INT_OVERFLOW.hxx>
32 #include <OSD_Exception_INVALID_DISPOSITION.hxx>
33 #include <OSD_Exception_NONCONTINUABLE_EXCEPTION.hxx>
34 #include <OSD_Exception_PRIV_INSTRUCTION.hxx>
35 #include <OSD_Exception_STACK_OVERFLOW.hxx>
36 #include <OSD_Exception_STATUS_NO_MEMORY.hxx>
37 #include <OSD_Exception_CTRL_BREAK.hxx>
38
39 #include <OSD_Environment.hxx>
40 #include <Standard_Underflow.hxx>
41 #include <Standard_DivideByZero.hxx>
42 #include <Standard_Overflow.hxx>
43 #include <Standard_ProgramError.hxx>
44 #include <Standard_Mutex.hxx>
45
46 #include <OSD_WNT_1.hxx>
47
48 #ifdef _MSC_VER
49 #include <eh.h>
50 #include <malloc.h>
51 #endif
52
53 #include <process.h>
54 #include <signal.h>
55 #include <float.h>
56
57 static Standard_Boolean fMsgBox;
58 static Standard_Boolean fFltExceptions;
59 static Standard_Boolean fDbgLoaded;
60 static Standard_Boolean fCtrlBrk;
61
62 // used to forbid simultaneous execution of setting / executing handlers
63 static Standard_Mutex THE_SIGNAL_MUTEX;
64
65 static LONG __fastcall _osd_raise ( DWORD, LPSTR );
66 static BOOL WINAPI     _osd_ctrl_break_handler ( DWORD );
67
68 static LONG _osd_debug   ( void );
69
70 //# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW )
71 # define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW )
72
73 //=======================================================================
74 //function : CallHandler
75 //purpose  :
76 //=======================================================================
77 static LONG CallHandler (DWORD dwExceptionCode,
78                          ptrdiff_t ExceptionInformation1,
79                          ptrdiff_t ExceptionInformation0)
80 {
81
82 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
83
84  Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
85  static char          buffer[ 2048 ];
86  int                  flterr = 0;
87
88  buffer[0] = '\0' ;
89
90 // cout << "CallHandler " << dwExceptionCode << endl ;
91  switch ( dwExceptionCode ) {
92  
93   case EXCEPTION_FLT_DENORMAL_OPERAND:
94 //      cout << "CallHandler : EXCEPTION_FLT_DENORMAL_OPERAND:" << endl ;
95       lstrcpyA (  buffer, "FLT DENORMAL OPERAND"  );
96       flterr = 1 ;
97       break ;
98   case EXCEPTION_FLT_DIVIDE_BY_ZERO:
99 //      cout << "CallHandler : EXCEPTION_FLT_DIVIDE_BY_ZERO:" << endl ;
100       lstrcpyA (  buffer, "FLT DIVIDE BY ZERO"  );
101       flterr = 1 ;
102       break ;
103   case EXCEPTION_FLT_INEXACT_RESULT:
104 //      cout << "CallHandler : EXCEPTION_FLT_INEXACT_RESULT:" << endl ;
105       lstrcpyA (  buffer, "FLT INEXACT RESULT"  );
106       flterr = 1 ;
107       break ;
108   case EXCEPTION_FLT_INVALID_OPERATION:
109 //      cout << "CallHandler : EXCEPTION_FLT_INVALID_OPERATION:" << endl ;
110       lstrcpyA (  buffer, "FLT INVALID OPERATION"  );
111       flterr = 1 ;
112       break ;
113   case EXCEPTION_FLT_OVERFLOW:
114 //      cout << "CallHandler : EXCEPTION_FLT_OVERFLOW:" << endl ;
115       lstrcpyA (  buffer, "FLT OVERFLOW"  );
116       flterr = 1 ;
117       break ;
118   case EXCEPTION_FLT_STACK_CHECK:
119 //      cout << "CallHandler : EXCEPTION_FLT_STACK_CHECK:" << endl ;
120       lstrcpyA (  buffer, "FLT STACK CHECK"  );
121       flterr = 1 ;
122       break ;
123   case EXCEPTION_FLT_UNDERFLOW:
124 //      cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
125       lstrcpyA (  buffer, "FLT UNDERFLOW"  );
126       flterr = 1 ;
127       break ;
128   case STATUS_FLOAT_MULTIPLE_TRAPS:
129 //      cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
130       lstrcpyA (  buffer, "FLT MULTIPLE TRAPS (possible overflow in conversion of double to integer)"  );
131       flterr = 1 ;
132       break ;
133   case STATUS_FLOAT_MULTIPLE_FAULTS:
134 //      cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
135       lstrcpyA (  buffer, "FLT MULTIPLE FAULTS"  );
136       flterr = 1 ;
137       break ;
138
139   case STATUS_NO_MEMORY:
140 //      cout << "CallHandler : STATUS_NO_MEMORY:" << endl ;
141       OSD_Exception_STATUS_NO_MEMORY ::
142       Raise (  "MEMORY ALLOCATION ERROR ( no room in the process heap )"  );
143
144   case EXCEPTION_ACCESS_VIOLATION:
145 //      cout << "CallHandler : EXCEPTION_ACCESS_VIOLATION:" << endl ;
146       wsprintf ( buffer, "%s%s%s0x%.8p%s%s%s", "ACCESS VIOLATION",
147                  fMsgBox ? "\n" : " ", "at address ",
148                  ExceptionInformation1 ,
149                  " during '",
150                  ExceptionInformation0 ? "WRITE" : "READ",
151                  "' operation");
152   break;
153
154   case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
155 //      cout << "CallHandler : EXCEPTION_ARRAY_BOUNDS_EXCEEDED:" << endl ;
156       lstrcpyA (  buffer, "ARRAY BOUNDS EXCEEDED"  );
157   break;
158
159   case EXCEPTION_DATATYPE_MISALIGNMENT:
160 //      cout << "CallHandler : EXCEPTION_DATATYPE_MISALIGNMENT:" << endl ;
161       lstrcpyA (  buffer, "DATATYPE MISALIGNMENT"  );
162   break;
163
164   case EXCEPTION_ILLEGAL_INSTRUCTION:
165 //      cout << "CallHandler : EXCEPTION_ILLEGAL_INSTRUCTION:" << endl ;
166       lstrcpyA (  buffer, "ILLEGAL INSTRUCTION"  );
167   break;
168
169   case EXCEPTION_IN_PAGE_ERROR:
170 //      cout << "CallHandler : EXCEPTION_IN_PAGE_ERROR:" << endl ;
171       lstrcpyA (  buffer, "IN_PAGE ERROR"  );
172   break;
173
174   case EXCEPTION_INT_DIVIDE_BY_ZERO:
175 //      cout << "CallHandler : EXCEPTION_INT_DIVIDE_BY_ZERO:" << endl ;
176       lstrcpyA (  buffer, "INTEGER DIVISION BY ZERO"  );
177   break;
178
179   case EXCEPTION_INT_OVERFLOW:
180 //      cout << "CallHandler : EXCEPTION_INT_OVERFLOW:" << endl ;
181       lstrcpyA (  buffer, "INTEGER OVERFLOW"  );
182   break;
183
184   case EXCEPTION_INVALID_DISPOSITION:
185 //      cout << "CallHandler : EXCEPTION_INVALID_DISPOSITION:" << endl ;
186       lstrcpyA (  buffer, "INVALID DISPOSITION"  );
187   break;
188
189   case EXCEPTION_NONCONTINUABLE_EXCEPTION:
190 //      cout << "CallHandler : EXCEPTION_NONCONTINUABLE_EXCEPTION:" << endl ;
191       lstrcpyA (  buffer, "NONCONTINUABLE EXCEPTION"  );
192   break;
193
194   case EXCEPTION_PRIV_INSTRUCTION:
195 //      cout << "CallHandler : EXCEPTION_PRIV_INSTRUCTION:" << endl ;
196       lstrcpyA (  buffer, "PRIVELEGED INSTRUCTION ENCOUNTERED"  );
197   break;
198
199   case EXCEPTION_STACK_OVERFLOW:
200 //      cout << "CallHandler : EXCEPTION_STACK_OVERFLOW:" << endl ;
201 #if defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
202     // try recovering from stack overflow: available in MS VC++ 7.0
203     if (!_resetstkoflw())
204       lstrcpyA (  buffer, "Unrecoverable STACK OVERFLOW"  );
205     else
206 #endif
207       lstrcpyA (  buffer, "STACK OVERFLOW"  );
208   break;
209  
210   default:
211     wsprintf( buffer, "unknown exception code 0x%x, params 0x%p 0x%p",
212               dwExceptionCode, ExceptionInformation1, ExceptionInformation0 );
213
214  }  // end switch
215
216  // provide message to the user with possibility to stop
217  int idx = lstrlenA ( buffer );
218  if ( idx && fMsgBox && dwExceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION ) {
219      // reset FP operations before message box, otherwise it may fail to show up
220     _fpreset();
221     _clearfp();
222
223     MessageBeep ( MB_ICONHAND );
224     int aChoice = ::MessageBox (0, buffer, "OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
225     if (aChoice == IDRETRY)
226     {
227       _osd_debug();
228       DebugBreak();
229     } 
230     else if (aChoice == IDABORT)
231       exit(0xFFFF);
232  }
233
234  // reset FPE state
235  if ( flterr ) {
236    if ( !fFltExceptions )
237      return EXCEPTION_EXECUTE_HANDLER;
238    _fpreset () ;
239    _clearfp() ;
240    _controlfp ( 0, _OSD_FPX ) ;          // JR add :
241 //     cout << "OSD::WntHandler _controlfp( 0, _OSD_FPX ) " << hex << _controlfp(0,0) << dec << endl ;
242  }
243  return _osd_raise ( dwExceptionCode, buffer );
244 #else
245  return 0;
246 #endif
247 }
248
249 //=======================================================================
250 //function : SIGWntHandler
251 //purpose  : Will only be used if user calls ::raise() function with
252 //           signal type set in OSD::SetSignal() - SIGSEGV, SIGFPE, SIGILL
253 //           (the latter will likely be removed in the future)
254 //=======================================================================
255 static void SIGWntHandler (int signum, int sub_code)
256 {
257 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
258     Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
259     switch( signum ) {
260     case SIGFPE :
261       if ( signal( signum , (void(*)(int))SIGWntHandler ) == SIG_ERR )
262           cout << "signal error" << endl ;
263       switch( sub_code ) {
264       case _FPE_INVALID :
265         CallHandler( EXCEPTION_FLT_INVALID_OPERATION ,0,0) ;
266         break ;
267       case _FPE_DENORMAL :
268         CallHandler( EXCEPTION_FLT_DENORMAL_OPERAND ,0,0) ;
269         break ;
270       case _FPE_ZERODIVIDE :
271         CallHandler( EXCEPTION_FLT_DIVIDE_BY_ZERO ,0,0) ;
272         break ;
273       case _FPE_OVERFLOW :
274         CallHandler( EXCEPTION_FLT_OVERFLOW ,0,0) ;
275         break ;
276       case _FPE_UNDERFLOW :
277         CallHandler( EXCEPTION_FLT_UNDERFLOW ,0,0) ;
278         break ;
279       case _FPE_INEXACT :
280         CallHandler( EXCEPTION_FLT_INEXACT_RESULT ,0,0) ;
281         break ;
282       default:
283         cout << "SIGWntHandler(default) -> Standard_NumericError::Raise(\"Floating Point Error\");" << endl;
284         Standard_NumericError::Raise("Floating Point Error");
285         break ;
286       }
287       break ;
288     case SIGSEGV :
289       if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
290         cout << "signal error" << endl ;
291       CallHandler( EXCEPTION_ACCESS_VIOLATION ,0,0) ;
292       break ;
293     case SIGILL :
294       if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
295         cout << "signal error" << endl ;
296       CallHandler( EXCEPTION_ILLEGAL_INSTRUCTION ,0,0) ;
297       break ;
298     default:
299       cout << "SIGWntHandler unexpected signal : " << signum << endl ;
300       break ;
301     }
302  DebugBreak ();
303 #endif
304 }
305
306 //=======================================================================
307 //function : TranslateSE
308 //purpose  : Translate Structural Exceptions into C++ exceptions
309 //           Will be used when user's code is compiled with /EHa option
310 //=======================================================================
311 #ifdef _MSC_VER
312
313 // If this file compiled with the default MSVC options for exception
314 // handling (/GX or /EHsc) then the following warning is issued:
315 //   warning C4535: calling _set_se_translator() requires /EHa
316 // However it is correctly inserted and used when user's code compiled with /EHa.
317 // So, here we disable the warning.
318 #pragma warning (disable:4535)
319
320 static void TranslateSE( unsigned int theCode, EXCEPTION_POINTERS* theExcPtr )
321 {
322   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
323   ptrdiff_t info1 = 0, info0 = 0;
324   if ( theExcPtr ) {
325     info1 = theExcPtr->ExceptionRecord->ExceptionInformation[1];
326     info0 = theExcPtr->ExceptionRecord->ExceptionInformation[0];
327   }
328   CallHandler(theCode, info1, info0);
329 }
330 #endif
331 //=======================================================================
332 //function : WntHandler
333 //purpose  : Will be used when user's code is compiled with /EHs
334 //           option and unless user sets his own exception handler with
335 //           ::SetUnhandledExceptionFilter().
336 //=======================================================================
337 static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
338 {
339   DWORD                dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
340
341   return CallHandler (dwExceptionCode,
342                       lpXP->ExceptionRecord->ExceptionInformation[1],
343                       lpXP->ExceptionRecord->ExceptionInformation[0]);
344 }
345 //=======================================================================
346 //function : SetSignal
347 //purpose  :
348 //=======================================================================
349 void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
350 {
351 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
352   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
353   LPTOP_LEVEL_EXCEPTION_FILTER aPreviousFilter;
354
355   OSD_Environment env (TEXT("CSF_DEBUG_MODE"));
356   TCollection_AsciiString val = env.Value();
357   if (!env.Failed())
358   {
359     cout << "Environment variable CSF_DEBUG_MODE setted.\n";
360     fMsgBox = Standard_True;
361   }
362   else
363   {
364     fMsgBox = Standard_False;
365   }
366
367   // Set exception handler (ignored when running under debugger). It will be used in most cases
368   // when user's code is compiled with /EHs
369   // Replaces the existing top-level exception filter for all existing and all future threads
370   // in the calling process
371   aPreviousFilter = ::SetUnhandledExceptionFilter (/*(LPTOP_LEVEL_EXCEPTION_FILTER)*/ WntHandler);
372
373   // Signal handlers will only be used when the method ::raise() will be used
374   // Handlers must be set for every thread
375   if (signal (SIGSEGV, (void(*)(int))SIGWntHandler) == SIG_ERR)
376     cout << "signal(OSD::SetSignal) error\n";
377   if (signal (SIGFPE,  (void(*)(int))SIGWntHandler) == SIG_ERR)
378     cout << "signal(OSD::SetSignal) error\n";
379   if (signal (SIGILL,  (void(*)(int))SIGWntHandler) == SIG_ERR)
380     cout << "signal(OSD::SetSignal) error\n";
381
382   // Set Ctrl-C and Ctrl-Break handler
383   fCtrlBrk = Standard_False;
384   SetConsoleCtrlHandler (&_osd_ctrl_break_handler, TRUE);
385
386 #ifdef _MSC_VER
387 //  _se_translator_function pOldSeFunc = 
388     _set_se_translator (TranslateSE);
389 #endif
390
391   fFltExceptions = theFloatingSignal;
392   if (theFloatingSignal)
393   {
394     _controlfp (0, _OSD_FPX);        // JR add :
395   }
396   else {
397     _controlfp (_OSD_FPX, _OSD_FPX); // JR add :
398   }
399 #endif
400 }  // end OSD :: SetSignal
401
402 //============================================================================
403 //==== ControlBreak 
404 //============================================================================
405
406 void OSD :: ControlBreak () {
407
408  if ( fCtrlBrk ) {
409  
410   fCtrlBrk = Standard_False;
411   OSD_Exception_CTRL_BREAK :: Raise (  TEXT( "*** INTERRUPT ***" )  );
412  
413  }  // end if
414
415 }  // end OSD :: ControlBreak
416
417 //============================================================================
418 //==== _osd_ctrl_break_handler 
419 //============================================================================
420
421 static BOOL WINAPI _osd_ctrl_break_handler ( DWORD dwCode ) {
422
423  if ( dwCode == CTRL_C_EVENT || dwCode == CTRL_BREAK_EVENT ) {
424
425   MessageBeep ( MB_ICONEXCLAMATION );
426   fCtrlBrk = Standard_True;
427
428  } else
429
430   exit ( 254 );
431
432  return TRUE;
433
434 }  // end _osd_ctrl_break_handler
435
436 //============================================================================
437 //==== _osd_raise 
438 //============================================================================
439
440 static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg ) 
441 {
442   if (msg[0] == '\x03') ++msg;
443
444   switch (dwCode)
445   {
446     case EXCEPTION_ACCESS_VIOLATION:
447       OSD_Exception_ACCESS_VIOLATION::Raise (msg);
448       break;
449     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
450       OSD_Exception_ARRAY_BOUNDS_EXCEEDED::Raise (msg);
451       break;
452     case EXCEPTION_DATATYPE_MISALIGNMENT:
453       Standard_ProgramError::Raise (msg);
454       break;
455     case EXCEPTION_ILLEGAL_INSTRUCTION:
456       OSD_Exception_ILLEGAL_INSTRUCTION::Raise (msg);
457       break;
458     case EXCEPTION_IN_PAGE_ERROR:
459       OSD_Exception_IN_PAGE_ERROR::Raise (msg);
460       break;
461     case EXCEPTION_INT_DIVIDE_BY_ZERO:
462       Standard_DivideByZero::Raise (msg);
463       break;
464     case EXCEPTION_INT_OVERFLOW:
465       OSD_Exception_INT_OVERFLOW::Raise (msg);
466       break;
467     case EXCEPTION_INVALID_DISPOSITION:
468       OSD_Exception_INVALID_DISPOSITION::Raise (msg);
469       break;
470     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
471       OSD_Exception_NONCONTINUABLE_EXCEPTION::Raise (msg);
472       break;
473     case EXCEPTION_PRIV_INSTRUCTION:
474       OSD_Exception_PRIV_INSTRUCTION::Raise (msg);
475       break;
476     case EXCEPTION_STACK_OVERFLOW:
477       OSD_Exception_STACK_OVERFLOW::Raise (msg);
478       break;
479     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
480       Standard_DivideByZero::Raise (msg);
481       break;
482     case EXCEPTION_FLT_STACK_CHECK:
483     case EXCEPTION_FLT_OVERFLOW:
484       Standard_Overflow::Raise (msg);
485       break;
486     case EXCEPTION_FLT_UNDERFLOW:
487       Standard_Underflow::Raise (msg);
488       break;
489     case EXCEPTION_FLT_INVALID_OPERATION:
490     case EXCEPTION_FLT_DENORMAL_OPERAND:
491     case EXCEPTION_FLT_INEXACT_RESULT:
492     case STATUS_FLOAT_MULTIPLE_TRAPS:
493     case STATUS_FLOAT_MULTIPLE_FAULTS:
494       Standard_NumericError::Raise (msg);
495       break;
496     default:
497       break;
498   }  // end switch
499   return EXCEPTION_EXECUTE_HANDLER;
500 }  // end _osd_raise
501
502 //============================================================================
503 //==== _osd_debug 
504 //============================================================================
505
506 #if defined(__CYGWIN32__) || defined(__MINGW32__)
507 #define __try
508 #define __finally
509 #define __leave return 0
510 #endif
511
512 LONG _osd_debug ( void ) {
513
514  LONG action ;
515
516  if ( !fDbgLoaded ) {
517  
518   HKEY                hKey = NULL;
519   HANDLE              hEvent = INVALID_HANDLE_VALUE;
520   DWORD               dwKeyType;
521   DWORD               dwValueLen;
522   TCHAR               keyValue[ MAX_PATH ];
523   TCHAR               cmdLine[ MAX_PATH ];
524   SECURITY_ATTRIBUTES sa;
525   PROCESS_INFORMATION pi;
526   STARTUPINFO         si;
527
528   __try {
529   
530    if (  RegOpenKey (
531           HKEY_LOCAL_MACHINE,
532           TEXT( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" ),
533           &hKey
534          ) != ERROR_SUCCESS
535    ) __leave;
536
537    dwValueLen = sizeof ( keyValue );
538   
539    if (  RegQueryValueEx (
540           hKey, TEXT( "Debugger" ), NULL, &dwKeyType, ( unsigned char* )keyValue, &dwValueLen
541          ) != ERROR_SUCCESS
542    ) __leave;
543
544    sa.nLength              = sizeof ( SECURITY_ATTRIBUTES );
545    sa.lpSecurityDescriptor = NULL;
546    sa.bInheritHandle       = TRUE;
547
548    if (   (  hEvent = CreateEvent ( &sa, TRUE, FALSE, NULL )  ) == NULL   ) __leave;
549
550    wsprintf (  cmdLine, keyValue, GetCurrentProcessId (), hEvent  );
551
552    ZeroMemory (  &si, sizeof ( STARTUPINFO )  );
553
554    si.cb      = sizeof ( STARTUPINFO );
555    si.dwFlags = STARTF_FORCEONFEEDBACK;
556
557 //   cout << "_osd_debug -> CreateProcess" << endl ;
558    if (  !CreateProcess (
559            NULL, cmdLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE,
560            NULL, NULL, &si, &pi
561           )
562    ) __leave;
563
564 //   cout << "_osd_debug -> WaitForSingleObject " << endl ;
565    WaitForSingleObject ( hEvent, INFINITE );
566 //   cout << "_osd_debug <- WaitForSingleObject -> CloseHandle " << endl ;
567
568    CloseHandle ( pi.hProcess );
569    CloseHandle ( pi.hThread  );
570
571 //   cout << "_osd_debug fDbgLoaded  " << endl ;
572    fDbgLoaded = TRUE;
573   
574   }  // end __try
575
576   __finally {
577   
578 //   cout << "_osd_debug -> CloseHandle(hKey) " << endl ;
579    if ( hKey   != INVALID_HANDLE_VALUE ) CloseHandle ( hKey   );
580 //   cout << "_osd_debug -> CloseHandle(hEvent) " << endl ;
581    if ( hEvent != INVALID_HANDLE_VALUE ) CloseHandle ( hEvent );
582 //   cout << "_osd_debug end __finally " << endl ;
583   
584   }  // end __finally
585
586  }  /* end if */
587
588  action = fDbgLoaded ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
589 // cout << "_osd_debug return " << action << " EXCEPTION_CONTINUE_EXECUTION("
590 //      << EXCEPTION_CONTINUE_EXECUTION << ")" << endl ;
591  return action ;
592
593 }  // end _osd_debug
594
595 #if defined(__CYGWIN32__) || defined(__MINGW32__)
596 #undef __try
597 #undef __finally
598 #undef __leave
599 #endif
600 #endif // WNT