/*************************************************************************
    Project:    AXAccess
    Module:     DDIHOOK.C

    Author:     Laura Butler
    Date:       05/01/96
    
    Notes:      16-bit DDIHOOK test applet

    Copyright (C) 1996 by Microsoft Corporation.  All rights reserved.
    See bottom of file for disclaimer
    
    History:    05/01/96 LauraBu Created.
*************************************************************************/
// ----------------------------------------------------------------------------
//
//  DDIHOOK.C
//
//  16-bit DDIHOOK test applet
//
// ----------------------------------------------------------------------------

#include <windows.h>

typedef struct tagDRAWMODE FAR*     LPDRAWMODE;
typedef struct tagGDIINFO FAR*      LPGDIINFO;

#include <winddi.h>

#include "ddihook.h"
#include "patch.h"


//
// Globals
//
HINSTANCE   hInstance   = NULL;
HPATCH      hpatch      = NULL;
BYTE        rgDdiHooked[DDI_MAX];
int         cHooked     = 0;
HFILE       hfLog       = -1;


//
// Functions
//
int     NEAR PASCAL WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
BOOL    CALLBACK    DdiDlgProc(HWND, UINT, WPARAM, LPARAM);

void    NEAR PASCAL InitDdiDialog(HWND);
void    NEAR PASCAL ToggleHookedDdi(HWND);
void    NEAR PASCAL StartOrStopHook(HWND);
void    NEAR PASCAL CheckOrUncheckAll(HWND, UINT);
void    NEAR PASCAL DrawListItem(HWND, LPDRAWITEMSTRUCT);




// ----------------------------------------------------------------------------
//
//  WinMain()
//
//  Main window procedure
//
// ----------------------------------------------------------------------------
int NEAR PASCAL WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR lpszCmd,
    int swShow)
{
    int     iddi;
    UINT    uResult;
    HWND    hwndMain;
    MSG     msg;

    hInstance = hInst;

    //
    // Initialize the ddi list to all hooked (checked)
    //
    for (iddi = 0; iddi < DDI_MAX; iddi++)
        rgDdiHooked[iddi] = TRUE;

    hwndMain = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_MAIN), NULL,
        DdiDlgProc, 0);
    if (!hwndMain)
        return(FALSE);

    ShowWindow(hwndMain, SW_SHOW);
    UpdateWindow(hwndMain);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        //
        // Make sure thread messages get to main window
        //
        if (!msg.hwnd)
            msg.hwnd = hwndMain;

        if (!IsDialogMessage(hwndMain, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return(uResult);
}



// ----------------------------------------------------------------------------
//
//  DdiDlgProc()
//
// ----------------------------------------------------------------------------
BOOL CALLBACK
DdiDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_INITDIALOG:
            InitDdiDialog(hdlg);
            break;

        case WM_DRAWITEM:
            DrawListItem(hdlg, (LPDRAWITEMSTRUCT)lParam);
            break;

        case WM_CLOSE:
            goto CancelTheDialog;


		case WM_VKEYTOITEM:
			if (wParam == VK_SPACE)
			{
				ToggleHookedDdi(hdlg);
				return -2;
			}
			else
				return -1;
			break;

        case WM_COMMAND:
            switch (wParam)
            {
                case IDCANCEL:
CancelTheDialog:
                    if (hpatch)
                        StartOrStopHook(hdlg);

                    EndDialog(hdlg, 0);
                    PostQuitMessage(0);
                    break;

                case IDOK:
                    //
                    // Start or Stop
                    //
                    StartOrStopHook(hdlg);
                    break;

                case ID_CHECKALL:
                case ID_UNCHECKALL:
                    CheckOrUncheckAll(hdlg, wParam);
                    break;

				// if they send a command to the list box...
                case ID_HOOKTHESE:
                    if (HIWORD(lParam) == LBN_DBLCLK)
                        ToggleHookedDdi(hdlg);
                    break;
            }
            break;

        case WM_DDICALL:
            if (rgDdiHooked[wParam] && (hfLog != (HFILE)-1))
            {
               _lwrite(hfLog, (LPSTR)lParam, lstrlen((LPSTR)lParam));
                _lwrite(hfLog, "\r\n", 2);
            }
            LocalFree(LOWORD(lParam));
            break;

        default:
            return(FALSE);
    }

    return(TRUE);
}




// --------------------------------------------------------------------------
//
//  InitDdiDialog()
//
//  Fills in the listbox with the DDIs to hook.
//
// --------------------------------------------------------------------------
void NEAR PASCAL
InitDdiDialog(HWND hdlg)
{
    int     iddi;
    char    szDdi[64];

    // Add ddi hook types to combobox
    for (iddi = DDIHOOK_RECORDER; iddi < DDIHOOK_MAX; iddi++)
    {
        LoadString(hInstance, IDS_DDITYPEFIRST+(iddi-DDIHOOK_RECORDER), szDdi, sizeof(szDdi));
        SendDlgItemMessage(hdlg, ID_HOOKTYPE, CB_ADDSTRING, 0, (LPARAM)(LPSTR)szDdi);
    }

    SendDlgItemMessage(hdlg, ID_HOOKTYPE, CB_SETCURSEL, 0, 0);

    // Add ddi calls to listbox
    for (iddi = 0; iddi < DDI_MAX; iddi++)
    {
        LoadString(hInstance, IDS_DDIFIRST+iddi, szDdi, sizeof(szDdi));
        SendDlgItemMessage(hdlg, ID_HOOKTHESE, LB_ADDSTRING, 0,
            (LPARAM)(LPSTR)szDdi);
    }

    cHooked = DDI_MAX;
}



// --------------------------------------------------------------------------
//
//  ToggleHookedDdi()
//
//  Checks/unchecks a list item.
//
// --------------------------------------------------------------------------
void NEAR PASCAL
ToggleHookedDdi(HWND hwnd)
{
    int     iToggle;
    RECT    rcItem;

    //
    // Get item with caret
    //
    iToggle = (int)SendDlgItemMessage(hwnd, ID_HOOKTHESE, LB_GETCARETINDEX, 0, 0);
    if ((iToggle < 0) || (iToggle >= DDI_MAX))
        return;

    //
    // Toggle it
    //
    if (rgDdiHooked[iToggle])
    {
        rgDdiHooked[iToggle] = FALSE;
        --cHooked;
    }
    else
    {
        rgDdiHooked[iToggle] = TRUE;
        ++cHooked;
    }

    //
    // Redraw list if visible
    //
    SetRectEmpty(&rcItem);

    if (SendDlgItemMessage(hwnd, ID_HOOKTHESE, LB_GETITEMRECT, iToggle,
        (LPARAM)(LPRECT)&rcItem))
    {
        InvalidateRect(GetDlgItem(hwnd, ID_HOOKTHESE), &rcItem, TRUE);
        // UpdateWindow(GetDlgItem(hwnd, ID_HOOKTHESE));
    }

    EnableWindow(GetDlgItem(hwnd, ID_CHECKALL), (cHooked != DDI_MAX));
    EnableWindow(GetDlgItem(hwnd, ID_UNCHECKALL), (cHooked != 0 ));
}



// --------------------------------------------------------------------------
//
//  CheckOrUncheckAll()
//
//  Checks or unchecks all the items in the DDI list
//
// --------------------------------------------------------------------------
void NEAR PASCAL
CheckOrUncheckAll(HWND hwnd, UINT idItem)
{
    int     iddi;
    BYTE    bValue;

    bValue = ((idItem == ID_CHECKALL) ? TRUE : FALSE);

    for (iddi = 0; iddi < DDI_MAX; iddi++)
        rgDdiHooked[iddi] = bValue;

    cHooked = ((idItem == ID_CHECKALL) ? DDI_MAX : 0);

    EnableWindow(GetDlgItem(hwnd, ID_CHECKALL), (cHooked != DDI_MAX));
    EnableWindow(GetDlgItem(hwnd, ID_UNCHECKALL), (cHooked != 0 ));

    InvalidateRect(GetDlgItem(hwnd, ID_HOOKTHESE), NULL, TRUE);
}



// --------------------------------------------------------------------------
//
//  StartOrStopHook()
//
// --------------------------------------------------------------------------
void NEAR PASCAL
StartOrStopHook(HWND hwnd)
{
    char  szButtonText[64];

    if (hpatch)
    {
        MSG msg;

        //
        // Stop the hook.
        //
        UnpatchDdi(hpatch);
        hpatch = NULL;

        //
        // Log the pending Ddis
        //
        while (PeekMessage(&msg, NULL, WM_DDICALL, WM_DDICALL, PM_REMOVE))
        {
            msg.hwnd = hwnd;
            DispatchMessage(&msg);
        }

SetHookFailed:
        //
        // Close the file
        //
        if (hfLog != (HFILE)-1)
        {
            _lclose(hfLog);
            hfLog = (HFILE)-1;
        }

        //
        // Change the button text
        //
        LoadString(hInstance, IDS_START, szButtonText, sizeof(szButtonText));
        SetWindowText(GetDlgItem(hwnd, IDOK), szButtonText);
    }
    else
    {
        char    szFile[MAX_PATH];
        DDITYPE ddiType;

        //
        // Open a file if the log item is filled in.
        //
        *szFile = 0;
        if (GetWindowText(GetDlgItem(hwnd, ID_LOGTOFILE), szFile, MAX_PATH))
        {
            hfLog = _lcreat(szFile, 0);
            if (hfLog == (HFILE)-1)
            {
                MessageBeep(0);
                return;
            }
        }

        //
        // Change the button text
        //
        LoadString(hInstance, IDS_STOP, szButtonText, sizeof(szButtonText));
        SetWindowText(GetDlgItem(hwnd, IDOK), szButtonText);

        ShowWindow(hwnd, SW_MINIMIZE);
        UpdateWindow(GetDesktopWindow());

        //
        // Get the hook type
        //
        ddiType = (DDITYPE)SendDlgItemMessage(hwnd, ID_HOOKTYPE, CB_GETCURSEL, 0, 0);
        ddiType++;

        //
        // Install the hook
        //
        hpatch = PatchDdi(hwnd, hInstance, ddiType);
        if (!hpatch)
        {
            ShowWindow(hwnd, SW_RESTORE);
            goto SetHookFailed;
        }
    }
}



// --------------------------------------------------------------------------
//
//  DrawListItem()
//
// --------------------------------------------------------------------------
void NEAR PASCAL
DrawListItem(HWND hwnd, LPDRAWITEMSTRUCT lpdis)
{
    RECT    rcBullet;
    char    szItem[64];
    DWORD   rgbBk;
    DWORD   rgbText;

    if (lpdis->itemID == -1)
    {
        DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
        return;
    }

    CopyRect(&rcBullet, &lpdis->rcItem);
    InflateRect(&rcBullet, -2, -2);
    rcBullet.right = rcBullet.left + (rcBullet.bottom - rcBullet.top);

    if (lpdis->itemState & ODS_SELECTED)
    {
        rgbBk = SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
        rgbText = SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
    }

    LoadString(hInstance, IDS_DDIFIRST+lpdis->itemID, szItem, 64);
    ExtTextOut(lpdis->hDC, rcBullet.right+2, lpdis->rcItem.top+1, ETO_OPAQUE,
        &lpdis->rcItem, szItem, lstrlen(szItem), NULL);

    if (rgDdiHooked[lpdis->itemID])
        DrawFrameControl(lpdis->hDC, &rcBullet, DFC_MENU, DFCS_MENUBULLET);

    if (lpdis->itemState & ODS_FOCUS)
        DrawFocusRect(lpdis->hDC, &lpdis->rcItem);

    if (lpdis->itemState & ODS_SELECTED)
    {
        SetBkColor(lpdis->hDC, rgbBk);
        SetTextColor(lpdis->hDC, rgbText);
    }
}

/*
    THE INFORMATION AND CODE PROVIDED HEREUNDER (COLLECTIVELY REFERRED TO
    AS "SOFTWARE") IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN
    NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR
    ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL,
    CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF
    MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR
    LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE
    FOREGOING LIMITATION MAY NOT APPLY.
*/
