472 lines
15 KiB
C++
472 lines
15 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 "COMSpy.h"
|
|
#include "ComSpyCtl.h"
|
|
#include "SpyCon.h"
|
|
|
|
static const LPCWSTR COMSPY_REG_KEY = L"Software\\Microsoft\\COMSpy";
|
|
static const LPCWSTR REG_VALUE_LEFT = L"Left";
|
|
static const LPCWSTR REG_VALUE_TOP = L"Top";
|
|
static const LPCWSTR REG_VALUE_RIGHT = L"Right";
|
|
static const LPCWSTR REG_VALUE_BOTTOM = L"Bottom";
|
|
static const LPCWSTR REG_VALUE_SHOW_WINDOW = L"ShowWindow";
|
|
static const LPCWSTR REG_VALUE_ALWAYS_ON_TOP = L"AlwaysOnTop";
|
|
static const LPCWSTR REG_VALUE_SAVE_ON_EXIT = L"SaveOnExit";
|
|
static const LPCWSTR REG_VALUE_CONTROL_PROPERTIES = L"ControlProperties";
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSpyCon
|
|
|
|
|
|
STDMETHODIMP CSpyCon::Run()
|
|
{
|
|
// Create our window
|
|
RECT rcPos = { CW_USEDEFAULT, 0, 0, 0 };
|
|
|
|
CString sWindowTitle;
|
|
BOOL bResult = sWindowTitle.LoadStringW(IDS_WINDOW_TITLE);
|
|
_ASSERTE(bResult);
|
|
|
|
HMENU hMenu = LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MENU1));
|
|
_ASSERTE(hMenu);
|
|
|
|
HWND hwnd = Create(NULL, rcPos, sWindowTitle, WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, hMenu);
|
|
_ASSERTE(hwnd);
|
|
|
|
// Set its icon
|
|
HICON hIcon = LoadIcon(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDI_MAIN));
|
|
_ASSERTE(hIcon);
|
|
SetIcon(hIcon, TRUE);
|
|
|
|
// Create the spy control
|
|
HRESULT hr = CoCreateInstance(CLSID_ComSpy, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&m_spOleObject));
|
|
if (FAILED(hr))
|
|
{
|
|
MessageBox(L"CoCreateInstance failed");
|
|
return hr;
|
|
}
|
|
_ASSERTE(m_spOleObject);
|
|
|
|
m_spOleObject->SetClientSite(this);
|
|
|
|
hr = m_spOleObject->QueryInterface(IID_PPV_ARGS(&m_spSpy));
|
|
_ASSERTE(SUCCEEDED(hr) && m_spSpy);
|
|
|
|
// Get our window state from the registry
|
|
HKEY hKey = NULL;
|
|
(void)RegCreateKeyEx(HKEY_LOCAL_MACHINE, COMSPY_REG_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE, NULL, &hKey, NULL);
|
|
if (hKey)
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD dwSize = sizeof(dwValue);
|
|
if ((ERROR_SUCCESS == RegQueryValueEx(hKey, REG_VALUE_LEFT, NULL, &dwType, (LPBYTE)&dwValue, &dwSize)) &&
|
|
(dwType == REG_DWORD) && (dwSize == sizeof(dwValue)))
|
|
{
|
|
m_wp.rcNormalPosition.left = (LONG)dwValue;
|
|
}
|
|
|
|
dwSize = sizeof(dwValue);
|
|
if ((ERROR_SUCCESS == RegQueryValueEx(hKey, REG_VALUE_TOP, NULL, &dwType, (LPBYTE)&dwValue, &dwSize)) &&
|
|
(dwType == REG_DWORD) && (dwSize == sizeof(dwValue)))
|
|
{
|
|
m_wp.rcNormalPosition.top = (LONG)dwValue;
|
|
}
|
|
|
|
dwSize = sizeof(dwValue);
|
|
if ((ERROR_SUCCESS == RegQueryValueEx(hKey, REG_VALUE_RIGHT, NULL, &dwType, (LPBYTE)&dwValue, &dwSize)) &&
|
|
(dwType == REG_DWORD) && (dwSize == sizeof(dwValue)))
|
|
{
|
|
m_wp.rcNormalPosition.right = (LONG)dwValue;
|
|
}
|
|
|
|
dwSize = sizeof(dwValue);
|
|
if ((ERROR_SUCCESS == RegQueryValueEx(hKey, REG_VALUE_BOTTOM, NULL, &dwType, (LPBYTE)&dwValue, &dwSize)) &&
|
|
(dwType == REG_DWORD) && (dwSize == sizeof(dwValue)))
|
|
{
|
|
m_wp.rcNormalPosition.bottom = (LONG)dwValue;
|
|
}
|
|
|
|
dwSize = sizeof(dwValue);
|
|
if ((ERROR_SUCCESS == RegQueryValueEx(hKey, REG_VALUE_SHOW_WINDOW, NULL, &dwType, (LPBYTE)&dwValue, &dwSize)) &&
|
|
(dwType == REG_DWORD) && (dwSize == sizeof(dwValue)))
|
|
{
|
|
m_wp.showCmd = (UINT)dwValue;
|
|
}
|
|
|
|
dwSize = sizeof(dwValue);
|
|
if ((ERROR_SUCCESS == RegQueryValueEx(hKey, REG_VALUE_ALWAYS_ON_TOP, NULL, &dwType, (LPBYTE)&dwValue, &dwSize)) &&
|
|
(dwType == REG_DWORD) && (dwSize == sizeof(dwValue)))
|
|
{
|
|
m_bAlwaysOnTop = (dwValue != 0);
|
|
}
|
|
|
|
// Using OnAlwaysOnTop to handle the always on top option, which toggles the value
|
|
m_bAlwaysOnTop = !m_bAlwaysOnTop;
|
|
BOOL bHandledIgnored = TRUE;
|
|
OnAlwaysOnTop(0,0,0,bHandledIgnored);
|
|
|
|
dwSize = sizeof(dwValue);
|
|
if ((ERROR_SUCCESS == RegQueryValueEx(hKey, REG_VALUE_SAVE_ON_EXIT, NULL, &dwType, (LPBYTE)&dwValue, &dwSize)) &&
|
|
(dwType == REG_DWORD) && (dwSize == sizeof(dwValue)))
|
|
{
|
|
m_bSaveOnExit = (dwValue != 0);
|
|
}
|
|
|
|
// Get the control properties persisted in a stream
|
|
dwSize = 0;
|
|
if ((ERROR_SUCCESS == RegQueryValueEx(hKey, REG_VALUE_CONTROL_PROPERTIES, NULL, &dwType, NULL, &dwSize)) &&
|
|
(dwType == REG_BINARY))
|
|
{
|
|
HGLOBAL hGlobal = GlobalAlloc(GPTR, dwSize);
|
|
if (hGlobal)
|
|
{
|
|
BYTE* pbValue = (BYTE*)GlobalLock(hGlobal);
|
|
_ASSERTE(pbValue);
|
|
LONG lResult = RegQueryValueEx(hKey, REG_VALUE_CONTROL_PROPERTIES, NULL, &dwType, pbValue, &dwSize);
|
|
GlobalUnlock(hGlobal);
|
|
|
|
CComPtr<IStream> spStream;
|
|
if ((ERROR_SUCCESS == lResult) &&
|
|
SUCCEEDED(CreateStreamOnHGlobal(hGlobal, TRUE, &spStream)))
|
|
{
|
|
CComPtr<IPersistStreamInit> spPersist;
|
|
hr = m_spSpy->QueryInterface(IID_PPV_ARGS(&spPersist));
|
|
_ASSERTE(SUCCEEDED(hr) && spPersist);
|
|
|
|
// Best effort (ignore failure)
|
|
(void)spPersist->Load(spStream);
|
|
}
|
|
else
|
|
{
|
|
GlobalFree(hGlobal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(( m_wp.rcNormalPosition.right - m_wp.rcNormalPosition.left < 10) || (m_wp.rcNormalPosition.bottom - m_wp.rcNormalPosition.top < 10)))
|
|
SetWindowPlacement(&m_wp);
|
|
else
|
|
ShowWindow(SW_SHOWNORMAL);
|
|
|
|
GetClientRect(&rcPos);
|
|
MSG msg;
|
|
return m_spOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, &msg, this, 0, m_hWnd, &rcPos);
|
|
}
|
|
|
|
//
|
|
// show the select filter dialog
|
|
//
|
|
LRESULT CSpyCon::OnSelectFilter(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
_ASSERTE(m_spSpy);
|
|
|
|
m_spSpy->SelectApplications();
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// the user clicks on the system menu
|
|
//
|
|
LRESULT CSpyCon::OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
bHandled = FALSE; // always do default processing
|
|
|
|
if (wParam == SC_CLOSE)
|
|
OnExit(NULL, NULL, NULL, bHandled);
|
|
|
|
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 CSpyCon::OnLogToFile(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
_ASSERTE(m_spSpy);
|
|
|
|
BOOL bVal;
|
|
m_spSpy->get_LogToFile(&bVal);
|
|
bVal = !bVal;
|
|
m_spSpy->put_LogToFile(bVal);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// User wants to choose a log file -- show the common dialog
|
|
//
|
|
LRESULT CSpyCon::OnChooseLogFile(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
_ASSERTE(m_spSpy);
|
|
|
|
CComBSTR bstrFileName;
|
|
BOOL bCanceled;
|
|
m_spSpy->ChooseLogFile(&bstrFileName, &bCanceled);
|
|
return 0;
|
|
|
|
}
|
|
|
|
//
|
|
// toggle the save on exit flag
|
|
//
|
|
LRESULT CSpyCon::OnToggleSaveOnExit(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
|
|
{
|
|
m_bSaveOnExit = !m_bSaveOnExit;
|
|
// For most of the options, we do not save until exit or "Save Settings Now" is clicked.
|
|
// If Save On Exit is disabled, however, we need to save this now. Otherwise, this
|
|
// option won't be saved and will still be enabled the next time we run.
|
|
if (!m_bSaveOnExit)
|
|
{
|
|
// Best effort (ignore failures)
|
|
HKEY hKey = NULL;
|
|
(void)RegCreateKeyEx(HKEY_LOCAL_MACHINE, COMSPY_REG_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
|
|
if (hKey)
|
|
{
|
|
DWORD dwValue = 0;
|
|
(void)RegSetValueEx(hKey, REG_VALUE_SAVE_ON_EXIT, NULL, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// toggle the show on screen flag
|
|
//
|
|
LRESULT CSpyCon::OnToggleShowOnScreen(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
_ASSERTE(m_spSpy);
|
|
|
|
BOOL bVal;
|
|
m_spSpy->get_ShowOnScreen(&bVal);
|
|
bVal = !bVal;
|
|
m_spSpy->put_ShowOnScreen(bVal);
|
|
return 0;
|
|
|
|
}
|
|
//
|
|
// update the UI in menus
|
|
//
|
|
LRESULT CSpyCon::OnInitMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
_ASSERTE(m_spSpy);
|
|
|
|
HMENU hMenu = (HMENU)wParam;
|
|
CComBSTR temp = "&Log to File ";
|
|
CComBSTR bstrFileName;
|
|
m_spSpy->get_LogFile(&bstrFileName);
|
|
if (bstrFileName.Length() > 5)
|
|
temp += bstrFileName;
|
|
else
|
|
temp = "&Log To file...";
|
|
|
|
ModifyMenu(hMenu, ID_LOG, MF_BYCOMMAND|MF_STRING, ID_LOG, temp);
|
|
BOOL bVal;
|
|
m_spSpy->get_LogToFile(&bVal);
|
|
CheckMenuItem(hMenu, ID_LOG, bVal ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED);
|
|
m_spSpy->get_ShowGridLines(&bVal);
|
|
CheckMenuItem(hMenu, ID_OPTIONS_GRID_LINES, bVal ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED);
|
|
m_spSpy->get_ShowOnScreen(&bVal);
|
|
CheckMenuItem(hMenu, ID_SHOW_ON_SCREEN, bVal ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED);
|
|
CheckMenuItem(hMenu, IDM_ON_TOP, m_bAlwaysOnTop ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED);
|
|
CheckMenuItem(hMenu, ID_SAVE_ON_EXIT, m_bSaveOnExit ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// show/hide gridlines in the list
|
|
//
|
|
// NOTE: This will only work if the user has installed IE 3.0 or greater
|
|
//
|
|
LRESULT CSpyCon::OnToggleGridLines(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
_ASSERTE(m_spSpy);
|
|
|
|
BOOL bVal;
|
|
m_spSpy->get_ShowGridLines(&bVal);
|
|
bVal = !bVal;
|
|
m_spSpy->put_ShowGridLines(bVal);
|
|
return 0;
|
|
}
|
|
//
|
|
// Toggle the Always on top option
|
|
//
|
|
LRESULT CSpyCon::OnAlwaysOnTop(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
m_bAlwaysOnTop = !m_bAlwaysOnTop;
|
|
if (m_bAlwaysOnTop)
|
|
SetWindowPos(HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE);
|
|
else
|
|
SetWindowPos(HWND_NOTOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE);
|
|
return 0;
|
|
}
|
|
//
|
|
// show the standard Shell About box
|
|
//
|
|
LRESULT CSpyCon::OnAbout(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
_ASSERTE(m_spSpy);
|
|
|
|
m_spSpy->About();
|
|
return 0;
|
|
}
|
|
//
|
|
// pick the font to use in the list
|
|
//
|
|
LRESULT CSpyCon::OnChooseFont(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
_ASSERTE(m_spSpy);
|
|
|
|
m_spSpy->ChooseFont();
|
|
return 0;
|
|
}
|
|
//
|
|
// called on a WM_CLOSE & WM_SYSCOMMAND (SC_CLOSE) message. If appropriate, save settings
|
|
// and then destroy the window
|
|
//
|
|
LRESULT CSpyCon::OnExit(WORD /*wNotifyCode*/, WORD /* wID */, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
|
|
{
|
|
if (m_bSaveOnExit)
|
|
SaveSettings();
|
|
|
|
m_spOleObject->Close(OLECLOSE_NOSAVE);
|
|
m_spOleObject.Release();
|
|
m_spSpy.Release();
|
|
DestroyWindow();
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// save current settings to the registry
|
|
//
|
|
LRESULT CSpyCon::OnSaveNow(WORD /*wNotifyCode*/, WORD /* wID */, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
|
|
{
|
|
SaveSettings();
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// clear the list box
|
|
//
|
|
LRESULT CSpyCon::OnClear(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
_ASSERTE(m_spSpy);
|
|
|
|
m_spSpy->ClearAllEvents();
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// save the items in the list box to the log file
|
|
//
|
|
LRESULT CSpyCon::OnSave(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
|
|
{
|
|
_ASSERTE(m_spSpy);
|
|
|
|
m_spSpy->SaveToFile();
|
|
return 0;
|
|
|
|
}
|
|
//
|
|
// saves settings. asks the control fro a stream to save its state
|
|
//
|
|
HRESULT CSpyCon::SaveSettings()
|
|
{
|
|
_ASSERTE(m_spSpy);
|
|
|
|
// Best effort (ignore failures)
|
|
HKEY hKey = NULL;
|
|
(void)RegCreateKeyEx(HKEY_LOCAL_MACHINE, COMSPY_REG_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
|
|
if (hKey)
|
|
{
|
|
DWORD dwValue = (DWORD)m_wp.rcNormalPosition.left;
|
|
(void)RegSetValueEx(hKey, REG_VALUE_LEFT, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
|
|
|
|
dwValue = (DWORD)m_wp.rcNormalPosition.top;
|
|
(void)RegSetValueEx(hKey, REG_VALUE_TOP, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
|
|
|
|
dwValue = (DWORD)m_wp.rcNormalPosition.right;
|
|
(void)RegSetValueEx(hKey, REG_VALUE_RIGHT, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
|
|
|
|
dwValue = (DWORD)m_wp.rcNormalPosition.bottom;
|
|
(void)RegSetValueEx(hKey, REG_VALUE_BOTTOM, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
|
|
|
|
dwValue = (DWORD)m_wp.showCmd;
|
|
(void)RegSetValueEx(hKey, REG_VALUE_SHOW_WINDOW, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
|
|
|
|
dwValue = m_bAlwaysOnTop ? 1 : 0;
|
|
(void)RegSetValueEx(hKey, REG_VALUE_ALWAYS_ON_TOP, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
|
|
|
|
dwValue = m_bSaveOnExit ? 1 : 0;
|
|
(void)RegSetValueEx(hKey, REG_VALUE_SAVE_ON_EXIT, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
|
|
|
|
CComPtr<IPersistStreamInit> spPersist;
|
|
HRESULT hr = m_spSpy->QueryInterface(IID_PPV_ARGS(&spPersist));
|
|
_ASSERTE(SUCCEEDED(hr) && spPersist);
|
|
|
|
CComPtr<IStream> spStream;
|
|
if (SUCCEEDED(CreateStreamOnHGlobal(NULL, TRUE, &spStream)))
|
|
{
|
|
if (SUCCEEDED(spPersist->Save(spStream, TRUE)))
|
|
{
|
|
HGLOBAL hGlobal = NULL;
|
|
hr = GetHGlobalFromStream(spStream, &hGlobal);
|
|
_ASSERTE(SUCCEEDED(hr) && spStream);
|
|
|
|
BYTE* pbValue = (BYTE *)GlobalLock(hGlobal);
|
|
_ASSERTE(pbValue);
|
|
|
|
DWORD dwSize = (DWORD)GlobalSize(hGlobal);
|
|
(void)RegSetValueEx(hKey, REG_VALUE_CONTROL_PROPERTIES, 0, REG_BINARY, pbValue, dwSize);
|
|
GlobalUnlock(hGlobal);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
LRESULT CSpyCon::OnNCDestroy(UINT /* uMsg */, WPARAM /* wParam */, LPARAM /* lParam */, BOOL& /* bHandled */)
|
|
{
|
|
PostQuitMessage(0);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSpyCon::OnErase(UINT /* uMsg */, WPARAM /* wParam */, LPARAM /* lParam */, BOOL& bHandled)
|
|
{
|
|
if (m_bInPlaceActive)
|
|
return 0;
|
|
bHandled = FALSE;
|
|
return 1;
|
|
}
|
|
|
|
LRESULT CSpyCon::OnSize(UINT /* uMsg */, WPARAM /* wParam */, LPARAM /* lParam */, BOOL& /* bHandled */)
|
|
{
|
|
if (m_spOleObject && m_bInPlaceActive)
|
|
{
|
|
CComPtr<IOleInPlaceObject> spInPlaceObject;
|
|
HRESULT hr = m_spOleObject->QueryInterface(IID_PPV_ARGS(&spInPlaceObject));
|
|
_ASSERTE(SUCCEEDED(hr) && spInPlaceObject);
|
|
|
|
RECT rcClient;
|
|
GetClientRect(&rcClient);
|
|
spInPlaceObject->SetObjectRects(&rcClient, &rcClient);
|
|
GetWindowPlacement(&m_wp); // for storing in the registry
|
|
}
|
|
return 0;
|
|
}
|