
/******************************************************************************\
*       This is a part of the Microsoft Source Code Samples. 
*       Copyright (C) 1993 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.cpp
*
*   Contains miscellaneous routines for the Windows debugging OAC Spy applet.
*
* Functions:
*
*   ReadRegistry()
*   WriteRegistry()
*   Message()
*   SetSpyCaption()
*   GetWindowName()
*   StripExtension()
*
* Comments:
*
\*****************************************************************************/

#include "oacspy.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[] = "oacspy.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 = sizeof(gwndpl);
    if (!ghkeySpy || RegQueryValueEx(ghkeySpy, gszKeyPosition, NULL, &dwType,
        (LPBYTE)&gwndpl, &cbData) != ERROR_SUCCESS)
    {
        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,
        (LPBYTE)&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,
        (LPBYTE)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,
        (LPBYTE)gszFile, &cbData) != ERROR_SUCCESS)
    {
        lstrcpy(gszFile, gszDefFileName);
    }

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

    cbData = sizeof(DWORD);
    if (!ghkeySpy || RegQueryValueEx(ghkeySpy, gszKeyFlags, NULL, &dwType,
        (LPBYTE)&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;
    }
}



/*****************************************************************************\
* 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)
    {
        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, gszAppName, 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(gszAppName) + lstrlen(szTemp) + 3 > MAXSTRING)
            szTemp[MAXSTRING - 3 - lstrlen(szTemp)] = 0;

        if (gfSpyOn)
            wsprintf(szText, "Spying on: %s", szTemp);
        else
            wsprintf(szText, "Spying on: %s", szTemp);
    }
    else
    {
        lstrcpy(szText, gszAppName);
    }

    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))
    {
        /*
         * Get the module name
         */
        GetModuleFileName((HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
            sz, MAXSTRING);
        lstrcpy(sz, StripExtension(sz));
        sz += lstrlen(sz);
        *sz++ = ' ';
        *sz = 0;

        GetWindowText(hwnd, sz, MAXSTRING - (sz - szSave));

        /*
         * 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 != '\\')
    {
        if (*p == '.')
            *p = 0;

        p--;
    }

    return ++p;
}




