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

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;
}