MISC.C


/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1993 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/

/*****************************************************************************\
*
* Module: misc.c
*
* Contains miscellaneous routines for the Windows debugging Spy SDK applet.
*
* Functions:
*
* ReadRegistry()
* WriteRegistry()
* Message()
* SetSpyCaption()
* GetWindowName()
* StripExtension()
*
* Comments:
*
\*****************************************************************************/

#include "spy.h"
#include <string.h>


//
// Registry flags for the "Flags" value.
//
#define REGFLAG_OUTPUTWIN 0x00000001
#define REGFLAG_OUTPUTCOM1 0x00000002
#define REGFLAG_OUTPUTFILE 0x00000004
#define REGFLAG_MSGSUSER 0x00000010
#define REGFLAG_MSGSUNKNOWN 0x00000020


PRIVATE HKEY ghkeySpy = NULL;
PRIVATE CHAR gszSpyAppKey[] = "Software\\Microsoft\\Spy";
PRIVATE CHAR gszKeyPosition[] = "Position";
PRIVATE CHAR gszKeyFont[] = "Font";
PRIVATE CHAR gszKeyMessages[] = "Messages";
PRIVATE CHAR gszKeyFileName[] = "FileName";
PRIVATE CHAR gszKeyLines[] = "Lines";
PRIVATE CHAR gszKeyFlags[] = "Flags";
PRIVATE CHAR gszDefFileName[] = "spy.log";
PRIVATE BYTE BitTable[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };


PRIVATE VOID GetWindowName(HWND hwnd, PSTR sz);
PRIVATE LPSTR StripExtension(LPSTR pszFileName);




/*****************************************************************************\
* ReadRegistry
*
* Opens (creates if necessary) the registry key for spy preferences and then
* reads the last saved values.
*
* Arguments:
* none
*
* Returns:
* VOID
\*****************************************************************************/

VOID
ReadRegistry(
VOID
)
{
LOGFONT lf;
BYTE abMsgs[128];
DWORD fFlags;
HDC hdc;
INT i;
DWORD dwType;
DWORD cbData;

RegCreateKey(HKEY_CURRENT_USER, gszSpyAppKey, &ghkeySpy);

cbData = gwndpl.length = sizeof(gwndpl);
if (!ghkeySpy || RegQueryValueEx(ghkeySpy, gszKeyPosition, NULL, &dwType,
(LPVOID)&gwndpl, &cbData) != ERROR_SUCCESS)
{
gwndpl.length = 0;
}


//
// If the spy process is killed while the registry key is open, the
// position data can be indeterminant... Here we catch the case that
// the reg. data is not good, and we set sensible defaults.
//

if (gwndpl.length != sizeof(gwndpl))
{

gwndpl.length = sizeof(gwndpl);
gwndpl.flags = 0;
gwndpl.showCmd = SW_SHOWNORMAL;
gwndpl.ptMinPosition.x = 0;
gwndpl.ptMinPosition.y = 0;
gwndpl.ptMaxPosition.x = 0;
gwndpl.ptMaxPosition.y = 0;
gwndpl.rcNormalPosition.left = 10;
gwndpl.rcNormalPosition.top = 10;
gwndpl.rcNormalPosition.right =
10 + (GetSystemMetrics(SM_CXSCREEN) / 3);
gwndpl.rcNormalPosition.bottom =
10 + (GetSystemMetrics(SM_CYSCREEN) / 3);
}

cbData = sizeof(lf);
if (!ghkeySpy || RegQueryValueEx(ghkeySpy, gszKeyFont, NULL, &dwType,
(LPVOID)&lf, &cbData) != ERROR_SUCCESS)
{
hdc = GetDC(NULL);
GetObject(GetStockObject(SYSTEM_FONT), sizeof(lf), &lf);
ReleaseDC(NULL, hdc);
}

ghfontPrintf = CreateFontIndirect(&lf);

cbData = sizeof(abMsgs);
if (!ghkeySpy || RegQueryValueEx(ghkeySpy, gszKeyMessages, NULL, &dwType,
(LPVOID)abMsgs, &cbData) != ERROR_SUCCESS)
{
//
// Select all messages by default
//
for (i = 0; i < gcMessages; i++)
{
gaMsgs[i].Flags |= MTF_SELECTED;
}
}
else
{
for (i = 0; i < gcMessages; i++)
{
if (abMsgs[gaMsgs[i].msg >> 3] & BitTable[gaMsgs[i].msg & 0x07])
gaMsgs[i].Flags |= MTF_SELECTED;
}
}

cbData = MAXSTRING * sizeof(TCHAR);
if (!ghkeySpy || RegQueryValueEx(ghkeySpy, gszKeyFileName, NULL, &dwType,
(LPVOID)gszFile, &cbData) != ERROR_SUCCESS)
{
lstrcpy(gszFile, gszDefFileName);
}

cbData = sizeof(DWORD);
if (!ghkeySpy || RegQueryValueEx(ghkeySpy, gszKeyLines, NULL, &dwType,
(LPVOID)&gnLines, &cbData) != ERROR_SUCCESS ||
gnLines > LINES_MAX)
{
gnLines = LINES_MAX;
}

cbData = sizeof(DWORD);
if (!ghkeySpy || RegQueryValueEx(ghkeySpy, gszKeyFlags, NULL, &dwType,
(LPVOID)&fFlags, &cbData) != ERROR_SUCCESS)
{
gfOutputWin = TRUE;
gfOutputCom1 = FALSE;
gfOutputFile = FALSE;
gfMsgsUser = TRUE;
gfMsgsUnknown = TRUE;
}
else
{
if (fFlags & REGFLAG_OUTPUTWIN)
gfOutputWin = TRUE;

if (fFlags & REGFLAG_OUTPUTCOM1)
gfOutputCom1 = TRUE;

if (fFlags & REGFLAG_OUTPUTFILE)
gfOutputFile = TRUE;

if (fFlags & REGFLAG_MSGSUSER)
gfMsgsUser = TRUE;

if (fFlags & REGFLAG_MSGSUNKNOWN)
gfMsgsUnknown = TRUE;
}

if (gfOutputFile)
{
gfhFile = _lcreat(gszFile, 0);
if (gfhFile == (HFILE)-1) //BUGBUG put up a message here.
gfhFile = 0;
}

if (gfOutputCom1)
{
gfhCom1 = CreateFile(
"com1",
GENERIC_WRITE,
0, // exclusive access
NULL, // no security attrs
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
}
}



/*****************************************************************************\
* WriteRegistry
*
* Writes out preference data to the registry when the app exits, then
* closes the registry key.
*
* Arguments:
* none
*
* Returns:
* VOID
\*****************************************************************************/

VOID
WriteRegistry(
VOID
)
{
LOGFONT lf;
BYTE abMsgs[128];
INT i;
DWORD fFlags;
WINDOWPLACEMENT wndpl;

if (ghkeySpy)
{
wndpl.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(ghwndSpyApp, &wndpl);
RegSetValueEx(ghkeySpy, gszKeyPosition, 0, REG_BINARY,
(LPBYTE)&wndpl, sizeof(wndpl));

GetObject(ghfontPrintf, sizeof(lf), &lf);
RegSetValueEx(ghkeySpy, gszKeyFont, 0, REG_BINARY,
(LPBYTE)&lf, sizeof(lf));

memset(abMsgs, 0, sizeof(abMsgs));
for (i = 0; i < gcMessages; i++)
{
if (gaMsgs[i].Flags & MTF_SELECTED)
abMsgs[gaMsgs[i].msg >> 3] |= BitTable[gaMsgs[i].msg & 0x07];
}

RegSetValueEx(ghkeySpy, gszKeyMessages, 0, REG_BINARY,
(LPBYTE)&abMsgs, sizeof(abMsgs));

RegSetValueEx(ghkeySpy, gszKeyFileName, 0, REG_SZ,
(LPBYTE)gszFile, (lstrlen(gszFile) + 1) * sizeof(TCHAR));

RegSetValueEx(ghkeySpy, gszKeyLines, 0, REG_DWORD,
(LPBYTE)&gnLines, sizeof(DWORD));

fFlags = 0;
if (gfOutputWin)
fFlags |= REGFLAG_OUTPUTWIN;

if (gfOutputCom1)
fFlags |= REGFLAG_OUTPUTCOM1;

if (gfOutputFile)
fFlags |= REGFLAG_OUTPUTFILE;

if (gfMsgsUser)
fFlags |= REGFLAG_MSGSUSER;

if (gfMsgsUnknown)
fFlags |= REGFLAG_MSGSUNKNOWN;

RegSetValueEx(ghkeySpy, gszKeyFlags, 0, REG_DWORD,
(LPBYTE)&fFlags, sizeof(DWORD));

RegCloseKey(ghkeySpy);
}
}



/*****************************************************************************\
* Message
*
* Puts up a message box.
*
* Arguments:
* UINT fuStyle - Flags for MessageBox (MB_YESNOCANCEL, etc).
* LPSTR pszFormat - Format string for the message.
*
* Returns:
* Whatever MessageBox returns.
*
\*****************************************************************************/

INT
Message(
UINT fuStyle,
LPSTR pszFormat,
...
)
{
va_list marker;
INT RetCode;
TCHAR szT[MAXSTRING];

va_start(marker, pszFormat);
wvsprintf(szT, pszFormat, marker);
RetCode = MessageBox(ghwndSpyApp, szT, gszWindowName, fuStyle|MB_TASKMODAL);
va_end(marker);

return RetCode;
}



/*****************************************************************************\
* SetSpyCaption
*
* This routine sets the Spy app's caption bar to display info on the window
* that is currently being spy'ed upon.
*
* Arguments:
* none
*
* Returns:
* VOID
\*****************************************************************************/

VOID
SetSpyCaption(
VOID
)
{
CHAR szText[MAXSTRING];
CHAR szTemp[MAXSTRING];

if (ghwndSpyingOn != NULL && ghwndSpyingOn != HWND_ALL)
{
GetWindowName(ghwndSpyingOn, szTemp);

if (lstrlen(gszWindowName) + lstrlen(szTemp) + 3 > MAXSTRING)
szTemp[MAXSTRING - 3 - lstrlen(szTemp)] = 0;

if (gfSpyOn)
wsprintf(szText, "%s - %s", gszWindowName, szTemp);
else
wsprintf(szText, "<%s - %s>", gszWindowName, szTemp);
}
else
{
lstrcpy(szText, gszWindowName);
}

SetWindowText(ghwndSpyApp, szText);
}



/*****************************************************************************\
* GetWindowName
*
* Builds the name of the window being spy'd on in the specified buffer.
* This will be something like "EXENAME!WindowText" or "EXENAME!Class".
*
* Arguments:
*
* HWND hwnd - handle to the window being spy'd on.
* PSTR pstr - pointer to string to return.
*
* Returns:
* VOID
\*****************************************************************************/

PRIVATE VOID
GetWindowName(
HWND hwnd,
PSTR sz
)
{
PSTR szSave = sz;

if (hwnd != NULL && IsWindow(hwnd))
{
#if 0
// THIS DOES NOT WORK ON NT SINCE HINST'S ARE NOT GLOBAL

HINSTANCE hinst;

SetLastError(0);
hinst = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);
GetLastError();

/*
* Get the module name
*/
#ifdef JAPAN
//DBCS_FIX
if (GetModuleFileName((HANDLE)GetWindowLong(hwnd, GWL_HINSTANCE),
sz, MAXSTRING)) {
//Probably this function will fail on NT
#else
SetLastError(0);
GetModuleFileName(hinst, sz, MAXSTRING);
GetLastError();
#endif
lstrcpy(sz, StripExtension(sz));

sz += lstrlen(sz);
*sz++ = '!';
#ifdef Japan
}
#endif
*sz = 0;

GetWindowText(hwnd, sz, MAXSTRING - (sz - szSave));
#else // !0
GetWindowText(hwnd, sz, MAXSTRING);
#endif

/*
* If the window has no caption string then use the Class name
*/
if (*sz == 0)
GetClassName(hwnd, sz, MAXSTRING - (sz - szSave));
}
else
{
*sz = 0;
}
}



/*****************************************************************************\
* StripExtension
*
* Strips the extension off of a filename.
*
* Arguments:
* LPSTR pszFileName - File name to process.
*
* Returns:
* Returns a pointer to the beginning of the filename. The extension
* will have been stripped off.
*
\*****************************************************************************/

PRIVATE LPSTR
StripExtension(
LPSTR pszFileName
)
{
LPSTR p = pszFileName;

while (*p)
p++;

while (p > pszFileName && *p != '\\' && *p != ':') {
p = CharPrev(pszFileName, p);
if (*p == '.') {
*p = 0;
}
}
if (*p == '\\' || *p == ':') {
p++;
}
return p;
}


/*****************************************************************************\
* LoadResourceString
*
* Loads a resource string from SPY and returns a pointer to the string.
*
* Arguments:
* wId - resource string id
*
* Returns:
* Returns a pointer to the string.
*
\*****************************************************************************/
LPTSTR
LoadResourceString( UINT wId )
{
static TCHAR lpBuf[1024];

LoadString( GetModuleHandle(NULL), wId, lpBuf, sizeof(lpBuf) );

return lpBuf;
}