// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved. #include "stdafx.h" #include #include "ComSpyCtl.h" #include "ComSpyAudit.h" #include "AppInfo.h" #include "CComSpy.h" #include "selecteventsdlg.h" #include "commdlg.h" #include #include "shellapi.h" #include LONGLONG PerformanceFrequency = 0; // // for some reason this define isn't being included // // const GUID CLSID_StockFontPage = {0x7ebdaae0, 0x8120, 0x11cf, { 0x89, 0x9f, 0x0, 0xaa, 0x0, 0x68, 0x8b, 0x10}}; // // given a GUID, return its string representation // BSTR GuidToBstr(REFGUID guid) { CComBSTR b(40); int nRet = StringFromGUID2(guid, b.m_str, 40); _ASSERTE(nRet); return b.Detach(); } ///////////////////////////////////////////////////////////////////////////// // CComSpy #define MAX_MSG_LENGTH 1024 static const LPCWSTR pwszColNames[] = { L"Count", L"Event", L"Tick Count", L"Application", L"Parameter", L"Value" }; CComSpy::CComSpy() : m_ctlSysListView32(L"SysListView32", this, 1) { m_hWndList = NULL; m_bLogToFile = FALSE; m_hFile = NULL; m_cEvents = 0; m_bShowGridLines = TRUE; m_bWindowOnly = TRUE; for (int i=0;i 5) temp += m_sLogFile; else temp += "..."; ModifyMenu(hMenu, ID_LOG, MF_BYCOMMAND|MF_STRING, ID_LOG, temp); CheckMenuItem(hMenu, ID_LOG, m_bLogToFile ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED); CheckMenuItem(hMenu, ID_OPTIONS_GRID_LINES, m_bShowGridLines ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED); CheckMenuItem(hMenu, ID_SHOW_ON_SCREEN, m_bShowOnScreen ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED); CheckMenuItem(hMenu, ID_AUDIT, m_bAudit ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED); m_hMenuDebug = GetSubMenu(hMenu, 5); _ASSERTE(m_hMenuDebug); AddRunningAspsToDebugMenu(m_hMenuDebug); return 0; } // // sets a glog to log to file // if the user hasn't chosen a log file, show the common dialog to allow them to select one // LRESULT CComSpy::OnLogToFile(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { m_bLogToFile = 1 - m_bLogToFile; if (m_bLogToFile) { if (m_sLogFile.Length() == 0) { BOOL bHandledIgnored = TRUE; OnChooseLogFile(0,0,0,bHandledIgnored); if (m_sLogFile.Length() == 0) return 0; } m_hFile = CreateFile(m_sLogFile, GENERIC_WRITE, 0, (LPSECURITY_ATTRIBUTES) NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL); if (!m_hFile) { m_bLogToFile = FALSE; return 0; } } else { if (m_hFile) { CloseHandle(m_hFile); m_hFile = NULL; } } return 0; } // // User wants to choose a log file -- show the common dialog // LRESULT CComSpy::OnChooseLogFile(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { OPENFILENAME OpenFileName; WCHAR szFile[MAX_PATH]; ZeroMemory(szFile, sizeof(szFile)); if (m_sLogFile.Length() > 2 && m_sLogFile.Length() < MAX_PATH-1) StringCchCopy(szFile, MAX_PATH, m_sLogFile.m_str); else StringCchCopy(szFile, MAX_PATH, L"ComSpy.Log"); // Fill in the OPENFILENAME structure to support a template and hook. OpenFileName.lStructSize = sizeof(OPENFILENAME); OpenFileName.hwndOwner = m_hWndList; OpenFileName.hInstance = _Module.GetModuleInstance( ); OpenFileName.lpstrFilter = L"TAB seperated Files (*.log)\0*.log\0CSV Files (*.csv)\0*.csv\0"; OpenFileName.lpstrCustomFilter = NULL; OpenFileName.nMaxCustFilter = 0; OpenFileName.nFilterIndex = 0; OpenFileName.lpstrFile = szFile; OpenFileName.nMaxFile = ARRAYSIZE(szFile); OpenFileName.lpstrFileTitle = NULL; OpenFileName.nMaxFileTitle = 0; OpenFileName.lpstrInitialDir = NULL; OpenFileName.lpstrTitle = L"Choose Log File"; OpenFileName.nFileOffset = 0; OpenFileName.nFileExtension = 0; OpenFileName.lpstrDefExt = NULL; OpenFileName.lCustData = 0; OpenFileName.lpfnHook = NULL; OpenFileName.lpTemplateName = NULL; OpenFileName.Flags = OFN_EXPLORER | OFN_HIDEREADONLY |OFN_NOREADONLYRETURN |OFN_CREATEPROMPT; // Call the common dialog function. if (GetSaveFileName(&OpenFileName)) { m_sLogFile = OpenFileName.lpstrFile; if (_wcsicmp(OpenFileName.lpstrFile + OpenFileName.nFileExtension, L"csv") == 0) m_bCSV = TRUE; } return 0; } // // show/hide gridlines in the list // // NOTE: This will only work if the user has installed IE 3.0 or greater // LRESULT CComSpy::OnToggleGridLines(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { m_bShowGridLines = 1 - m_bShowGridLines; DWORD dwStyle = ListView_GetExtendedListViewStyle(m_hWndList); (m_bShowGridLines) ? dwStyle |= LVS_EX_GRIDLINES : dwStyle &= ~LVS_EX_GRIDLINES; ListView_SetExtendedListViewStyle(m_hWndList, dwStyle); return 0; } // // enable/disable auditing // // LRESULT CComSpy::OnToggleAudit(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { m_bAudit = !m_bAudit; HRESULT hr = EnableAudit(m_bAudit); if (hr != S_OK) m_bAudit = FALSE; return 0; } LRESULT CComSpy::OnToggleShowOnScreen(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { m_bShowOnScreen = 1-m_bShowOnScreen; return 0; } // // show the standard Shell About box // LRESULT CComSpy::OnAbout(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { HICON hIcon = LoadIcon(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDI_MAIN)); ShellAbout(m_hWnd, L"COM Spy", L"Version 1.00", hIcon); return 0; } // // clear the list box // LRESULT CComSpy::OnClear(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { ListView_DeleteAllItems(m_hWndList); m_cEvents = 0; return 0; } // // save the items in the list box to the log file // LRESULT CComSpy::OnSave(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { OPENFILENAME OpenFileName; WCHAR szFile[MAX_PATH]; ZeroMemory(szFile, sizeof(szFile)); if (m_sLogFile.Length() > 2 && m_sLogFile.Length() < MAX_PATH -1) StringCchCopy(szFile, MAX_PATH, m_sLogFile.m_str); else StringCchCopy(szFile, MAX_PATH, L"COMSpy.Log"); OpenFileName.lStructSize = sizeof(OPENFILENAME); OpenFileName.hwndOwner = m_hWndList; OpenFileName.hInstance = _Module.GetModuleInstance( ); OpenFileName.lpstrFilter = NULL; OpenFileName.lpstrCustomFilter = NULL; OpenFileName.nMaxCustFilter = 0; OpenFileName.nFilterIndex = 0; OpenFileName.lpstrFile = szFile; OpenFileName.nMaxFile = ARRAYSIZE(szFile); OpenFileName.lpstrFileTitle = NULL; OpenFileName.nMaxFileTitle = 0; OpenFileName.lpstrInitialDir = NULL; OpenFileName.lpstrTitle = L"Log ToFile"; OpenFileName.nFileOffset = 0; OpenFileName.nFileExtension = 0; OpenFileName.lpstrDefExt = NULL; OpenFileName.lCustData = 0; OpenFileName.lpfnHook = NULL; OpenFileName.lpTemplateName = NULL; OpenFileName.Flags = OFN_EXPLORER | OFN_HIDEREADONLY |OFN_NOREADONLYRETURN; // Call the common dialog function. if (GetSaveFileName(&OpenFileName)) { FILE* f; if (_tfopen_s(&f, OpenFileName.lpstrFile, L"a+") == 0) { int nCount = ListView_GetItemCount(m_hWndList); int i, j; WCHAR wszBuffer[MAX_MSG_LENGTH]; for (i=0; i= nIndex) bRet = true; return bRet; } // // disconnect & destroy all sinks associated with the given App // HRESULT CComSpy::ShutdownApplication(LPCWSTR pwszApplicationName) { CAppInfo * pInfo = m_map[pwszApplicationName]; if (!pInfo) { _ASSERTE(0); // we should never get this unless we have a sink for (at least) the Applicatioin events return E_FAIL; } size_t nElementsRemoved = m_map.erase(pwszApplicationName); _ASSERTE(nElementsRemoved == 1); delete pInfo; return S_OK; } // // this method is called by all of the sinks to add an item to the list box // bool CComSpy::AddEventToList(LONGLONG perfCount, LPCWSTR pwszEvent, LPCWSTR pwszApplication) { long TickCount = 0; if (PerformanceFrequency != 0) TickCount = (long)((1000 * perfCount) / PerformanceFrequency); bool bRet; if (m_bLogToFile) { WCHAR sSep[2]; sSep[0] = m_bCSV ? L',' : L'\t'; sSep[1] = L'\0'; _ASSERTE(m_hFile); WCHAR wszBuffer[MAX_MSG_LENGTH]; ZeroMemory(wszBuffer, sizeof(wszBuffer)); StringCchPrintf(wszBuffer, ARRAYSIZE(wszBuffer), L"%s%s%d%s%s\n", pwszEvent, sSep, TickCount, sSep, pwszApplication); if (m_hFile) { DWORD cbWritten; bRet = (FALSE != WriteFile(m_hFile, wszBuffer, lstrlen(wszBuffer) * sizeof(WCHAR), &cbWritten, NULL)); } } if (m_bShowOnScreen) { int nCount = ListView_GetItemCount(m_hWndList); LV_ITEM item; WCHAR sz[8]; StringCchPrintf(sz, ARRAYSIZE(sz), L"%ld", m_cEvents++); ZeroMemory(&item, sizeof(item)); item.mask = LVIF_TEXT; item.iItem = nCount; item.pszText = sz; item.cchTextMax = lstrlen(sz); ListView_InsertItem(m_hWndList, &item); ListView_SetItemText(m_hWndList, nCount, 1, (LPWSTR)pwszEvent); WCHAR szTick[16]; StringCchPrintf(szTick, ARRAYSIZE(szTick), L"%ld", TickCount); ListView_SetItemText(m_hWndList, nCount, 2, szTick); ListView_SetItemText(m_hWndList, nCount, 3, (LPWSTR)pwszApplication); if (ShouldScroll(nCount)) ListView_EnsureVisible(m_hWndList, nCount, FALSE); } return TRUE; } // // this method is called by all the sinks to add a Named/Value pair to the // list // bool CComSpy::AddParamValueToList(LPCWSTR pwszParamName, LPCWSTR pwszValue) { bool bRet; if (m_bLogToFile) { WCHAR sSep[2]; sSep[0] = m_bCSV ? L',' : L'\t'; sSep[1] = L'\0'; _ASSERTE(m_hFile); WCHAR wszBuffer[MAX_MSG_LENGTH]; ZeroMemory(wszBuffer, sizeof(wszBuffer)); StringCchPrintf(wszBuffer, ARRAYSIZE(wszBuffer), L"%s%s%s%s%s%s\n", sSep, sSep, sSep, pwszParamName,sSep, pwszValue); if (m_hFile) { DWORD cbWritten; bRet = (FALSE != WriteFile(m_hFile, wszBuffer, lstrlen(wszBuffer) * sizeof(WCHAR), &cbWritten, NULL)); } } if (m_bShowOnScreen) { int nCount = ListView_GetItemCount(m_hWndList); LV_ITEM item; item.mask = LVIF_TEXT; item.iItem = nCount; item.pszText = L""; item.cchTextMax = 1; item.iSubItem = 0; int nItem; nItem = ListView_InsertItem(m_hWndList, &item); ListView_SetItemText(m_hWndList, nItem, 4, (LPWSTR)pwszParamName); ListView_SetItemText(m_hWndList, nItem, 5, (LPWSTR)pwszValue); if (ShouldScroll(nCount)) ListView_EnsureVisible(m_hWndList, nItem, FALSE); } return TRUE; } // // show the select Applications dialog // LRESULT CComSpy::OnSelectApplications(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { CSelectEventsDlg dlg(&m_map, m_pSysAppInfo, this); dlg.DoModal(); return 0; } LRESULT CComSpy::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; // continue processing // // clean up our application information // MapStringToAppInfo::iterator iter; CAppInfo * pInfo; for (iter = m_map.begin(); iter != m_map.end(); ++iter) { pInfo = (*iter).second; delete pInfo; } m_map.clear(); if(m_pSysAppInfo) delete m_pSysAppInfo; if (m_hFont) { DeleteObject(m_hFont); m_hFont = NULL; } m_bLogToFile = FALSE; if (m_hFile) { CloseHandle(m_hFile); m_hFile = NULL; } m_cEvents = 0; m_bShowGridLines = TRUE; return 0; } // // show only the ChooseFont property page // LRESULT CComSpy::OnChooseFont(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { HRESULT hr = S_OK; CComPtr pUnk; ControlQueryInterface(IID_PPV_ARGS(&pUnk)); _ASSERTE(pUnk != NULL); LPCWSTR pwszTitle = L"Com Spy - Choose Font"; hr = OleCreatePropertyFrame(m_hWnd, m_rcPos.top, m_rcPos.left, pwszTitle, 1, &pUnk.p, 1, (LPCLSID)&CLSID_StockFontPage, // Ok, OleCreatePropertyFrame will not write to this LOCALE_USER_DEFAULT, 0, 0); return 0; } STDMETHODIMP CComSpy::get_LogFile(BSTR * pVal) { *pVal = m_sLogFile.Copy(); return S_OK; } STDMETHODIMP CComSpy::put_LogFile(BSTR newVal) { HANDLE hTemp; hTemp = CreateFile(newVal, GENERIC_WRITE, 0, (LPSECURITY_ATTRIBUTES) NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL); if (hTemp) { if (m_hFile) { CloseHandle(m_hFile); } m_hFile = hTemp; } else return E_INVALIDARG; m_sLogFile = newVal; return S_OK; } STDMETHODIMP CComSpy::get_ShowGridLines(BOOL * pVal) { *pVal = m_bShowGridLines; return S_OK; } STDMETHODIMP CComSpy::put_ShowGridLines(BOOL newVal) { m_bShowGridLines = newVal; DWORD dwStyle = ListView_GetExtendedListViewStyle(m_hWndList); (m_bShowGridLines) ? dwStyle |= LVS_EX_GRIDLINES : dwStyle &= ~LVS_EX_GRIDLINES; ListView_SetExtendedListViewStyle(m_hWndList, dwStyle); FireViewChange(); return S_OK; } STDMETHODIMP CComSpy::get_Audit(BOOL * pVal) { *pVal = m_bAudit; return S_OK; } STDMETHODIMP CComSpy::put_Audit(BOOL newVal) { m_bAudit = newVal; EnableAudit(m_bAudit); return S_OK; } STDMETHODIMP CComSpy::get_ColWidth(short nColumn, long * pVal) { _ASSERTE(m_hWndList); _ASSERTE(nColumn >= 0 && nColumn <= NUMBER_COLUMNS); *pVal = ListView_GetColumnWidth(m_hWndList, nColumn); return S_OK; } STDMETHODIMP CComSpy::put_ColWidth(short nColumn, long newVal) { if (nColumn >= NUMBER_COLUMNS) return E_INVALIDARG; m_nWidth[nColumn] = newVal; ListView_SetColumnWidth(m_hWndList, nColumn, newVal); FireViewChange(); return S_OK; } HRESULT CComSpy::IPersistStreamInit_Load(LPSTREAM pStm, const ATL_PROPMAP_ENTRY* pMap) { ULONG cbRead; // read in the version UINT nVersion; pStm->Read(&nVersion, sizeof(UINT), &cbRead); if (nVersion != 4) { ::MessageBox(m_hWndList, L"The saved information is from a different version of the control.\n\nThe saved state will have to be discarded.", L"COM Spy", MB_ICONINFORMATION); return S_OK; } // get log file size long lLen; pStm->Read(&lLen, sizeof(long), &cbRead); // read in the chars for the log name char * pLog = new char[lLen+1]; ZeroMemory(pLog, lLen+1); pStm->Read((void*)pLog, lLen, &cbRead); m_sLogFile = pLog; delete [] pLog; // gridlines pStm->Read(&m_bShowGridLines, sizeof(m_bShowGridLines),&cbRead); put_ShowGridLines(m_bShowGridLines); // show on screen pStm->Read(&m_bShowOnScreen, sizeof(m_bShowOnScreen),&cbRead); put_ShowOnScreen(m_bShowOnScreen); // log to file pStm->Read(&m_bLogToFile, sizeof(m_bLogToFile),&cbRead); put_LogToFile(m_bLogToFile); // csv files pStm->Read(&m_bCSV, sizeof(m_bCSV), &cbRead); // csv files pStm->Read(&m_bAudit, sizeof(m_bAudit), &cbRead); EnableAudit(m_bAudit); // read the col widths int i; long nWidth; for (i=0;iRead(&nWidth, sizeof(nWidth), &cbRead); put_ColWidth(i, nWidth); } BOOL bCustomFont = FALSE; pStm->Read(&bCustomFont, sizeof(bCustomFont),&cbRead); if (bCustomFont) { if (!m_pFont) { //create an IFontDisp HRESULT hr= CoCreateInstance(CLSID_StdFont, NULL, CLSCTX_ALL, IID_PPV_ARGS(&m_pFont)); _ASSERTE(SUCCEEDED(hr)); } if (m_pFont) { CComPtr spFontSt; m_pFont->QueryInterface(IID_PPV_ARGS(&spFontSt)); _ASSERTE(spFontSt); spFontSt->Load(pStm); if (m_hFont) // should I tell the list that I deleted its font? DeleteObject(m_hFont); CComPtr spFont; m_pFont->QueryInterface(IID_PPV_ARGS(&spFont)); _ASSERTE(spFont); m_hFont = CreateHFontFromIFont(spFont); } } return S_OK; } HRESULT CComSpy::IPersistStreamInit_Save(LPSTREAM pStm, BOOL /* fClearDirty */, const ATL_PROPMAP_ENTRY* pMap) { _ASSERTE(this); _ASSERTE(m_hWndList); ULONG cbWritten = 0; // write a version UINT nVersion = 4; pStm->Write(&nVersion, sizeof(UINT), &cbWritten); // write the log file size long nChars = m_sLogFile.Length(); pStm->Write(&nChars, sizeof(long), &cbWritten); _ASSERTE(cbWritten == sizeof(long)); // write the log file name pStm->Write((LPCWSTR)m_sLogFile, m_sLogFile.Length(), &cbWritten); // write the BOOL if gridlines should be shown pStm->Write(&m_bShowGridLines, sizeof(m_bShowGridLines), &cbWritten); // write the BOOL if the user wants to see the messages pStm->Write(&m_bShowOnScreen, sizeof(m_bShowOnScreen), &cbWritten); // write the BOOL if the user wants to log the messages pStm->Write(&m_bLogToFile, sizeof(m_bLogToFile), &cbWritten); // write the BOOL if we have CSV files pStm->Write(&m_bCSV, sizeof(m_bCSV), &cbWritten); // write the BOOL if Auditing is enabled pStm->Write(&m_bAudit, sizeof(m_bAudit), &cbWritten); // write the col widths int i; long nWidth; for (i=0;iWrite(&nWidth, sizeof(nWidth), &cbWritten); } // ask the font to persist itself in the stream BOOL bCustomFont; if (m_pFont) { bCustomFont = TRUE; pStm->Write(&bCustomFont, sizeof(bCustomFont), &cbWritten); CComPtr pPersistStream; m_pFont->QueryInterface(IID_PPV_ARGS(&pPersistStream)); _ASSERTE(pPersistStream); pPersistStream->Save(pStm, FALSE); } else { bCustomFont = FALSE; pStm->Write(&bCustomFont, sizeof(bCustomFont), &cbWritten); } return S_OK; } HRESULT CComSpy::Close( DWORD dwSaveOption ) { return IOleObject_Close(dwSaveOption); } HFONT CComSpy::CreateHFontFromIFont(__in IFont* pFont) { _ASSERTE(pFont); HFONT hFont; LOGFONT lf; ZeroMemory(&lf, sizeof(lf)); CComBSTR bstr; pFont->get_Name(&bstr); StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), bstr.m_str); CY cy; pFont->get_Size(&cy); HDC hDC = ::GetDC(NULL); _ASSERTE(hDC); long lCaps = GetDeviceCaps(hDC, LOGPIXELSY); lf.lfHeight = -MulDiv(cy.Hi, lCaps, 72); lf.lfHeight += -MulDiv(cy.Lo, lCaps, 720000); ::ReleaseDC(NULL, hDC); short sVal; pFont->get_Weight(&sVal); lf.lfWeight = sVal; BOOL bFlag; pFont->get_Italic(&bFlag); lf.lfItalic = bFlag; pFont->get_Underline(&bFlag); lf.lfUnderline = bFlag; pFont->get_Strikethrough(&bFlag); lf.lfStrikeOut = bFlag; pFont->get_Charset(&sVal); lf.lfCharSet = (BYTE)sVal; hFont = CreateFontIndirect(&lf); return hFont; } STDMETHODIMP CComSpy::SelectApplications() { BOOL bHandled = TRUE; OnSelectApplications(0,0,0,bHandled); return S_OK; } STDMETHODIMP CComSpy::SaveToFile() { BOOL bHandled = TRUE; OnSave(0,0,0,bHandled); return S_OK; } STDMETHODIMP CComSpy::ClearAllEvents() { BOOL bHandled = TRUE; OnClear(0,0,0,bHandled); return S_OK; } STDMETHODIMP CComSpy::About() { BOOL bHandled = TRUE; OnAbout(0,0,0,bHandled); return S_OK; } STDMETHODIMP CComSpy::get_LogToFile(BOOL * pVal) { *pVal = m_bLogToFile; return S_OK; } STDMETHODIMP CComSpy::put_LogToFile(BOOL newVal) { m_bLogToFile = newVal; if (m_bLogToFile) { if (m_sLogFile.Length() == 0) { BOOL bHandled = TRUE; OnChooseLogFile(0,0,0,bHandled); if (m_sLogFile.Length() == 0) return 0; } if (m_hFile) { CloseHandle(m_hFile); m_hFile = NULL; } m_hFile = CreateFile(m_sLogFile, GENERIC_WRITE, 0, (LPSECURITY_ATTRIBUTES) NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL); if (!m_hFile) { m_bLogToFile = FALSE; return E_FAIL; } } else { if (m_hFile) { CloseHandle(m_hFile); m_hFile = NULL; } } return S_OK; } STDMETHODIMP CComSpy::ChooseFont() { BOOL bHandled = TRUE; OnChooseFont(0,0,0,bHandled); return S_OK; } STDMETHODIMP CComSpy::get_ShowOnScreen(BOOL * pVal) { *pVal = m_bShowOnScreen; return S_OK; } STDMETHODIMP CComSpy::put_ShowOnScreen(BOOL newVal) { m_bShowOnScreen = newVal; return S_OK; } STDMETHODIMP CComSpy::ChooseLogFile(BSTR * sLogFileName, BOOL * bCanceled) { *bCanceled = TRUE; BOOL bHandled = TRUE; OnChooseLogFile(0,0,0,bHandled); if (m_sLogFile.Length() == 0) { return S_OK; } *sLogFileName = ::SysAllocString(m_sLogFile.m_str); *bCanceled = FALSE; return S_OK; } // // loop through the ROT and add Application names // to the debug menu // bool CComSpy::AddRunningAspsToDebugMenu(HMENU hMenu) { // // remove the menu item // RemoveMenu(hMenu, 0, MF_BYPOSITION); HRESULT hr = E_FAIL; CComPtr spMtsGrp; hr = CoCreateInstance (CLSID_MtsGrp, NULL, CLSCTX_ALL, IID_PPV_ARGS(&spMtsGrp)); if (!spMtsGrp) { _ASSERTE(0); return false; } long lApplications; spMtsGrp->Refresh(); // its important to call this! spMtsGrp->get_Count(&lApplications); CComPtr spUnk; CComPtr spEvents; long lPID; WCHAR szBuf[128]; for (int i=0; iItem(i, &spUnk); _ASSERTE(spUnk); spUnk->QueryInterface(IID_PPV_ARGS(&spEvents)); _ASSERTE(spEvents); if (SUCCEEDED(hr)) { CComBSTR bstrName; spEvents->get_PackageName(&bstrName.m_str); spEvents->GetProcessID(&lPID); ZeroMemory(szBuf, sizeof(szBuf)); if (bstrName.m_str) { StringCchPrintf(szBuf, ARRAYSIZE(szBuf), L"%s - PID: %ld", bstrName.m_str, lPID); int nRet = InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING, ID_DEBUG_BEGIN + i, szBuf); } } spUnk.Release(); spEvents.Release(); } return true; } // // user wants to debug a Application -- // // NOTE: This is designed to work with Microsoft Developer Studio // if you want to add support for another tool, modify the // ShellExecute() line below. This is alson non-robust in // the sense that it requires MSDEV.EXE to be in the path // and set up correctly. // LRESULT CComSpy::OnDebugApplication(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { HCURSOR hBusy = LoadCursor(NULL, IDC_WAIT); HCURSOR hOldCur = SetCursor(hBusy); WCHAR szBuf[128]; ZeroMemory(szBuf, sizeof(szBuf)); int nChars; _ASSERTE(m_hMenuDebug); nChars = GetMenuString(m_hMenuDebug, wID, szBuf, 128, MF_BYCOMMAND); if (nChars) { int nCount = lstrlen(szBuf); LPWSTR p = szBuf + nCount; while (*p-- != ':' && nCount) { nCount --; } if (nCount == 0) { SetCursor(hOldCur); return 0; } p+=3; WCHAR wszBuffer[MAX_PATH]; StringCchPrintf(wszBuffer, MAX_PATH, L"-p %s -e %s", p, p); HINSTANCE hInst = ShellExecute( NULL, L"open", L"msdev", wszBuffer, NULL, SW_SHOWNORMAL); } SetCursor(hOldCur); return 0; } // // Enable/Disable auditing // HRESULT CComSpy::EnableAudit(BOOL bEnable) { if (!bEnable) { m_spSqlAudit.Release(); return S_OK; } if (m_spSqlAudit) // make EnableAudit() idempotent -- we are already enabled return S_OK; HRESULT hr; hr = CoCreateInstance(CLSID_ComSpyAudit, NULL, CLSCTX_ALL, IID_PPV_ARGS(&m_spSqlAudit)); if (SUCCEEDED(hr)) { // // these hard coded strings (user and pw) should be looked up in the registry for a production // app hr = m_spSqlAudit->Init(L"ComSpyAudit", L"sa", L""); if (FAILED(hr)) { LPCWSTR pwszMsg = L"Unable to connect to DSN 'ComSpyAudit'.\n" L"Make sure that the DSN exists, the Database has the\n" L"schema contained in ComSpyAudit.SQL, and you have\n" L"the permission to access the database."; ::MessageBox(m_hWndList, pwszMsg, L"ComSpy", MB_ICONSTOP); m_spSqlAudit.Release(); } } else { ::MessageBox(m_hWndList, L"Unable to create the ComSpyAudit component!", L"ComSpy", MB_ICONSTOP); } return hr; } HRESULT CComSpy::putref_Font(__in IFontDisp* pFontDisp) { if (!pFontDisp) return E_POINTER; CComPtr spFont; if (SUCCEEDED(pFontDisp->QueryInterface(IID_PPV_ARGS(&spFont)))) { if (m_hFont) { DeleteObject(m_hFont); m_hFont = NULL; } m_hFont = CreateHFontFromIFont(spFont); if (m_hFont) { ::SendMessage(m_hWndList, WM_SETFONT, (WPARAM)m_hFont, 0L); } } if (FireOnRequestEdit(DISPID_FONT) == S_FALSE) return S_FALSE; m_pFont = pFontDisp; m_bRequiresSave = TRUE; FireOnChanged(DISPID_FONT); FireViewChange(); return S_OK; }