HWND AttemptSetForeground(HWND aTargetWindow, HWND aForeWindow) { BOOL result = SetForegroundWindow(aTargetWindow); HWND new_fore_window = GetForegroundWindow(); Sleep(10); if (new_fore_window == aTargetWindow) { #ifdef _DEBUG_WINACTIVATE if (!result) { FileAppend(LOGF, "SetForegroundWindow() indicated failure even though it succeeded: ", false); FileAppend(LOGF, aTargetTitle); } #endif return aTargetWindow; } if (new_fore_window != aForeWindow && aTargetWindow == GetWindow(new_fore_window, GW_OWNER)) // The window we're trying to get to the foreground is the owner of the new foreground window. // This is considered to be a success because a window that owns other windows can never be // made the foreground window, at least if the windows it owns are visible. return new_fore_window; // Otherwise, failure: #ifdef _DEBUG_WINACTIVATE if (result) { FileAppend(LOGF, "SetForegroundWindow() indicated success even though it failed: ", false); FileAppend(LOGF, aTargetTitle); } #endif return NULL; }
void CCrashHandler::HandleExceptionGlobal ( int iSig ) { MakeSureDirExists ( "dumps/" ); // Collect backtrace information void * buffer [ 100 ]; int iAmount = backtrace ( buffer, sizeof buffer ); char ** symbols = backtrace_symbols ( buffer, iAmount ); // Generate a .log file time_t pTime = time ( NULL ); struct tm * tm = localtime ( &pTime ); SString sFileName; sFileName.Format ( "dumps/server_%s_%04d%02d%02d_%02d%02d.log", MTA_DM_BUILDTYPE, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min ); SString sContent; sContent += SString ( "MTA:SA Server v%s-r%d-%s crash report.\n", MTA_DM_VERSIONSTRING, MTASA_VERSION_BUILD, MTA_DM_BUILDTYPE ); sContent += SString ( "%04d-%02d-%02d %02d:%02d\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min ); sContent += SString ( "Caught %d addresses ...\n\n", iAmount ); sContent += "Backtrace:\n"; for ( int i = 0; i < iAmount; i++ ) { if ( symbols [ i ] ) { sContent += SString ( "#%d - %s\n", i, symbols [ i ] ); } } sContent += std::string( 80, '-' ) + "\n"; // Write the content to the file and close FileAppend( sFileName, sContent ); FileAppend( "dumps/server_pending_upload.log", sContent ); free ( symbols ); // Try to close window gracefully if ( !g_bSilent && !g_bNoCurses && m_wndInput ) { if ( m_wndMenu ) { delwin ( m_wndMenu ); m_wndMenu = NULL; } delwin ( m_wndInput ); m_wndInput = NULL; endwin ( ); } exit ( EXIT_FAILURE ); }
static void SaveBacktraceSummary() { // Collect backtrace information void * buffer [ 100 ]; int iAmount = backtrace ( buffer, sizeof buffer ); iAmount = std::min < int > ( iAmount, NUMELMS( buffer ) ); char ** symbols = backtrace_symbols ( buffer, iAmount ); // Generate a .log file time_t pTime = time ( NULL ); struct tm * tm = localtime ( &pTime ); SString sFileName; sFileName.Format ( "server_%s_%04d%02d%02d_%02d%02d.log", MTA_DM_BUILDTYPE, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min ); SString sContent; sContent += SString ( "MTA:SA Server v%s-r%d-%s crash report.\n", MTA_DM_VERSIONSTRING, MTASA_VERSION_BUILD, MTA_DM_BUILDTYPE ); sContent += SString ( "%04d-%02d-%02d %02d:%02d\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min ); sContent += SString ( "Caught %d addresses ...\n\n", iAmount ); sContent += "Backtrace:\n"; for ( int i = 0; i < iAmount; i++ ) { if ( symbols [ i ] ) { sContent += SString ( "#%d - %s\n", i, symbols [ i ] ); } } sContent += std::string( 80, '-' ) + "\n"; // Write the content to the file and close MakeSureDirExists ( PathJoin( ms_strDumpPath, sFileName ) ); FileAppend( PathJoin( ms_strDumpPath, sFileName ), sContent ); FileAppend( PathJoin( ms_strDumpPath, "server_pending_upload.log" ), sContent ); free ( symbols ); // Try to close window gracefully if ( !g_bSilent && !g_bNoCurses && m_wndInput ) { if ( m_wndMenu ) { delwin ( m_wndMenu ); m_wndMenu = NULL; } delwin ( m_wndInput ); m_wndInput = NULL; endwin ( ); } }
// // CFunctionUseLogger::MaybeFlush // void CFunctionUseLogger::MaybeFlush( bool bForce ) { CTickCount timeNow = CTickCount::Now(); for( std::map < SString, SFuncCallRecord >::iterator iter = m_FuncCallRecordMap.begin() ; iter != m_FuncCallRecordMap.end() ; ) { const SFuncCallRecord& callRecord = iter->second; // Time to flush this line? if ( bForce || ( timeNow - callRecord.timeFirstUsed ).ToInt() > 1500 ) { // Add log line SString strMessage( "%s - %s - %s x %d [%s]\n" , *GetLocalTimeString( true, true ) , *callRecord.strResourceName , *callRecord.strFunctionName , callRecord.uiCallCount , *callRecord.strExampleArgs ); if ( !m_strLogFilename.empty() ) FileAppend( m_strLogFilename, strMessage ); m_FuncCallRecordMap.erase( iter++ ); } else ++iter; } }
void SharedUtil::AddReportLog ( uint uiId, const SString& strText ) { SString strPathFilename = PathJoin ( GetMTADataPath (), "report.log" ); MakeSureDirExists ( strPathFilename ); SString strMessage ( "%u: %s %s - %s\n", uiId, GetTimeString ( true, false ).c_str (), GetReportLogHeaderText ().c_str (), strText.c_str () ); FileAppend ( strPathFilename, &strMessage.at ( 0 ), strMessage.length () ); #if MTA_DEBUG OutputDebugLine ( SStringX ( "[ReportLog] " ) + strMessage ); #endif }
// // Add extra data to the dump file and hope visual studio doesn't mind // void CCrashDumpWriter::AppendToDumpFile ( const SString& strPathFilename, const CBuffer& dataBuffer, DWORD dwMagicStart, DWORD dwMagicEnd ) { CBuffer output; CBufferWriteStream stream ( output ); // 4 bytes zero stream.Write ( (DWORD)0 ); // 4 bytes magic stream.Write ( dwMagicStart ); // 4 bytes size of data stream.Write ( dataBuffer.GetSize () ); // n bytes data stream.WriteBytes ( dataBuffer.GetData (), dataBuffer.GetSize () ); // 4 bytes size of data stream.Write ( dataBuffer.GetSize () ); // 4 bytes magic stream.Write ( dwMagicEnd ); // 4 bytes zero stream.Write ( (DWORD)0 ); FileAppend ( strPathFilename, output.GetData (), output.GetSize () ); }
bool SharedUtil::FileAppend ( const SString& strFilename, const SString& strBuffer, bool bForce ) { return FileAppend ( strFilename, strBuffer.length () ? &strBuffer.at ( 0 ) : NULL, strBuffer.length (), bForce ); }
/////////////////////////////////////////////////////////////// // // CDatabaseJobQueueImpl::LogString // // Add string to log output // /////////////////////////////////////////////////////////////// void CDatabaseJobQueueImpl::LogString ( const SString& strText ) { FileAppend ( m_strLogFilename, strText ); }
HWND SetForegroundWindowEx(HWND aTargetWindow) // Caller must have ensured that aTargetWindow is a valid window or NULL, since we // don't call IsWindow() here. { DWORD target_thread; HWND orig_foreground_wnd; HWND new_foreground_wnd; int is_attached_my_to_fore; int is_attached_fore_to_target; DWORD fore_thread; int i; int show_mode; if (!aTargetWindow) return NULL ; // When called this way (as it is sometimes), do nothing. // v1.0.42.03: Calling IsWindowHung() once here rather than potentially more than once in AttemptSetForeground() // solves a crash that is not fully understood, nor is it easily reproduced (it occurs only in release mode, // not debug mode). It's likely a bug in the API's IsHungAppWindow(), but that is far from confirmed. target_thread = GetWindowThreadProcessId(aTargetWindow, NULL) ; /* if (target_thread != g_MainThreadID && IsWindowHung(aTargetWindow)) // Calls to IsWindowHung should probably be avoided if the window belongs to our thread. Relies upon short-circuit boolean order. */ /* return NULL ; */ orig_foreground_wnd = GetForegroundWindow() ; // AutoIt3: If there is not any foreground window, then input focus is on the TaskBar. // MY: It is definitely possible for GetForegroundWindow() to return NULL, even on XP. if (!orig_foreground_wnd) orig_foreground_wnd = FindWindow("Shell_TrayWnd", NULL) ; if (aTargetWindow == orig_foreground_wnd) // It's already the active window. return aTargetWindow ; if (IsIconic(aTargetWindow)) show_mode = SW_RESTORE; else show_mode = SW_SHOW; ShowWindow(aTargetWindow, show_mode); // if (g_os.IsWin95() || (!g_os.IsWin9x() && !g_os.IsWin2000orLater()))) // Win95 or NT // Try a simple approach first for these two OS's, since they don't have // any restrictions on focus stealing: #ifdef _DEBUG_WINACTIVATE #define IF_ATTEMPT_SET_FORE if (new_foreground_wnd = AttemptSetForeground(aTargetWindow, orig_foreground_wnd, win_name)) #else #define IF_ATTEMPT_SET_FORE if (new_foreground_wnd = AttemptSetForeground(aTargetWindow, orig_foreground_wnd)) #endif IF_ATTEMPT_SET_FORE return new_foreground_wnd ; // Otherwise continue with the more drastic methods below. // MY: The AttachThreadInput method, when used by itself, seems to always // work the first time on my XP system, seemingly regardless of whether the // "allow focus steal" change has been made via SystemParametersInfo() // (but it seems a good idea to keep the SystemParametersInfo() in effect // in case Win2k or Win98 needs it, or in case it really does help in rare cases). // In many cases, this avoids the two SetForegroundWindow() attempts that // would otherwise be needed ; and those two attempts cause some windows // to flash in the taskbar, such as Metapad and Excel (less frequently) whenever // you quickly activate another window after activating it first (e.g. via hotkeys). // So for now, it seems best just to use this method by itself. The // "two-alts" case never seems to fire on my system? Maybe it will // on Win98 sometimes. // Note: In addition to the "taskbar button flashing" annoyance mentioned above // any SetForegroundWindow() attempt made prior to the one below will, // as a side-effect, sometimes trigger the need for the "two-alts" case // below. So that's another reason to just keep it simple and do it this way // only. #ifdef _DEBUG_WINACTIVATE char buf[1024] ; #endif is_attached_my_to_fore = 0; is_attached_fore_to_target = 0; if (orig_foreground_wnd) // Might be NULL from above. { // Based on MSDN docs, these calls should always succeed due to the other // checks done above (e.g. that none of the HWND's are NULL): fore_thread = GetWindowThreadProcessId(orig_foreground_wnd, NULL) ; // MY: Normally, it's suggested that you only need to attach the thread of the // foreground window to our thread. However, I've confirmed that doing all three // attaches below makes the attempt much more likely to succeed. In fact, it // almost always succeeds whereas the one-attach method hardly ever succeeds the first // time (resulting in a flashing taskbar button due to having to invoke a second attempt) // when one window is quickly activated after another was just activated. // AutoIt3: Attach all our input threads, will cause SetForeground to work under 98/Me. // MSDN docs: The AttachThreadInput function fails if either of the specified threads // does not have a message queue (My: ok here, since any window's thread MUST have a // message queue). [It] also fails if a journal record hook is installed. ... Note // that key state, which can be ascertained by calls to the GetKeyState or // GetKeyboardState function, is reset after a call to AttachThreadInput. You cannot // attach a thread to a thread in another desktop. A thread cannot attach to itself. // Therefore, idAttachTo cannot equal idAttach. Update: It appears that of the three, // this first call does not offer any additional benefit, at least on XP, so not // using it for now: //if (g_MainThreadID != target_thread) // Don't attempt the call otherwise. // AttachThreadInput(g_MainThreadID, target_thread, TRUE) ; if (fore_thread && g_MainThreadID != fore_thread) is_attached_my_to_fore = AttachThreadInput(g_MainThreadID, fore_thread, TRUE) != 0 ; if (fore_thread && target_thread && fore_thread != target_thread) // IsWindowHung(aTargetWindow) was called earlier. is_attached_fore_to_target = AttachThreadInput(fore_thread, target_thread, TRUE) != 0 ; } // The log showed that it never seemed to need more than two tries. But there's // not much harm in trying a few extra times. The number of tries needed might // vary depending on how fast the CPU is: for (i = 0; i < 5; ++i) { IF_ATTEMPT_SET_FORE { #ifdef _DEBUG_WINACTIVATE if (i > 0) // More than one attempt was needed. { snprintf(buf, sizeof(buf), "AttachThreadInput attempt #%d indicated success: %s" , i + 1, win_name); FileAppend(LOGF, buf); } #endif break; } } // I decided to avoid the quick minimize + restore method of activation. It's // not that much more effective (if at all), and there are some significant // disadvantages: // - This call will often hang our thread if aTargetWindow is a hung window: ShowWindow(aTargetWindow, SW_MINIMIZE) // - Using SW_FORCEMINIMIZE instead of SW_MINIMIZE has at least one (and probably more) // side effect: When the window is restored, at least via SW_RESTORE, it is no longer // maximized even if it was before the minmize. So don't use it. if (!new_foreground_wnd) // Not successful yet. { // Some apps may be intentionally blocking us by having called the API function // LockSetForegroundWindow(), for which MSDN says "The system automatically enables // calls to SetForegroundWindow if the user presses the ALT key or takes some action // that causes the system itself to change the foreground window (for example, // clicking a background window)." Also, it's probably best to avoid doing // the 2-alts method except as a last resort, because I think it may mess up // the state of menus the user had displayed. And of course if the foreground // app has special handling for alt-key events, it might get confused. // My original note: "The 2-alts case seems to mess up on rare occasions, // perhaps due to menu weirdness triggered by the alt key." // AutoIt3: OK, this is not funny - bring out the extreme measures (usually for 2000/XP). // Simulate two single ALT keystrokes. UPDATE: This hardly ever succeeds. Usually when // it fails, the foreground window is NULL (none). I'm going to try an Win-tab instead, // which selects a task bar button. This seems less invasive than doing an alt-tab // because not only doesn't it activate some other window first, it also doesn't appear // to change the Z-order, which is good because we don't want the alt-tab order // that the user sees to be affected by this. UPDATE: Win-tab isn't doing it, so try // Alt-tab. Alt-tab doesn't do it either. The window itself (metapad.exe is the only // culprit window I've found so far) seems to resist being brought to the foreground, // but later, after the hotkey is released, it can be. So perhaps this is being // caused by the fact that the user has keys held down (logically or physically?) // Releasing those keys with a key-up event might help, so try that sometime: key_down_up(VK_LMENU); key_down_up(VK_LMENU); //KeyEvent(KEYDOWN, VK_LWIN) ; //KeyEvent(KEYDOWN, VK_TAB) ; //KeyEvent(KEYUP, VK_TAB) ; //KeyEvent(KEYUP, VK_LWIN) ; //KeyEvent(KEYDOWN, VK_MENU) ; //KeyEvent(KEYDOWN, VK_TAB) ; //KeyEvent(KEYUP, VK_TAB) ; //KeyEvent(KEYUP, VK_MENU) ; // Also replacing "2-alts" with "alt-tab" below, for now: #ifndef _DEBUG_WINACTIVATE new_foreground_wnd = AttemptSetForeground(aTargetWindow, orig_foreground_wnd) ; #else // debug mode IF_ATTEMPT_SET_FORE FileAppend(LOGF, "2-alts ok: ", false) ; else {