//++ ------------------------------------------------------------------------------------ // Details: Write data to existing opened file. // Type: Method. // Args: vData - (R) Text data. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIUtilFileStd::Write( const CMIUtilString & vData ) { if( vData.size() == 0 ) return MIstatus::success; if( m_bFileError ) return MIstatus::failure; if( m_pFileHandle == nullptr ) { m_bFileError = true; SetErrorDescriptionn( MIRSRC( IDE_UTIL_FILE_ERR_WRITING_NOTOPEN ), m_fileNamePath.c_str() ); return MIstatus::failure; } // Get the string size MIuint size = vData.size(); if( ::fwrite( vData.c_str(), 1, size, m_pFileHandle ) == size ) { // Flush the data to the file ::fflush( m_pFileHandle ); return MIstatus::success; } // Not all of the data has been transferred m_bFileError = true; SetErrorDescriptionn( MIRSRC( IDE_UTIL_FILE_ERR_WRITING_FILE ), m_fileNamePath.c_str() ); return MIstatus::failure; }
//++ ------------------------------------------------------------------------------------ // Details: Start worker threads for the driver. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::StartWorkerThreads( void ) { bool bOk = MIstatus::success; // Grab the thread manager CMICmnThreadMgrStd & rThreadMgr = CMICmnThreadMgrStd::Instance(); // Start the stdin thread bOk &= m_rStdin.SetVisitor( *this ); if( bOk && !rThreadMgr.ThreadStart< CMICmnStreamStdin >( m_rStdin )) { const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str() ); SetErrorDescriptionn( errMsg ); return MIstatus::failure; } // Start the event polling thread if( bOk && !rThreadMgr.ThreadStart< CMICmnLLDBDebugger >( m_rLldbDebugger ) ) { const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC( IDS_THREADMGR_ERR_THREAD_FAIL_CREATE ), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str() ); SetErrorDescriptionn( errMsg ); return MIstatus::failure; } return bOk; }
//++ ------------------------------------------------------------------------------------ // Details: Write data to existing opened file. // Type: Method. // Args: vData - (R) Text data. // vCharCnt - (R) Text data length. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIUtilFileStd::Write( const MIchar * vpData, const MIuint vCharCnt ) { if( vCharCnt == 0 ) return MIstatus::success; if( m_bFileError ) return MIstatus::failure; if( m_pFileHandle == nullptr ) { m_bFileError = true; SetErrorDescriptionn( MIRSRC( IDE_UTIL_FILE_ERR_WRITING_NOTOPEN ), m_fileNamePath.c_str() ); return MIstatus::failure; } if( ::fwrite( vpData, 1, vCharCnt, m_pFileHandle ) == vCharCnt ) { // Flush the data to the file ::fflush( m_pFileHandle ); return MIstatus::success; } // Not all of the data has been transferred m_bFileError = true; SetErrorDescriptionn( MIRSRC( IDE_UTIL_FILE_ERR_WRITING_FILE ), m_fileNamePath.c_str() ); return MIstatus::failure; }
@@ -509,7 +509,7 @@ bool CMIDriver::StartWorkerThreads() { const CMIUtilString errMsg = CMIUtilString::Format( MIRSRC(IDS_THREADMGR_ERR_THREAD_FAIL_CREATE), CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str()); - SetErrorDescriptionn(errMsg); + SetErrorDescriptionn(errMsg.c_str()); return MIstatus::failure; }
//++ //------------------------------------------------------------------------------------ // Details: Release resources for *this thread manager. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnThreadMgrStd::Shutdown() { if (--m_clientUsageRefCnt > 0) return MIstatus::success; if (!m_bInitialized) return MIstatus::success; m_bInitialized = false; ClrErrorDescription(); bool bOk = MIstatus::success; CMIUtilString errMsg; // Tidy up ThreadAllTerminate(); // Note shutdown order is important here MI::ModuleShutdown<CMICmnResources>(IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg); MI::ModuleShutdown<CMICmnLog>(IDS_MI_SHTDWN_ERR_LOG, bOk, errMsg); if (!bOk) { SetErrorDescriptionn(MIRSRC(IDS_MI_SHUTDOWN_ERR), errMsg.c_str()); } return bOk; }
//++ ------------------------------------------------------------------------------------ // Details: Release resources for *this Stdin stream. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdin::Shutdown(void) { if (--m_clientUsageRefCnt > 0) return MIstatus::success; if (!m_bInitialized) return MIstatus::success; m_bInitialized = false; ClrErrorDescription(); if (m_pCmdBuffer != nullptr) { delete[] m_pCmdBuffer; m_pCmdBuffer = nullptr; } bool bOk = MIstatus::success; CMIUtilString errMsg; MI::ModuleShutdown<CMICmnResources>(IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg); MI::ModuleShutdown<CMICmnLog>(IDS_MI_SHTDWN_ERR_LOG, bOk, errMsg); if (!bOk) { SetErrorDescriptionn(MIRSRC(IDE_MI_SHTDWN_ERR_STREAMSTDIN), errMsg.c_str()); } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Release resources for *this Stdin stream. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdinLinux::Shutdown( void ) { if( !m_bInitialized ) return MIstatus::success; m_bInitialized = false; ClrErrorDescription(); bool bOk = MIstatus::success; CMIUtilString errMsg; // Tidy up if( m_pCmdBuffer != nullptr ) { delete [] m_pCmdBuffer; m_pCmdBuffer = nullptr; } m_pStdin = nullptr; // Note shutdown order is important here MI::ModuleShutdown< CMICmnResources >( IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg ); MI::ModuleShutdown< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg ); if( !bOk ) { SetErrorDescriptionn( MIRSRC( IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER ), errMsg.c_str() ); } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Unbind detach or release resources used by *this driver. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::Shutdown(void) { if (--m_clientUsageRefCnt > 0) return MIstatus::success; if (!m_bInitialized) return MIstatus::success; m_eCurrentDriverState = eDriverState_ShuttingDown; ClrErrorDescription(); bool bOk = MIstatus::success; CMIUtilString errMsg; // Shutdown all of the modules we depend on MI::ModuleShutdown<CMICmnLLDBDebugger>(IDS_MI_INIT_ERR_LLDBDEBUGGER, bOk, errMsg); MI::ModuleShutdown<CMICmdMgr>(IDS_MI_INIT_ERR_CMDMGR, bOk, errMsg); MI::ModuleShutdown<CMICmnStreamStdin>(IDS_MI_INIT_ERR_STREAMSTDIN, bOk, errMsg); MI::ModuleShutdown<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMANAGER, bOk, errMsg); MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg); MI::ModuleShutdown<CMICmnStreamStderr>(IDS_MI_INIT_ERR_STREAMSTDERR, bOk, errMsg); MI::ModuleShutdown<CMICmnStreamStdout>(IDS_MI_INIT_ERR_STREAMSTDOUT, bOk, errMsg); MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg); if (!bOk) { SetErrorDescriptionn(MIRSRC(IDS_MI_SHUTDOWN_ERR), errMsg.c_str()); } m_eCurrentDriverState = eDriverState_NotRunning; return bOk; }
//++ ------------------------------------------------------------------------------------ // Details: Set a unique ID for *this driver. It cannot be empty. // Type: Overridden. // Args: vId - (R) Text description. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::SetId( const CMIUtilString & vId ) { if( vId.empty() ) { SetErrorDescriptionn( MIRSRC( IDS_DRIVER_ERR_ID_INVALID ), GetName().c_str(), vId.c_str() ); return MIstatus::failure; } m_strDriverId = vId; return MIstatus::success; }
//++ //------------------------------------------------------------------------------------ // Details: Release resources for *this debugger object. // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebugger::Shutdown() { if (--m_clientUsageRefCnt > 0) return MIstatus::success; if (!m_bInitialized) return MIstatus::success; m_bInitialized = false; ClrErrorDescription(); bool bOk = MIstatus::success; CMIUtilString errMsg; // Explicitly delete the remote target in case MI needs to exit prematurely // otherwise // LLDB debugger may hang in its Destroy() fn waiting on events lldb::SBTarget sbTarget = CMICmnLLDBDebugSessionInfo::Instance().GetTarget(); m_lldbDebugger.DeleteTarget(sbTarget); // Debug: May need this but does seem to work without it so commented out the // fudge 19/06/2014 // It appears we need to wait as hang does not occur when hitting a debug // breakpoint here // const std::chrono::milliseconds time( 1000 ); // std::this_thread::sleep_for( time ); lldb::SBDebugger::Destroy(m_lldbDebugger); lldb::SBDebugger::Terminate(); m_pClientDriver = nullptr; m_mapBroadcastClassNameToEventMask.clear(); m_mapIdToEventMask.clear(); // Note shutdown order is important here MI::ModuleShutdown<CMICmnLLDBDebugSessionInfo>( IDS_MI_INIT_ERR_DEBUGSESSIONINFO, bOk, errMsg); MI::ModuleShutdown<CMICmnLLDBDebuggerHandleEvents>( IDS_MI_INIT_ERR_OUTOFBANDHANDLER, bOk, errMsg); MI::ModuleShutdown<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMGR, bOk, errMsg); MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg); MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg); if (!bOk) { SetErrorDescriptionn(MIRSRC(IDS_MI_SHTDWN_ERR_LLDBDEBUGGER), errMsg.c_str()); } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Release resources for *this Command Manager. // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmdMgr::Shutdown(void) { if (--m_clientUsageRefCnt > 0) return MIstatus::success; if (!m_bInitialized) return MIstatus::success; m_bInitialized = false; ClrErrorDescription(); bool bOk = MIstatus::success; CMIUtilString errMsg; // Tidy up m_setCmdDeleteCallback.clear(); // Note shutdown order is important here if (!m_invoker.Shutdown()) { bOk = false; errMsg += CMIUtilString::Format(MIRSRC(IDS_MI_SHTDWN_ERR_CMDINVOKER), m_invoker.GetErrorDescription().c_str()); } if (!m_factory.Shutdown()) { bOk = false; if (!errMsg.empty()) errMsg += ", "; errMsg += CMIUtilString::Format(MIRSRC(IDS_MI_SHTDWN_ERR_CMDFACTORY), m_factory.GetErrorDescription().c_str()); } if (!m_interpretor.Shutdown()) { bOk = false; if (!errMsg.empty()) errMsg += ", "; errMsg += CMIUtilString::Format(MIRSRC(IDS_MI_SHTDWN_ERR_CMDINTERPRETER), m_interpretor.GetErrorDescription().c_str()); } MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg); MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg); if (!bOk) { SetErrorDescriptionn(MIRSRC(IDS_MI_SHUTDOWN_ERR), errMsg.c_str()); } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Register a driver with *this Driver Manager. Call SetUseThisDriverToDoWork() // inform the manager which driver is the one to the work. The manager calls // the driver's init function which must be successful in order to complete the // registration. // Type: Method. // Args: vrDriver - (R) The driver to register. // vrDriverID - (R) The driver's ID to lookup by. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriverMgr::RegisterDriver( const IDriver & vrDriver, const CMIUtilString & vrDriverID ) { if( HaveDriverAlready( vrDriver ) ) return MIstatus::success; IDriver * pDriver = const_cast< IDriver * >( &vrDriver ); if( !pDriver->SetId( vrDriverID ) ) return MIstatus::failure; if( !pDriver->DoInitialize() ) { SetErrorDescriptionn( MIRSRC( IDS_DRIVERMGR_DRIVER_ERR_INIT ), pDriver->GetName().c_str(), vrDriverID.c_str(), pDriver->GetError().c_str() ); return MIstatus::failure; } MapPairDriverIdToDriver_t pr( vrDriverID, pDriver ); m_mapDriverIdToDriver.insert( pr ); return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Open file for writing. On the first call to this function after *this object // is created the file is either created or replace, from then on open only opens // an existing file. // Type: Method. // Args: vFileNamePath - (R) File name path. // vwrbNewCreated - (W) True - file recreated, false - file appended too. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIUtilFileStd::CreateWrite( const CMIUtilString & vFileNamePath, bool & vwrbNewCreated ) { // Reset m_bFileError = false; vwrbNewCreated = false; if( vFileNamePath.empty() ) { m_bFileError = true; SetErrorDescription( MIRSRC( IDS_UTIL_FILE_ERR_INVALID_PATHNAME ) ); return MIstatus::failure; } // File is already open so exit if( m_pFileHandle != nullptr ) return MIstatus::success; #if !defined( _MSC_VER ) // Open with 'write' and 'binary' mode m_pFileHandle = ::fopen( vFileNamePath.c_str(), "wb" ); #else // Open a file with exclusive write and shared read permissions m_pFileHandle = ::_fsopen( vFileNamePath.c_str(), "wb", _SH_DENYWR ); #endif // !defined( _MSC_VER ) if( m_pFileHandle == nullptr ) { m_bFileError = true; SetErrorDescriptionn( MIRSRC( IDS_UTIL_FILE_ERR_OPENING_FILE ), strerror( errno ), vFileNamePath.c_str() ); return MIstatus::failure; } vwrbNewCreated = true; m_fileNamePath = vFileNamePath; return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Release resources for *this Stdin stream. // Type: Method. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMICmnStreamStdin::Shutdown(void) { if (--m_clientUsageRefCnt > 0) return MIstatus::success; if (!m_bInitialized) return MIstatus::success; m_bInitialized = false; ClrErrorDescription(); bool bOk = MIstatus::success; CMIUtilString errMsg; m_pVisitor = nullptr; m_bKeyCtrlCHit = false; // Note shutdown order is important here #ifndef _MSC_VER MI::ModuleShutdown<CMICmnStreamStdinLinux>(IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER, bOk, errMsg); #else MI::ModuleShutdown<CMICmnStreamStdinWindows>(IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER, bOk, errMsg); #endif // ( _MSC_VER ) MI::ModuleShutdown<CMICmnThreadMgrStd>(IDS_MI_SHTDWN_ERR_THREADMGR, bOk, errMsg); MI::ModuleShutdown<CMICmnResources>(IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg); MI::ModuleShutdown<CMICmnLog>(IDS_MI_SHTDWN_ERR_LOG, bOk, errMsg); if (!bOk) { SetErrorDescriptionn(MIRSRC(IDE_MI_SHTDWN_ERR_STREAMSTDIN), errMsg.c_str()); } return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Call this function puts *this driver to work. // This function is used by the application's main thread. // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::DoMainLoop(void) { if (!InitClientIDEToMIDriver()) // Init Eclipse IDE { SetErrorDescriptionn(MIRSRC(IDS_MI_INIT_ERR_CLIENT_USING_DRIVER)); return MIstatus::failure; } if (!StartWorkerThreads()) return MIstatus::failure; bool bOk = MIstatus::success; if (HaveExecutableFileNamePathOnCmdLine()) { if (!LocalDebugSessionStartupExecuteCommands()) { SetErrorDescription(MIRSRC(IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION)); bOk = MIstatus::failure; } } // App is not quitting currently m_bExitApp = false; // While the app is active while (bOk && !m_bExitApp) { CMIUtilString errorText; const MIchar *pCmd = m_rStdin.ReadLine (errorText); if (pCmd != nullptr) { CMIUtilString lineText(pCmd); if (!lineText.empty ()) { if (lineText == "quit") { // We want to be exiting when receiving a quit command m_bExitApp = true; break; } { // Lock Mutex before processing commands so that we don't disturb an event // being processed CMIUtilThreadLock lock(CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex()); bOk = InterpretCommand(lineText); } // Draw prompt if desired if (bOk && m_rStdin.GetEnablePrompt()) bOk = m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); } } } // Signal that the application is shutting down DoAppQuit(); // Close and wait for the workers to stop StopWorkerThreads(); // Ensure that a new line is sent as the last act of the dying driver m_rStdOut.WriteMIResponse("\n", false); return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Call this function puts *this driver to work. // This function is used by the application's main thread. // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriver::DoMainLoop(void) { if (!InitClientIDEToMIDriver()) // Init Eclipse IDE { SetErrorDescriptionn(MIRSRC(IDS_MI_INIT_ERR_CLIENT_USING_DRIVER)); return MIstatus::failure; } if (!StartWorkerThreads()) return MIstatus::failure; bool bOk = MIstatus::success; if (HaveExecutableFileNamePathOnCmdLine()) { if (!LocalDebugSessionStartupExecuteCommands()) { SetErrorDescription(MIRSRC(IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION)); bOk = MIstatus::failure; } } // App is not quitting currently m_bExitApp = false; // Handle source file if (m_bHaveCommandFileNamePathOnCmdLine) { const bool bAsyncMode = false; ExecuteCommandFile(bAsyncMode); } // While the app is active while (bOk && !m_bExitApp) { CMIUtilString errorText; const char *pCmd = m_rStdin.ReadLine (errorText); if (pCmd != nullptr) { CMIUtilString lineText(pCmd); if (!lineText.empty ()) { // Check that the handler thread is alive (otherwise we stuck here) assert(CMICmnLLDBDebugger::Instance().ThreadIsActive()); { // Lock Mutex before processing commands so that we don't disturb an event // being processed CMIUtilThreadLock lock(CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex()); bOk = InterpretCommand(lineText); } // Draw prompt if desired bOk = bOk && CMICmnStreamStdout::WritePrompt(); // Wait while the handler thread handles incoming events CMICmnLLDBDebugger::Instance().WaitForHandleEvent(); } } } // Signal that the application is shutting down DoAppQuit(); // Close and wait for the workers to stop StopWorkerThreads(); // Ensure that a new line is sent as the last act of the dying driver m_rStdOut.WriteMIResponse("\n", false); return MIstatus::success; }
//++ ------------------------------------------------------------------------------------ // Details: Unbind detach or release resources used by this server in general common // functionality shared between versions of any server interfaces implemented. // Type: Method. // Args: vbAppExitOk - (R) True = No problems, false = App exiting with problems (investigate!). // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool CMIDriverMgr::Shutdown( void ) { // Do not want a ref counter because this function needs to be called how ever this // application stops running //if( --m_clientUsageRefCnt > 0 ) // return MIstatus::success; bool vbAppExitOk = true; ClrErrorDescription(); if( !m_bInitialized ) return MIstatus::success; if( vbAppExitOk ) { // The MI Driver's log updating may have been switched off switch back on to say all is ok. CMICmnLog::Instance().SetEnabled( true ); #if _DEBUG CMICmnStreamStdout::Instance().Write( MIRSRC( IDE_MI_APP_EXIT_OK ) ); // Both stdout and Log #else CMICmnLog::WriteLog( MIRSRC( IDE_MI_APP_EXIT_OK ) ); // Just to the Log #endif // _DEBUG } else { CMICmnLog & rAppLog = CMICmnLog::Instance(); if( rAppLog.GetEnabled() ) { const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDE_MI_APP_EXIT_WITH_PROBLEM ), CMICmnLogMediumFile::Instance().GetFileName().c_str() ) ); CMICmnStreamStdout::Instance().Write( msg ); } else { // The MI Driver's log updating may have been switched off switch back on to say there has been problem. rAppLog.SetEnabled( true ); const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDE_MI_APP_EXIT_WITH_PROBLEM_NO_LOG ), CMICmnLogMediumFile::Instance().GetFileName().c_str() ) ); CMICmnStreamStdout::Instance().Write( msg ); } } m_bInitialized = false; bool bOk = MIstatus::success; CMIUtilString errMsg; // Tidy up UnregisterDriverAll(); MIUtilTermios::StdinTermiosReset(); // Note shutdown order is important here MI::ModuleShutdown< CMICmnResources >( IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg ); MI::ModuleShutdown< CMICmnLog > ( IDS_MI_SHTDWN_ERR_LOG , bOk, errMsg ); if( !bOk ) { SetErrorDescriptionn( MIRSRC( IDS_MI_SHTDWN_ERR_DRIVERMGR ), errMsg.c_str() ); } return bOk; }