2025-11-28 00:35:46 +09:00

1167 lines
31 KiB
C++

// 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 <comsvcs.h>
#include "ComSpyCtl.h"
#include "ComSpyAudit.h"
#include "AppInfo.h"
#include "CComSpy.h"
#include "selecteventsdlg.h"
#include "commdlg.h"
#include <time.h>
#include "shellapi.h"
#include <strsafe.h>
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<NUMBER_COLUMNS;i++)
{
m_nWidth[i] = 60;
}
m_hFont = NULL;
m_bShowOnScreen = TRUE;
m_bCSV = FALSE;
m_bAudit = FALSE;
m_spSqlAudit = NULL;
CComBSTR bstrAppName(L"SysApp");
m_pSysAppInfo = new CAppInfo((LPCWSTR)bstrAppName, this);
_ASSERTE(m_pSysAppInfo);
}
HRESULT CComSpy::OnDrawAdvanced(ATL_DRAWINFO& di)
{
return S_OK;
}
LRESULT CComSpy::OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
HMENU hMenu = LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_SPYMENU));
_ASSERTE(hMenu != NULL);
if (!hMenu)
return 0;
POINT local;
local.x = LOWORD(lParam);
local.y = HIWORD(lParam);
ClientToScreen(&local);
HMENU hPopup = GetSubMenu(hMenu, 0);
_ASSERTE(hPopup != NULL);
if (!hPopup)
return 0;
TrackPopupMenu(hPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, local.x, local.y, NULL, m_hWndList, NULL);
return 0;
}
LRESULT CComSpy::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
RECT rc;
GetWindowRect(&rc);
rc.right -= rc.left;
rc.bottom -= rc.top;
rc.top = rc.left = 0;
DWORD dwStyle = WS_VISIBLE|WS_CHILD|LVS_REPORT|LVS_SINGLESEL|WS_BORDER;
if (!m_hWndList)
m_hWndList = m_ctlSysListView32.Create(m_hWnd, rc, L"", dwStyle);
_ASSERTE(m_hWndList);
put_ShowGridLines(m_bShowGridLines);
//
// we always want the list to be Full Row Select --
// note: this only works if the user has IE 3.0 installed
//
dwStyle = ListView_GetExtendedListViewStyle(m_hWndList);
dwStyle |= LVS_EX_FULLROWSELECT;
ListView_SetExtendedListViewStyle(m_hWndList, dwStyle);
//
// create the columns in our list
//
LV_COLUMN col;
ZeroMemory(&col, sizeof(col));
col.mask = LVCF_TEXT|LVCF_WIDTH;
col.fmt = LVCFMT_LEFT;
int i;
for (i=0;i<NUMBER_COLUMNS;i++)
{
col.cx = m_nWidth[i];
col.pszText = (LPWSTR)pwszColNames[i]; // Ok, ListView_InsertColumn does not write to this string
col.cchTextMax = lstrlen(col.pszText);
ListView_InsertColumn(m_hWndList, i, &col);
}
QueryPerformanceFrequency((LARGE_INTEGER *)&PerformanceFrequency);
if (m_hFont)
{
// this is set if the container app has set our properties using the property bag
::SendMessage(m_hWndList, WM_SETFONT, (WPARAM)m_hFont, MAKELPARAM(TRUE,0));
}
return 0;
}
//
// update the UI in menus
//
LRESULT CComSpy::OnInitMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
HMENU hMenu = (HMENU)wParam;
CComBSTR temp = "Log to File ";
if (m_sLogFile.Length() > 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<nCount; i++)
{
for (j=0; j < 4; j++)
{
ListView_GetItemText(m_hWndList, i, j, wszBuffer, ARRAYSIZE(wszBuffer));
_ftprintf(f, L"%s\t",wszBuffer);
}
while ( i < nCount - 1)
{
i++; // move to next column
// now get the name/value pairs
ListView_GetItemText(m_hWndList, i, 4, wszBuffer, ARRAYSIZE(wszBuffer));
if (*wszBuffer)
{
_ftprintf(f, L"\n\t\t\t\t%s\t", wszBuffer);
ListView_GetItemText(m_hWndList, i, 5, wszBuffer, ARRAYSIZE(wszBuffer));
_ftprintf(f, L"%s",wszBuffer);
}
else
{
i--;
_ftprintf(f, L"\n");
break;
}
}
}
fclose(f);
}
}
return 0;
}
//
// given the index to the list, we return TRUE if the index
// should scroll -- this occurs when the user is looking
// at the last element in the list. If they have scrolled
// up to look at a previous element in the list, then we
// don't scroll when an event is added
//
bool CComSpy::ShouldScroll(int nIndex)
{
bool bRet = false;
int nCountPage = ListView_GetCountPerPage(m_hWndList);
int nTopIndex = ListView_GetTopIndex(m_hWndList);
if (nTopIndex + nCountPage>= 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<IUnknown> 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;i<NUMBER_COLUMNS;i++)
{
pStm->Read(&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<IPersistStream> 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<IFont> 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;i<NUMBER_COLUMNS;i++)
{
get_ColWidth(i, &nWidth);
_ASSERTE(nWidth);
pStm->Write(&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<IPersistStream> 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 <No Running Applications> menu item
//
RemoveMenu(hMenu, 0, MF_BYPOSITION);
HRESULT hr = E_FAIL;
CComPtr<IMtsGrp> 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<IUnknown> spUnk;
CComPtr<IMtsEvents> spEvents;
long lPID;
WCHAR szBuf[128];
for (int i=0; i<lApplications; i++)
{
spMtsGrp->Item(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<IFont> 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;
}