// Commands.cpp : implementation file // // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. #include "stdafx.h" #include "AutoBld.h" #include "Commands.h" #include "config.h" #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CCommands CCommands::CCommands() { m_pApplication = NULL; m_pApplicationEventsObj = NULL; m_pDebuggerEventsObj = NULL; //Because AutoBuild has an event for capturing the buildfinish event, we // need to set some flags to make sure only want to send mail when the // AutoBuild command is invoked, not when you walk up and say "compile" m_bAutoBuilding = TRUE; // if there is a build in progress lets not try to start a second build m_bBuildInProgres = FALSE; m_bTesting = TRUE; //Here we retrieve all our information for the build from the registry m_bSendMail = (BOOL)(AfxGetApp()->GetProfileInt (_T("Configure"), _T("SendMail"), 0)); m_strSendTo = AfxGetApp()->GetProfileString (_T("Configure"), _T("SendTo"), _T("")); m_strStatusLine = AfxGetApp()->GetProfileString (_T("Configure"), _T("StatusText"), _T("")); m_bMailOnEach = (BOOL)(AfxGetApp()->GetProfileInt (_T("Configure"), _T("MailOnEach"), 1)); m_bIncBuildResults = (BOOL)(AfxGetApp()->GetProfileInt (_T("Configure"), _T("IncludeBuildResults"), 1)); m_bSendFile = (BOOL)(AfxGetApp()->GetProfileInt (_T("Configure"), _T("SendFile"), 0)); m_strFileToSend = AfxGetApp()->GetProfileString (_T("Configure"), _T("FileToSend")); m_bCloseWhenDone = (BOOL)(AfxGetApp()->GetProfileInt (_T("Configure"), _T("CloseWhenDone"), 0)); //If the user wishes to send mail when all building is complete, a // running count of the number of Warnings/Errors is needed m_nTotalErrors = 0; m_nTotalWarnings = 0; } CCommands::~CCommands() { ASSERT (m_pApplication != NULL); m_pApplication->Release(); } void CCommands::SetApplicationObject(IApplication* pApplication) { // This function assumes pApplication has already been AddRef'd // for us, which CDSAddIn did in its QueryInterface call // just before it called us. m_pApplication = pApplication; // Create Application event handlers XApplicationEventsObj::CreateInstance(&m_pApplicationEventsObj); m_pApplicationEventsObj->AddRef(); m_pApplicationEventsObj->Connect(m_pApplication); m_pApplicationEventsObj->m_pCommands = this; // Create Debugger event handler CComPtr pDebugger; if (SUCCEEDED(m_pApplication->get_Debugger(&pDebugger)) && pDebugger != NULL) { XDebuggerEventsObj::CreateInstance(&m_pDebuggerEventsObj); m_pDebuggerEventsObj->AddRef(); m_pDebuggerEventsObj->Connect(pDebugger); m_pDebuggerEventsObj->m_pCommands = this; } } void CCommands::UnadviseFromEvents() { ASSERT (m_pApplicationEventsObj != NULL); m_pApplicationEventsObj->Disconnect(m_pApplication); m_pApplicationEventsObj->Release(); m_pApplicationEventsObj = NULL; if (m_pDebuggerEventsObj != NULL) { // Since we were able to connect to the Debugger events, we // should be able to access the Debugger object again to // unadvise from its events (thus the VERIFY_OK below--see stdafx.h). CComPtr pDebugger; VERIFY_OK(m_pApplication->get_Debugger(&pDebugger)); ASSERT (pDebugger != NULL); m_pDebuggerEventsObj->Disconnect(pDebugger); m_pDebuggerEventsObj->Release(); m_pDebuggerEventsObj = NULL; } } ///////////////////////////////////////////////////////////////////////////// // Event handlers // TODO: Fill out the implementation for those events you wish handle // Use m_pCommands->GetApplicationObject() to access the Developer // Studio Application object // Application events HRESULT CCommands::XApplicationEvents::BeforeBuildStart() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } HRESULT CCommands::XApplicationEvents::BuildFinish(long nNumErrors, long nNumWarnings) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); m_pCommands->m_bBuildInProgres = FALSE; if (m_pCommands->m_bAutoBuilding == TRUE) //See comment in the constructor { //here we create a mail message, and send it off... if ((m_pCommands->m_bSendMail == TRUE) && (m_pCommands->m_bMailOnEach == TRUE)) { HINSTANCE hInstMail = ::LoadLibrary("MAPI32.DLL"); if (hInstMail != NULL) { ULONG (PASCAL *lpfnSendMail)(ULONG, ULONG, MapiMessage*, FLAGS, ULONG); (FARPROC&)lpfnSendMail = GetProcAddress(hInstMail, "MAPISendMail"); if (lpfnSendMail != NULL) { MapiMessage message; memset((void*)&message, 0, sizeof(message)); message.lpszSubject = const_cast ((LPCSTR)m_pCommands->m_strStatusLine); CString strErrWarnCStr; if (m_pCommands->m_bIncBuildResults == TRUE) { CString strErrWarnText; strErrWarnText.Format(IDS_ERRWARNTEXT, nNumErrors, nNumWarnings); strErrWarnCStr = CString(message.lpszSubject) + strErrWarnText; message.lpszSubject = const_cast ((LPCSTR)strErrWarnCStr); } CString strToMail; if (m_pCommands->m_bSendFile == FALSE) { strToMail.Format(IDS_DEFAULTMAILBODY, m_pCommands->m_strBuildingConfigurationName); } else { CString strResult; CStdioFile fileTextToMail; try { fileTextToMail.Open(m_pCommands->m_strFileToSend, CFile::modeRead | CFile::typeText); DWORD dwFileSize = fileTextToMail.GetLength(); dwFileSize = fileTextToMail.Read( strResult.GetBuffer(dwFileSize), dwFileSize); strResult.ReleaseBuffer(dwFileSize); CString strLocal; strLocal.Format(strResult, m_pCommands->m_strBuildingConfigurationName, nNumErrors, nNumWarnings); strToMail = strLocal; } catch (...) //If some problem occurrs when working // with the file, just send the default // message body { if (m_pCommands->m_bTesting == TRUE) AfxMessageBox(IDS_WARNSENDDEF); strToMail.Format(IDS_DEFAULTMAILBODY, m_pCommands->m_strBuildingConfigurationName); } } message.lpszNoteText = const_cast((LPCSTR)strToMail); message.nRecipCount = 1; message.lpRecips = new MapiRecipDesc; memset(message.lpRecips, 0, sizeof(MapiRecipDesc)); message.lpRecips->ulRecipClass = MAPI_TO; CString strTemp2 = CString("SMTP:") + m_pCommands->m_strSendTo; message.lpRecips->lpszName = const_cast ((LPCSTR)m_pCommands->m_strSendTo); message.lpRecips->lpszAddress = const_cast ((LPCSTR)strTemp2); int error = lpfnSendMail(0, (ULONG)0, &message, 0, 0); //error is not handled, because you really don't want to // pop up a message box. Putting up a message box would // suspend other pending builds until somebody would // manually click the OK button. You may wish to place // some sort of logging here, so that the error would be // dumped to a file. // The reason you might get an error is because your email // may require a password. You can log into your email account first, // or create an account that doesn't require a password. if (error != SUCCESS_SUCCESS) { if (m_pCommands->m_bTesting == TRUE) { AfxMessageBox(IDS_MAPIERROR); } else { // log some other kind of error in a log file } } delete message.lpRecips; } ::FreeLibrary(hInstMail); } } } m_pCommands->m_nTotalErrors += nNumErrors; m_pCommands->m_nTotalWarnings += nNumWarnings; return S_OK; } HRESULT CCommands::XApplicationEvents::BeforeApplicationShutDown() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } HRESULT CCommands::XApplicationEvents::DocumentOpen(IDispatch* theDocument) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } HRESULT CCommands::XApplicationEvents::BeforeDocumentClose(IDispatch* theDocument) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } HRESULT CCommands::XApplicationEvents::DocumentSave(IDispatch* theDocument) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } HRESULT CCommands::XApplicationEvents::NewDocument(IDispatch* theDocument) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } HRESULT CCommands::XApplicationEvents::WindowActivate(IDispatch* theWindow) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } HRESULT CCommands::XApplicationEvents::WindowDeactivate(IDispatch* theWindow) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } HRESULT CCommands::XApplicationEvents::WorkspaceOpen() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } HRESULT CCommands::XApplicationEvents::WorkspaceClose() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } HRESULT CCommands::XApplicationEvents::NewWorkspace() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } // Debugger event HRESULT CCommands::XDebuggerEvents::BreakpointHit(IDispatch* pBreakpoint) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); return S_OK; } ///////////////////////////////////////////////////////////////////////////// // CCommands methods STDMETHODIMP CCommands::AutoBuildTest() { // don't allow more than one test to go. if (m_bBuildInProgres) return S_OK; AFX_MANAGE_STATE(AfxGetStaticModuleState()); m_pApplication->EnableModeless(VARIANT_FALSE); m_nTotalErrors = 0; m_nTotalWarnings = 0; m_bAutoBuilding = TRUE; //See comment in the constructor m_bBuildInProgres = TRUE; //See comment in the constructor long lCount; int nNumWorkspaces = AfxGetApp()->GetProfileInt(_T("Configure"), _T("NumWorkspaces"), 0); for (int nWorkspaceNumber = 1 ; nWorkspaceNumber <= nNumWorkspaces ; nWorkspaceNumber++) { char RegKey[50]; wsprintf(RegKey, "Workspace%d", nWorkspaceNumber-1); CComBSTR bszWorkspacePathName = AfxGetApp()->GetProfileString( _T("Configure"), RegKey, ""); CComPtr pDispDocuments; VERIFY_OK(m_pApplication->get_Documents(&pDispDocuments)); CComVariant OleVariant; //By default, the type is VT_EMPTY CComQIPtr pDocuments(pDispDocuments); CComPtr pWorkspace; //Never gets used except in: VERIFY_OK(pDocuments->Open(bszWorkspacePathName, OleVariant, OleVariant, &pWorkspace)); //First, get a pointer to the dispatch for the Projects collection CComPtr pDispProjects; // clean out the output files from and old build. VERIFY_OK(m_pApplication->get_Projects(&pDispProjects)); CComQIPtr pProjects(pDispProjects); //Get the number of projects in the collection VERIFY_OK(pProjects->get_Count(&lCount)); for (long i = 1 ; i < lCount+1 ; i++) { long lNumConfigs; CComVariant Vari = i; //Get the next project CComPtr pGenProject; VERIFY_OK(pProjects->Item(Vari, &pGenProject)); CComQIPtr pProject(pGenProject); //Each project has a configuration (Win32 Release, Win32 Debug, // etc.), get the collection of these configurations CComPtr pConfigs; VERIFY_OK(pProject->get_Configurations(&pConfigs)); VERIFY_OK(pConfigs->get_Count(&lNumConfigs)); for (long j = 1 ; j < lNumConfigs+1 ; j++) { CComVariant Varj = j; //Get each individual configuration CComPtr pConfig; VERIFY_OK(pConfigs->Item(Varj, &pConfig)); CComVariant VarDisp = pConfig; CComBSTR bszStr; VERIFY_OK(pConfig->get_Name(&bszStr)); if (m_bMailOnEach == TRUE) m_strBuildingConfigurationName = bszStr; else m_strBuildingConfigurationName += CString(", ") + CString(bszStr); //Build this particular // configuration, in this project, // in this Workspace... VERIFY_OK(m_pApplication->Build(VarDisp)); } } } if (m_bMailOnEach == FALSE) { //We only wish to send mail when everything is built. // to do this, we just say "from now on we are sending Mail on each // configuration build" m_bMailOnEach = TRUE; // then manually call the BuildFinish event, as if a configuration is // done, but this "Configuration" is the entire project ASSERT(m_pApplicationEventsObj != NULL); m_pApplicationEventsObj->BuildFinish(m_nTotalErrors, m_nTotalWarnings); //Reset MailOnEach m_bMailOnEach = FALSE; } m_bAutoBuilding = FALSE; //See comment in the constructor m_pApplication->EnableModeless(VARIANT_TRUE); if (m_bTesting == FALSE) { if (m_bCloseWhenDone == TRUE) VERIFY_OK(m_pApplication->Quit()); } else { if (m_bCloseWhenDone == TRUE) AfxMessageBox(IDS_WARNEXIT); } return S_OK; } STDMETHODIMP CCommands::AutoBuild() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); m_bTesting = FALSE; AutoBuildTest(); m_bTesting = TRUE; return S_OK; } STDMETHODIMP CCommands::AutoBuildConfigure() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); m_pApplication->EnableModeless(VARIANT_FALSE); CConfigure AutoBuildConfigDlg; // stuff all the pre read data values in the dialog before // showing it AutoBuildConfigDlg.m_bSendMail = m_bSendMail; AutoBuildConfigDlg.m_bCloseWhenDone = m_bCloseWhenDone; AutoBuildConfigDlg.m_bMailOnEach = m_bMailOnEach; AutoBuildConfigDlg.m_bIncBuildResults = m_bIncBuildResults; AutoBuildConfigDlg.m_bSendFile = m_bSendFile; AutoBuildConfigDlg.m_strFileToSend = m_strFileToSend; AutoBuildConfigDlg.m_strStatusLine = m_strStatusLine; AutoBuildConfigDlg.m_strSendTo = m_strSendTo; AutoBuildConfigDlg.DoModal(); // get the data values back. m_bSendMail = AutoBuildConfigDlg.m_bSendMail; m_bCloseWhenDone = AutoBuildConfigDlg.m_bCloseWhenDone; m_bMailOnEach = AutoBuildConfigDlg.m_bMailOnEach; m_bIncBuildResults = AutoBuildConfigDlg.m_bIncBuildResults; m_bSendFile = AutoBuildConfigDlg.m_bSendFile; m_strFileToSend = AutoBuildConfigDlg.m_strFileToSend; m_strStatusLine = AutoBuildConfigDlg.m_strStatusLine; m_strSendTo = AutoBuildConfigDlg.m_strSendTo; m_pApplication->EnableModeless(VARIANT_TRUE); return S_OK; }