//
//         Postman -- Windows PostMessage Utility
//                    Chiverton Graphics, Inc., 1991
//
//
#include <windows.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "postman1.h"
#include "dlgdefs.h"




/* proc addresses needed for subclassing */
static FARPROC lpprocFilterHexNumber,
               lpEditControlProc;

static WORD wEditID[6] = {
                         IDD_EDIT_HWND,
                         IDD_EDIT_WMSG,
                         IDD_EDIT_WPARAM,
                         IDD_EDIT_LPARAM,
                         IDD_EDIT_HIWORD,
                         IDD_EDIT_LOWORD
                         };

static WORD wFile = IDD_RB_WM;

HANDLE hInstance ;

static void show_lparam_controls (HWND hDlg, BOOL bHiLo);
static void check_control_enable (HWND hDlg, int idEdit, int idButton, WORD message);
static void fill_hwnd_combobox   (HWND hDlg);
static void fill_wmsg_combobox   (HWND hDlg);

static void combobox_DrawEntireItem (LPDRAWITEMSTRUCT lp);
static void combobox_DrawSelection  (LPDRAWITEMSTRUCT lp);
static void combobox_DrawFocus      (LPDRAWITEMSTRUCT lp);

BOOL FAR PASCAL DialogWndProc     (HWND hDlg, unsigned message, WORD wParam, LONG lParam);
BOOL FAR PASCAL AboutDialogWndProc(HWND hDlg, unsigned message, WORD wParam, LONG lParam);
long FAR PASCAL filter_hex_number (HWND hWnd, unsigned message, WORD wParam, LONG lParam);




int PASCAL WinMain (HANDLE hInst, HANDLE hPrevInst, LPSTR lpszCmdLine, int nCmdShow )
     {
     FARPROC lpProc;

     hInstance = hInst;

     lpProc = MakeProcInstance ((FARPROC) DialogWndProc, hInstance);
     DialogBox (hInstance, MAKEINTRESOURCE (IDD_DIALOG), NULL, lpProc);
     FreeProcInstance (lpProc);

     return 0L;
     }



BOOL FAR PASCAL DialogWndProc (HWND hDlg, unsigned message, WORD wParam, LONG lParam)
   {
   int  i;
   LONG lResult;
   static BOOL bHiLo = FALSE;     // use lParam initially

   switch (message)
   {
   case WM_INITDIALOG:

        // Add the About Postman... dlgbox to the system menu
        {
        HMENU hMenu = GetSystemMenu (hDlg, FALSE);
        ChangeMenu (hMenu, 0, NULL, 0, MF_APPEND);
        ChangeMenu (hMenu, 0, "A&bout Postman...", IDD_ABOUT, MF_APPEND);
        }


        //  Use a fixed font for the message combobox

        SendDlgItemMessage (hDlg, IDD_CB_WMSG, WM_SETFONT,
                              GetStockObject (SYSTEM_FIXED_FONT), 0L);


        //  limit length of edit controls

        for (i=0; i<6; i++)
            SendDlgItemMessage (hDlg,wEditID[i],EM_LIMITTEXT,4,0L);
        SendDlgItemMessage(hDlg,IDD_EDIT_LPARAM,EM_LIMITTEXT,8,0L);


        //  Subclass the edit controls by substituting filter_hex_number()
        //  for each edit control's windowproc.
        //  Note that the EDIT control's window proc is the same for every one.

        lpprocFilterHexNumber = MakeProcInstance ((FARPROC)filter_hex_number, hInstance);
        for (i=0; i<6; i++)
            {
            HWND hWndEdit     = GetDlgItem (hDlg, wEditID[i]);
            lpEditControlProc = (FARPROC) SetWindowLong (hWndEdit, GWL_WNDPROC, (long)lpprocFilterHexNumber);
            }


        //  Get current number of windows (nWindows)...
        //  and then fill hwnd combobox.
        //
        winlist_enumAll    (hDlg);
        fill_hwnd_combobox (hDlg);
        fill_wmsg_combobox (hDlg);

        // EDIT controls are empty...so disable some other controls
        EnableWindow (GetDlgItem(hDlg, IDD_POSTMESSAGE)  , FALSE);

        SetDlgItemText (hDlg, IDD_EDIT_HWND  , "");
        SetDlgItemText (hDlg, IDD_EDIT_WMSG  , "");
        SetDlgItemText (hDlg, IDD_EDIT_WPARAM, "");

        CheckRadioButton (hDlg,IDD_RB_WM, IDD_RB_USERDEFINED, wFile);

        CheckDlgButton (hDlg, IDD_HILO, bHiLo);
        show_lparam_controls (hDlg, bHiLo);

        SetFocus (GetDlgItem(hDlg,IDD_CB_HWND) );
        return FALSE;

   case WM_MEASUREITEM:
        ((LPMEASUREITEMSTRUCT)lParam)->itemHeight =
             GetSystemMetrics(SM_CYICON) + 8;
        return TRUE;

   case WM_DRAWITEM:
        {
        LPDRAWITEMSTRUCT lp = (LPDRAWITEMSTRUCT) lParam ;

        if (lp->itemID == -1)
             {
             combobox_DrawFocus (lp);
             }
        else
             {
             switch (lp->itemAction)
                  {
                  case ODA_DRAWENTIRE: combobox_DrawEntireItem (lp); break ;
                  case ODA_SELECT    : combobox_DrawSelection  (lp); break ;
                  case ODA_FOCUS     : combobox_DrawFocus      (lp); break ;
                  }
             }
        }
        return TRUE;

   case WM_ERASEBKGND:
        return (IsIconic (hDlg));

   case WM_PAINT:
        if (IsIconic(hDlg))
             {
             PAINTSTRUCT ps;
             BeginPaint (hDlg, (LPPAINTSTRUCT) &ps);
             DefWindowProc (hDlg, WM_ICONERASEBKGND, (WORD)ps.hdc, 0L);
             DrawIcon (ps.hdc, 0, 0, LoadIcon (hInstance, "postmanIcon"));
             EndPaint (hDlg, (LPPAINTSTRUCT) &ps);
             return TRUE;
             }
        else
             {
             return FALSE;
             }

   case WM_SYSCOMMAND:
        if (wParam == IDD_ABOUT)
             {
             FARPROC lpfnAboutDlgProc = MakeProcInstance (AboutDialogWndProc,hInstance);
             DialogBox (hInstance, MAKEINTRESOURCE (IDD_ABOUT),
                        hDlg, lpfnAboutDlgProc);
             FreeProcInstance (lpfnAboutDlgProc);
             return TRUE;
             }
        else if ((wParam & 0xfff0) == SC_CLOSE)
             {
             //  Restore original Edit Control procs.
             for (i=0; i<=5; i++)
                 {
                 SetWindowLong (GetDlgItem (hDlg, wEditID[i]), GWL_WNDPROC, (long)lpEditControlProc);
                 }
             FreeProcInstance (lpprocFilterHexNumber);
             EndDialog (hDlg, TRUE);
             }
        else
             {
             return FALSE;
             }

   case WM_COMMAND:
        switch(wParam)
          {
          case IDD_RB_WM:
          case IDD_RB_USERDEFINED:
          case IDD_RB_REGISTERED:
               if (wParam != wFile)
                   {
                   SendDlgItemMessage (hDlg, wFile, BM_SETCHECK, FALSE, 0L);
                   wFile = wParam;
                   SendDlgItemMessage (hDlg, wFile, BM_SETCHECK, TRUE, 0L);
                   SendDlgItemMessage (hDlg, IDD_CB_WMSG, CB_RESETCONTENT, 0, 0L);
                   fill_wmsg_combobox  (hDlg);
                   }
               return TRUE;

          case IDD_REFRESH:
               winlist_enumAll    (hDlg);
               SendDlgItemMessage (hDlg, IDD_CB_HWND, CB_RESETCONTENT, 0, 0L);
               fill_hwnd_combobox (hDlg);
               return TRUE;

          case IDD_POSTMESSAGE:
               {
               BOOL bResult;
               char szBuffer[10],
                    szHex[11];
               PSTR pPrefix = "0x";
               HWND hWnd;
               LONG lPar;
               WORD wMsg,
                    wPar,
                    wHi,
                    wLo;

               GetDlgItemText (hDlg, IDD_EDIT_HWND, szBuffer, 5);
               strcpy (szHex, pPrefix);
               strcat (szHex, szBuffer);
               hWnd = (HWND) strtol (szHex, NULL, 0);

               GetDlgItemText (hDlg, IDD_EDIT_WMSG, szBuffer, 5);
               strcpy(szHex, pPrefix);
               strcat(szHex, szBuffer);
               wMsg = (WORD) strtol (szHex, NULL, 0);

               GetDlgItemText (hDlg, IDD_EDIT_WPARAM, szBuffer, 5);
               strcpy (szHex, pPrefix);
               strcat (szHex, szBuffer);
               wPar = (WORD) strtol (szHex, NULL, 0);

               if (bHiLo)
                   {
                   GetDlgItemText (hDlg, IDD_EDIT_HIWORD, szBuffer, 5);
                   strcpy (szHex, pPrefix);
                   strcat (szHex, szBuffer);
                   wHi = (WORD) strtol (szHex, NULL, 0);

                   GetDlgItemText (hDlg, IDD_EDIT_LOWORD, szBuffer, 5);
                   strcpy (szHex, pPrefix);
                   strcat (szHex, szBuffer);
                   wLo = (WORD) strtol (szHex, NULL, 0);

                   lPar = MAKELONG (wLo, wHi);
                   }
               else
                   {
                   GetDlgItemText (hDlg, IDD_EDIT_LPARAM, szBuffer, 9);
                   strcpy (szHex, pPrefix);
                   strcat (szHex, szBuffer);
                   lPar = strtol (szHex, NULL, 0);
                   }

               if (!IsWindow (hWnd))
                   MessageBeep (0);
               else
                   {
                   bResult = PostMessage (hWnd, wMsg, wPar, lPar);
                   if (bResult == FALSE)
                       {
                       MessageBeep (0);
                       MessageBox(hDlg, "PostMessage failed.", "PostMessage",(MB_ICONEXCLAMATION | MB_OK));
                       }
                   }
               }
               return TRUE;

          case IDD_HILO:
               bHiLo = !bHiLo;
               CheckDlgButton (hDlg, IDD_HILO, bHiLo);
               show_lparam_controls (hDlg, bHiLo);
               return TRUE;


          case IDD_EDIT_HWND: // activate controls only if all EDIT controls aren't empty.
          case IDD_EDIT_WMSG:
          case IDD_EDIT_WPARAM:
          case IDD_EDIT_LPARAM:
          case IDD_EDIT_HIWORD:
          case IDD_EDIT_LOWORD:
               if ( HIWORD (lParam) == EN_CHANGE )
                   {
                   BOOL bAllFilled;

                   if (bHiLo)
                       {
                       bAllFilled =
                           (
                           (BOOL) (SendDlgItemMessage (hDlg, IDD_EDIT_HWND,   WM_GETTEXTLENGTH, 0, 0L)) &&
                           (BOOL) (SendDlgItemMessage (hDlg, IDD_EDIT_WMSG,   WM_GETTEXTLENGTH, 0, 0L)) &&
                           (BOOL) (SendDlgItemMessage (hDlg, IDD_EDIT_WPARAM, WM_GETTEXTLENGTH, 0, 0L)) &&
                           (BOOL) (SendDlgItemMessage (hDlg, IDD_EDIT_HIWORD, WM_GETTEXTLENGTH, 0, 0L)) &&
                           (BOOL) (SendDlgItemMessage (hDlg, IDD_EDIT_LOWORD, WM_GETTEXTLENGTH, 0, 0L))
                           );
                       }
                   else
                       {
                       bAllFilled =
                           (
                           (BOOL) (SendDlgItemMessage (hDlg, IDD_EDIT_HWND,   WM_GETTEXTLENGTH, 0, 0L)) &&
                           (BOOL) (SendDlgItemMessage (hDlg, IDD_EDIT_WMSG,   WM_GETTEXTLENGTH, 0, 0L)) &&
                           (BOOL) (SendDlgItemMessage (hDlg, IDD_EDIT_WPARAM, WM_GETTEXTLENGTH, 0, 0L)) &&
                           (BOOL) (SendDlgItemMessage (hDlg, IDD_EDIT_LPARAM, WM_GETTEXTLENGTH, 0, 0L))
                           );
                       }
                   EnableWindow (GetDlgItem (hDlg, IDD_POSTMESSAGE), bAllFilled);
                   }
               return TRUE;


          case IDD_CB_HWND:
               /*
                *   User single clicked or doubled clicked in combobox -
                *   Fill edit box with selection.
                */
               if (HIWORD (lParam) == CBN_SELCHANGE)
                  {
                  lResult = SendDlgItemMessage (hDlg,IDD_CB_HWND, CB_GETCURSEL, 0, 0L);
                  if (lResult != CB_ERR)
                      {
                      char szHwnd[5];
                      HWINFO  hWinfo = winlist_getWinfo ();
                      LPWINFO lpWinfo;

                      /* retrieve current ListBox selection... */

                      lpWinfo = (LPWINFO) GlobalLock (hWinfo);
                      lpWinfo += lResult;
                      wsprintf (szHwnd, "%04X", lpWinfo->hwnd);
                      GlobalUnlock (hWinfo);


                      /* ...and put in EDIT control.           */
                      SetDlgItemText (hDlg, IDD_EDIT_HWND, szHwnd);
                      }
                  }
               return TRUE;


          case IDD_CB_WMSG:
               if (HIWORD (lParam) == CBN_SELCHANGE)
                  {
                  lResult  = SendDlgItemMessage(hDlg,IDD_CB_WMSG, CB_GETCURSEL, 0, (LONG)(LPSTR)0);
                  if (lResult != CB_ERR)
                     {
                     char szBuffer [60],
                          szWmsg   [ 5];

                     /* retrieve current ListBox selection... */
                     SendDlgItemMessage (hDlg,IDD_CB_WMSG, CB_GETLBTEXT, (WORD)lResult, (LONG)(LPSTR)szBuffer);

                     /* ...and put in EDIT control.           */
                     strncpy (szWmsg, szBuffer+29, 4);
                     szWmsg [4] = '\0';
                     SetDlgItemText(hDlg, IDD_EDIT_WMSG, szWmsg);
                     }
                  }
               return TRUE;

          default:
               break;
          } /* switch wParam */

   default:
        break;
   }
   return FALSE;
   }



static void show_lparam_controls(HWND hDlg, BOOL bHiLo)
    {
    ShowWindow (GetDlgItem (hDlg,IDD_EDIT_LPARAM), bHiLo ? HIDE_WINDOW     : SHOW_OPENWINDOW);
    ShowWindow (GetDlgItem (hDlg,IDD_EDIT_HIWORD), bHiLo ? SHOW_OPENWINDOW : HIDE_WINDOW);
    ShowWindow (GetDlgItem (hDlg,IDD_EDIT_LOWORD), bHiLo ? SHOW_OPENWINDOW : HIDE_WINDOW);
    ShowWindow (GetDlgItem (hDlg,IDD_STEXT_SLASH), bHiLo ? SHOW_OPENWINDOW : HIDE_WINDOW);

    SetDlgItemText (hDlg, IDD_EDIT_LPARAM, "");
    SetDlgItemText (hDlg, IDD_EDIT_HIWORD, "");
    SetDlgItemText (hDlg, IDD_EDIT_LOWORD, "");
    }



// filter_hex_number - EDIT Control subclass procedure
//
long FAR PASCAL filter_hex_number(HWND hWnd, unsigned message, WORD wParam, LONG lParam)
    {
    //   Pass on every message we get to the original EDIT control
    //   proc except WM_CHAR.
    //   Only process '0'-'9','A'-'F','a'-'f', and the backspace
    //   character. Ignore other characters.
    //
    if (message == WM_CHAR)
        {
        if (!isxdigit(wParam) && wParam != '\b')
           return 0L;
        else
           return CallWindowProc (lpEditControlProc, hWnd,
                        message, wParam, lParam);
        }
    return CallWindowProc(lpEditControlProc, hWnd, message, wParam, lParam);
    }


static void check_control_enable(HWND hDlg, int idEdit, int idButton, WORD msg)
    {
    if (msg == EN_CHANGE)
        EnableWindow(GetDlgItem(hDlg, idButton),
           (BOOL)(SendDlgItemMessage(hDlg, idEdit,
           WM_GETTEXTLENGTH, 0, 0L)));
    }


static void fill_hwnd_combobox (HWND hDlg)
    {
    int n,
        nWindows = winlist_getCount();

    for ( n = 1; n <= nWindows; n++)
        {
        SendDlgItemMessage (hDlg, IDD_CB_HWND, CB_ADDSTRING, 0, 0L);
        }
    }


static void fill_wmsg_combobox (HWND hDlg)
    {
    char szMsgAndHex [35],
         szMsg [81],
         szHex [ 5];

    OFSTRUCT ofstruct;
    int      hFile;
    LPSTR    lpFileName;

    switch (wFile)
         {
         case IDD_RB_REGISTERED:  lpFileName = "register.msg"; break;
         case IDD_RB_USERDEFINED: lpFileName = "user.msg";     break;
         case IDD_RB_WM:          lpFileName = "wm.msg";
         }

     hFile = OpenFile (lpFileName, &ofstruct, OF_READ);

     if (hFile != -1)
          {
          FILE *fp = fdopen(hFile, "r");
          szMsgAndHex [34] = '\0';

          if (wFile == IDD_RB_REGISTERED)
               {
               while (fscanf(fp,"%80s", szMsg) != EOF)
                   {
                   wsprintf(szMsgAndHex,"%-28.28s %X", (LPSTR)szMsg, RegisterWindowMessage(szMsg));
                   SendDlgItemMessage (hDlg, IDD_CB_WMSG, CB_ADDSTRING, 0, (long)(LPSTR)szMsgAndHex);
                   }
               }
          else
               {
               while (fscanf(fp,"%80s %4s", szMsg, szHex) != EOF )
                   {
                   wsprintf(szMsgAndHex,"%-28.28s %s", (LPSTR)szMsg, (LPSTR)szHex);
                   SendDlgItemMessage (hDlg, IDD_CB_WMSG, CB_ADDSTRING, 0, (long)(LPSTR)szMsgAndHex);
                   }
               }
          fclose (fp);
          }
    }


static void combobox_DrawEntireItem (LPDRAWITEMSTRUCT lp)
     {
     char  szBuffer[70];
     LPSTR lpTypeName;
     int    nCount ,
            nIndent1,
            nIndent2,
            nIconWidth = GetSystemMetrics (SM_CXICON);
     HWINFO  hWinfo    = winlist_getWinfo ();
     LPWINFO lpWinfo;
     HICON  hIcon;
     RECT   rc;

     lpWinfo = (LPWINFO) GlobalLock (hWinfo);
     lpWinfo += lp->itemID;

     nIndent1 = lpWinfo->nLevel * nIconWidth + 10;
     nIndent2 = nIndent1 + nIconWidth + 5;

     if (!IsWindow (lpWinfo->hwnd))
          hIcon = LoadIcon (hInstance, "invalidIcon");
     else if (lpWinfo->hIcon)
          hIcon = lpWinfo->hIcon;
     else
          hIcon = LoadIcon (hInstance, "nullIcon");

     DrawIcon (lp->hDC, lp->rcItem.left+nIndent1, lp->rcItem.top+4, hIcon) ;

     if (lpWinfo->dwStyle & WS_CHILD)       lpTypeName = "Child";
     else if( lpWinfo->dwStyle & WS_ICONIC) lpTypeName = "Icon";
     else if( lpWinfo->dwStyle & WS_POPUP ) lpTypeName = "Popup";
     else                                   lpTypeName = "Overlapped";

     wsprintf(szBuffer,"%s %04X %04X [%.14s] \"%.30s\"",
             lpTypeName,
             lpWinfo->hwnd,
             lpWinfo->hwndParent,
             (LPSTR)(lpWinfo->szClassName),
             (LPSTR)(lpWinfo->szTitle));

     nCount  = _fstrlen (szBuffer) ;
     rc      = lp->rcItem;
     rc.left = lp->rcItem.left + nIndent2;
     rc.top  = lp->rcItem.top  + 8;

     if (lpWinfo->bColor && GetBkColor(lp->hDC) == RGB(255,255,255))
          {
          COLORREF crOld = SetTextColor (lp->hDC, RGB (0,0,255));
          DrawText (lp->hDC, szBuffer, nCount, &rc, DT_SINGLELINE) ;
          SetTextColor (lp->hDC, crOld);
          }
     else
          {
          DrawText (lp->hDC, szBuffer, nCount, &rc, DT_SINGLELINE) ;
          }

     combobox_DrawFocus     (lp);
     combobox_DrawSelection (lp);
     GlobalUnlock (hWinfo);
     }


static void combobox_DrawFocus (LPDRAWITEMSTRUCT lp)
     {
     HBRUSH hbr;
     RECT   rc ;

     CopyRect (&rc, &lp->rcItem);
     InflateRect (&rc, -3, -3);

     if (lp->itemState & ODS_FOCUS)
          {
          hbr = GetStockObject (GRAY_BRUSH);
          }
     else
          {
          hbr = CreateSolidBrush (GetSysColor(COLOR_WINDOW)) ;
          }
     FrameRect (lp->hDC, &rc, hbr);
     DeleteObject (hbr);
     }


static void combobox_DrawSelection (LPDRAWITEMSTRUCT lp)
     {
     HBRUSH hbr;
     RECT   rc ;

     CopyRect (&rc, &lp->rcItem);
     InflateRect (&rc, -1, -1);

     if (lp->itemState & ODS_SELECTED)
          {
          hbr = GetStockObject (BLACK_BRUSH);
          }
     else
          {
          hbr = CreateSolidBrush (GetSysColor(COLOR_WINDOW)) ;
          }
     FrameRect (lp->hDC, &rc, hbr);
     DeleteObject (hbr);
     }


BOOL FAR PASCAL AboutDialogWndProc (HWND hDlg, unsigned m, WORD w, LONG l)
     {
     switch (m)
          {
          case WM_INITDIALOG:
               return TRUE;

          case WM_COMMAND:
               EndDialog (hDlg, 0);
               return TRUE;
          }
     return FALSE;
     }
