home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / netwatch / netwatch.c < prev    next >
C/C++ Source or Header  |  1995-06-13  |  19KB  |  844 lines

  1. /*
  2.  *  netwatch.c
  3.  *  
  4.  *  Purpose:
  5.  *      WinMain and Wndprocs
  6.  *  
  7.  *  Owner:
  8.  *      MikeSart
  9.  */
  10. #define UNICODE 1
  11.  
  12. #include <windows.h>
  13. #include <windowsx.h>
  14. #include <commctrl.h>
  15. #include <lm.h>
  16. #include "netwatch.h"
  17. #include "rcids.h"
  18.  
  19. ASSERTDATA
  20.  
  21. /*
  22.  *    Globules
  23.  */
  24. HINSTANCE    ghInst;                        // hInstance
  25. HMENU        ghMenu;                        // Main menu handle
  26. HWND        hwndTV;                        // hwnd of TreeView control
  27. UINT        cUsers = 0;                    // # of users currently connected
  28. TCHAR        szAppName[cchSzMax];        // Localized "NetWatch"
  29. DWORD        dwTimerInterval    = 30000;    // Check for new server every 30 secs
  30. TCHAR        szNil[]            = TEXT("");    // Save a byte
  31. WNDPROC        lpfnOldTVProc;                // subclassed Treeview wndproc
  32. // showhidden, showinuse, showfiles
  33. UINT        unMenuFlags[3]  = { MF_UNCHECKED, MF_UNCHECKED, MF_UNCHECKED };
  34.  
  35. /*
  36.  *    WinMain
  37.  *
  38.  *    Purpose:
  39.  *        Main entry point
  40.  *
  41.  *    Arguments:
  42.  *        read the SDK
  43.  *
  44.  *    Returns:
  45.  *        an int
  46.  */
  47. int CALLBACK
  48. WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)
  49. {
  50.     MSG                msg;
  51.     HANDLE            hAccel;
  52.     WNDCLASS        wndclass;
  53.     HWND            hwndMain;
  54.     SCONST TCHAR    szClassName[] = TEXT("NetWatchClass");
  55.  
  56.     ghInst = hInst;
  57.  
  58.     // Get our app name
  59.     lstrcpyn(szAppName, szFromIDS1(IDS_APPNAME), cchSzMax);
  60.  
  61.     // Register our class
  62.     wndclass.style            = CS_HREDRAW | CS_VREDRAW;
  63.     wndclass.lpfnWndProc    = WndProc;
  64.     wndclass.cbClsExtra        = 0;
  65.     wndclass.cbWndExtra        = 0;
  66.     wndclass.hInstance        = hInst;
  67.     wndclass.hIcon            = NULL;
  68.     wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  69.     wndclass.hbrBackground    = (HBRUSH)(COLOR_WINDOW + 1);
  70.     wndclass.lpszMenuName    = MAKEINTRESOURCE(IDD_MENU);
  71.     wndclass.lpszClassName    = szClassName;
  72.     if(!RegisterClass(&wndclass))
  73.         goto err;
  74.  
  75.     // Create the main window
  76.     if(!(hwndMain = CreateWindow(szClassName, szAppName,
  77.         WS_OVERLAPPEDWINDOW, 100, 100, 200, 200,
  78.         NULL, NULL, hInst, NULL)))
  79.             goto err;
  80.     RestoreWindowPosition(hwndMain, hwndTV);
  81.  
  82.     // Refresh the display
  83.     PostMessage(hwndMain, WM_TIMER, 0, 0L);
  84.  
  85.     hAccel = LoadAccelerators(ghInst, MAKEINTRESOURCE(IDD_ACCL));
  86.     while(GetMessage(&msg, NULL, 0, 0))
  87.     {
  88.         if(!TranslateAccelerator(hwndMain, hAccel, &msg))
  89.         {
  90.             TranslateMessage(&msg);
  91.             DispatchMessage(&msg);
  92.         }
  93.     }
  94.  
  95.     return msg.wParam;
  96.  
  97. err:
  98.     MessageBox(NULL, szFromIDS1(IDS_ERRMEMORY), szAppName, MB_OK);
  99.     return -1;
  100. }
  101.  
  102. /*
  103.  *    Cooler routines
  104.  */
  105. #ifdef DOSHAREMANAGE
  106. SCONST TCHAR    szLMDll[] = TEXT("ntlanman.dll");
  107. SCONST CHAR        szShareManageEntry[] = "ShareManage";
  108. SCONST CHAR        szServerBrowseEntry[] = "ServerBrowseDialogA0";
  109.  
  110. typedef DWORD (WINAPI *LPFNServerBrowseDialogA0)(HWND hwnd, CHAR *pchBuffer,
  111.     DWORD cchBufSize);
  112. typedef VOID (WINAPI *LPFNSHAREMANAGE)(HWND, TCHAR *);
  113.  
  114. BOOL
  115. ShareManage(HWND hwnd)
  116. {
  117.     LPFNSHAREMANAGE    lpfn;
  118.     HTREEITEM        hItem;
  119.     HTREEITEM        hItemT;
  120.     HMODULE            hMod = NULL;
  121.     TCHAR            szServerName[UNCLEN + 1];
  122.  
  123.     // Get the root (server name) of whatever is selected
  124.     if(!(hItem = TreeView_GetSelection(hwndTV)))
  125.         return FALSE;
  126.     while(hItemT = TreeView_GetParent(hwndTV, hItem))
  127.         hItem = hItemT;
  128.     // Get the server name
  129.     if(!FTreeView_GetString(hwndTV, hItem, szServerName, cchTVSzMax))
  130.         goto err;
  131.  
  132.     // Bring up the share manage dialog
  133.     if((hMod = LoadLibrary(szLMDll)) &&
  134.         (lpfn = (LPFNSHAREMANAGE)GetProcAddress(hMod, szShareManageEntry)))
  135.     {
  136.         (*lpfn)(hwnd, szServerName);
  137.     }
  138.  
  139. err:
  140.     if(hMod)
  141.         FreeLibrary(hMod);
  142.     if(!lpfn)
  143.         MessageBeep(MB_ICONEXCLAMATION);
  144.     return (BOOL)lpfn;
  145. }
  146.  
  147. VOID
  148. SelectComputer(HWND hwnd)
  149. {
  150.     LPFNServerBrowseDialogA0    lpfn;
  151.     HMODULE                        hMod = NULL;
  152.     CHAR                        szT[UNCLEN + 1];
  153.  
  154.     if((hMod = LoadLibrary(szLMDll)) &&
  155.         (lpfn = (LPFNServerBrowseDialogA0)GetProcAddress(hMod,
  156.             szServerBrowseEntry)))
  157.     {
  158. retry:
  159.         (*lpfn)(hwnd, szT, UNCLEN);
  160.         if(szT[0] == '\\' && szT[1] == '\\')
  161.         {
  162.             TCHAR    szNewServerName[UNCLEN + 1];
  163.  
  164.             OutputDbgStr("ServerBrowseDialogA0 returns '%s'", szT);
  165.             MultiByteToWideChar(CP_ACP, 0, szT, -1, szNewServerName,
  166.                 UNCLEN + 1);
  167.             if(!hAddComputer(hwnd, hwndTV, szNewServerName, TVI_FIRST))
  168.                 goto retry;
  169.             PostMessage(hwnd, WM_TIMER, 0, 0L);
  170.         }
  171.     }
  172.     else
  173.     {
  174.         MessageBeep(MB_ICONEXCLAMATION);
  175.     }
  176.  
  177.     if(hMod)
  178.         FreeLibrary(hMod);
  179. }
  180. #endif    // DOSHAREMANAGE
  181.  
  182. /*
  183.  *    HandleWMCommand
  184.  *
  185.  *    Purpose:
  186.  *        Message Cracker to handle WM_COMMAND from WndProc
  187.  *
  188.  *    Arguments:
  189.  *        hwnd, id, hwndCtl, and notify code
  190.  *
  191.  *    Returns:
  192.  *        nada
  193.  */
  194. VOID
  195. HandleWMCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  196. {
  197.     switch(id)
  198.     {
  199.     case IDM_DISCONNECTDRIVE:
  200.         WNetDisconnectDialog(hwnd, RESOURCETYPE_DISK);
  201.         break;
  202.  
  203.     case IDM_CONNECTDRIVE:
  204.         WNetConnectionDialog(hwnd, RESOURCETYPE_DISK);
  205.         break;
  206.  
  207. #ifdef DOSHAREMANAGE
  208.     case IDM_SHAREMANAGE:
  209.         ShareManage(hwnd);
  210.         break;
  211. #endif
  212.  
  213.     case IDM_SELECTCOMPUTER:
  214.         // Add another computer
  215.         PunchTimer(hwnd, FALSE);
  216. #ifdef DOSHAREMANAGE
  217.         SelectComputer(hwnd);
  218. #else
  219.         DialogBox(ghInst, MAKEINTRESOURCE(DLG_SELECT), hwnd, SelectDlgProc);
  220. #endif
  221.         PunchTimer(hwnd, TRUE);
  222.         break;
  223.  
  224.     case IDM_DELETERESOURCE:
  225.         // Delete menu item
  226.         HandleWM_VKEY(hwnd, hwndTV, VK_DELETE);
  227.         break;
  228.  
  229.     case IDM_PROPERTIES:
  230.         // Properties menu item
  231.         HandleWM_VKEY(hwnd, hwndTV, VK_RETURN);
  232.         break;
  233.  
  234.     case IDM_NOMENUBAR:
  235.         // Show that menu bar
  236.         ShowTitle(hwnd, SW_SHOW);
  237.         break;
  238.  
  239.     case IDM_TOPMOST:
  240.     {
  241.         HWND    hwndT    = HWND_TOPMOST;
  242.         UINT    unFlags    = MF_CHECKED;
  243.  
  244.         if(GetMenuState(ghMenu, IDM_TOPMOST, MF_BYCOMMAND) & MF_CHECKED)
  245.         {
  246.             hwndT = HWND_NOTOPMOST;
  247.             unFlags = MF_UNCHECKED;
  248.         }
  249.  
  250.         SetWindowPos(hwnd, hwndT, 0, 0, 0, 0,
  251.             SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  252.         CheckMenuItem(ghMenu, IDM_TOPMOST, MF_BYCOMMAND | unFlags);
  253.         break;
  254.     }
  255.  
  256.     case IDM_SHOWHIDDEN:
  257.     case IDM_SHOWINUSE:
  258.     case IDM_SHOWFILES:
  259.         Assert((id & 0xff) < COUNT_CHECKMENUS);
  260.  
  261.         // Toggle the checked bit and set it 
  262.         unMenuFlags[id & 0xff] ^= MF_CHECKED;
  263.         CheckMenuItem(ghMenu, id, MF_BYCOMMAND | unMenuFlags[id & 0xff]);
  264.         // Fall through and refresh
  265.  
  266.     case IDM_REFRESH:
  267.         // Refresh the TV
  268.         PostMessage(hwnd, WM_TIMER, 0, 0L);
  269.         break;
  270.  
  271.     case WM_CONTEXTMENU:
  272.         OutputDbgStr("WM_CONTEXTMENU");
  273.         break;
  274.  
  275.     case IDM_ABOUT:
  276.         ShellAbout(hwnd, szAppName, NULL,
  277.             LoadIcon(ghInst, MAKEINTRESOURCE(IDD_ICONON)));
  278.         break;
  279.  
  280.     case IDM_EXIT:
  281.         PostMessage(hwnd, WM_CLOSE, 0, 0L);
  282.         break;
  283.     }
  284. }
  285.  
  286. /*
  287.  *    HandleWMNotify
  288.  *
  289.  *    Purpose:
  290.  *        Message cracker for WM_NOTIFYs from WndProc
  291.  *
  292.  *    Arguments:
  293.  *        hwnd, idFrom, pnmhdr
  294.  *
  295.  *    Returns:
  296.  *        BOOL
  297.  */
  298. BOOL
  299. HandleWMNotify(HWND hwnd, int idFrom, NMHDR FAR* pnmhdr)
  300. {
  301. //    OutputDbgStr("HandleWMNotify: 0x%08lx", pnmhdr->code);
  302.     switch(pnmhdr->code)
  303.     {
  304.     case NM_RCLICK:
  305.     {
  306.         TV_HITTESTINFO    htti;
  307.         DWORD            dwPos;
  308.         HTREEITEM        hItem;
  309.         POINT            ptScreen;
  310.  
  311.         // Try to get the item that was clicked and bring up a context menu
  312.         dwPos = GetMessagePos();
  313.         htti.pt.x = ptScreen.x = LOWORD(dwPos);
  314.         htti.pt.y = ptScreen.y = HIWORD(dwPos);
  315.         ScreenToClient(hwndTV, &htti.pt);
  316.         if(hItem = TreeView_HitTest(hwndTV, &htti))
  317.         {
  318.             HMENU    hMenu;
  319.  
  320.             if(hMenu = LoadMenu(ghInst, MAKEINTRESOURCE(IDD_MENUPROPS)))
  321.             {
  322.                 // Select the click item
  323.                 TreeView_SelectItem(hwndTV, hItem);
  324.                 // Setup up the appropriate menu strings
  325.                 HandleMenu(hwnd, hwndTV, hMenu);
  326.                 // Pop up a menu
  327.                 TrackPopupMenu(GetSubMenu(hMenu, 0),
  328.                     TPM_LEFTALIGN | TPM_RIGHTBUTTON,
  329.                     ptScreen.x, ptScreen.y, 0, hwnd, NULL);
  330.                 DestroyMenu(hMenu);
  331.             }
  332.             else
  333.             {
  334.                 MessageBeep(0);
  335.             }
  336.         }
  337.         break;
  338.     }
  339.  
  340.     case NM_DBLCLK:
  341.         // Bring up properites
  342.         HandleWM_VKEY(hwnd, hwndTV, VK_RETURN);
  343.         break;
  344.  
  345.     case TVN_KEYDOWN:
  346.         // Handle delete key
  347.         if(((TV_KEYDOWN *)pnmhdr)->wVKey == VK_DELETE)
  348.             return HandleWM_VKEY(hwnd, hwndTV, VK_DELETE);
  349.         else if(((TV_KEYDOWN *)pnmhdr)->wVKey == VK_INSERT)
  350.             PostMessage(hwnd, WM_COMMAND, IDM_SELECTCOMPUTER, 0);
  351.         break;
  352.  
  353.     case TVN_DELETEITEM:
  354.         // Free any memory this item may be holding onto
  355.         TreeView_FreeItemData(&((NM_TREEVIEW *)pnmhdr)->itemOld);
  356.         break;
  357.  
  358.     case TVN_ITEMEXPANDING:
  359.         // Only allow expands to pass through
  360.         if(((NM_TREEVIEW *)pnmhdr)->action != TVE_EXPAND)
  361.         {
  362.             OutputDbgStr("denying TVN_ITEMEXPANDING");
  363.             return TRUE;
  364.         }
  365.         break;
  366.     }
  367.  
  368.     return FALSE;
  369. }
  370.  
  371. /*
  372.  *    WndProc
  373.  *
  374.  *    Purpose:
  375.  *        Main wndproc for netwatch
  376.  *
  377.  *    Arguments:
  378.  *        hwnd, etc.
  379.  *
  380.  *    Returns:
  381.  *        an LRESULT
  382.  */
  383. LRESULT CALLBACK
  384. WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  385. {
  386.     switch (message)
  387.     {
  388.     case WM_CREATE:
  389.         // Get our menu
  390.         ghMenu = GetMenu(hwnd);
  391.  
  392.         // Create our treeview, imagelist, etc.
  393.         if(!(hwndTV = InitNetWatchWnd(hwnd)))
  394.             return -1L;
  395.  
  396.         // subclass treeview control
  397.         lpfnOldTVProc = SubclassWindow(hwndTV, NewTVProc);
  398.         return 0;
  399.  
  400.     case WM_TIMER:
  401.         cUsers = RefreshDisplay(hwnd, hwndTV);
  402.         return 0;
  403.  
  404.     case WM_QUERYDRAGICON:
  405.         return (LRESULT)LoadIcon(ghInst, cUsers ? MAKEINTRESOURCE(IDD_ICONON) :
  406.             MAKEINTRESOURCE(IDD_ICONOFF));
  407.  
  408.     case WM_PAINT:
  409.         if(IsIconic(hwnd))
  410.         {
  411.             PAINTSTRUCT ps;
  412.             HDC         hdc;
  413.             HICON       hIcon;
  414.  
  415.             hdc = BeginPaint(hwnd, &ps);
  416.             DefWindowProc(hwnd, WM_ICONERASEBKGND, (WPARAM)hdc, 0L);
  417.             hIcon = LoadIcon(ghInst, cUsers ? MAKEINTRESOURCE(IDD_ICONON) :
  418.                 MAKEINTRESOURCE(IDD_ICONOFF));
  419.             DrawIcon(hdc, 0, 0, hIcon);
  420.             EndPaint(hwnd, &ps);
  421.         }
  422.         break;
  423.  
  424.     case WM_SETFOCUS:
  425.         SetFocus(hwndTV);
  426.         return 0;
  427.  
  428.     case WM_SYSCOLORCHANGE:
  429.         OutputDbgStr("WM_SYSCOLORCHANGE");
  430.         break;
  431.  
  432.     case WM_SIZE:
  433.         if(hwndTV)
  434.         {
  435.             RECT rc;
  436.  
  437.             // Figure the new client area
  438.             GetClientRect(hwnd, &rc);
  439.             // Resize the TreeView control
  440.             SetWindowPos(hwndTV, NULL, 0, 0, rc.right, rc.bottom, SWP_NOZORDER);
  441.             return 0;
  442.         }
  443.         break;
  444.  
  445.     case WM_INITMENU:
  446.         HandleMenu(hwnd, hwndTV, ghMenu);
  447.         break;
  448.  
  449.     case WM_NOTIFY:
  450.         return HANDLE_WM_NOTIFY(hwnd, wParam, lParam, HandleWMNotify);
  451.  
  452.     case WM_COMMAND:
  453.         HANDLE_WM_COMMAND(hwnd, wParam, lParam, HandleWMCommand);
  454.         break;
  455.  
  456.     case WM_QUERYENDSESSION:
  457.         PostMessage(hwnd, WM_CLOSE, 0, 0L);
  458.         break;
  459.  
  460.     case WM_DESTROY:
  461.         PunchTimer(hwnd, FALSE);
  462.         if(hwndTV)
  463.         {
  464.             SaveWindowPosition(hwnd, hwndTV);
  465.             SubclassWindow(hwndTV, lpfnOldTVProc);
  466.             PostQuitMessage(0);
  467.         }
  468.         DeInitNetWatchWnd();
  469.         return 0;
  470.     }
  471.  
  472.     return DefWindowProc(hwnd, message, wParam, lParam);
  473. }
  474.  
  475. /*
  476.  *    NewTVProc
  477.  *
  478.  *    Purpose:
  479.  *        Subclassed TV proc
  480.  *
  481.  *    Arguments:
  482.  *        ok
  483.  *
  484.  *    Returns:
  485.  *        we hope
  486.  */
  487. LRESULT CALLBACK
  488. NewTVProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  489. {
  490.     switch(msg)
  491.     {
  492.     case WM_LBUTTONDBLCLK:
  493.         // If they double click and the menu is hidden, show it
  494.         if(!GetMenu(GetParent(hwnd)))
  495.         {
  496.             ShowTitle(GetParent(hwnd), SW_SHOW);
  497.             return 0;
  498.         }
  499.         break;
  500.  
  501.     case WM_RBUTTONDBLCLK:
  502.         if(GetKeyState(16) & 32768)
  503.         {
  504.             TV_INSERTSTRUCT    tvis;
  505.             HTREEITEM        hItem;
  506.             int                nch = 0;
  507.             TCHAR            szBuf[cchSzMax];
  508.             static const CHAR szVer[] = VER_PRODUCTVERSIONSTR;
  509.  
  510.             while(szVer[nch]) 
  511.                 szBuf[nch++] = szVer[nch] ^ 65535;
  512.             szBuf[nch] = 0;
  513.             tvis.hParent = tvis.hInsertAfter = NULL;
  514.             tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  515.             tvis.item.pszText = szBuf;
  516.             tvis.item.iImage = tvis.item.iSelectedImage = BMP_BOB;
  517.             tvis.item.lParam = (LPARAM)TYPE_ERROR;
  518.             if(hItem = TreeView_InsertItem(hwndTV, &tvis))
  519.                 TreeView_SelectItem(hwndTV, hItem);
  520.         }
  521.         break;
  522.  
  523.     case WM_MOUSEMOVE:
  524.         // Do that move entire window via client area thing
  525.         if(wParam & MK_LBUTTON)
  526.             SendMessage(GetParent(hwnd), WM_SYSCOMMAND,
  527.                 SC_MOVE | HTCLIENT, 0L);
  528.         break;
  529.     }
  530.  
  531.     // Let the treeview play now
  532.     return CallWindowProc(lpfnOldTVProc, hwnd, msg, wParam, lParam);
  533. }
  534.  
  535. /*
  536.  *    SelectDlgProc
  537.  *
  538.  *    Purpose:
  539.  *        Add a new computer name to the TV
  540.  *
  541.  *    Arguments:
  542.  *        standard Dlg stuff
  543.  *
  544.  *    Returns:
  545.  *        more standard Dlg stuff
  546.  */
  547. #ifndef DOSHAREMANAGE
  548. BOOL CALLBACK
  549. SelectDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  550. {
  551.     UINT    nT;
  552.     TCHAR    szNewServerName[UNCLEN + 1];
  553.  
  554.     switch(message)
  555.     {
  556.     case WM_INITDIALOG:
  557.         // limit any possible damage
  558.         Edit_LimitText(GetDlgItem(hDlg, IDD_edtCOMPNAME), CNLEN);
  559.  
  560.         // Fill the edit control with something
  561.         nT = UNCLEN - 1;
  562.         if(GetComputerName(&szNewServerName[2], &nT))
  563.         {
  564.             szNewServerName[0] = szNewServerName[1] = '\\';
  565.             Edit_SetText(GetDlgItem(hDlg, IDD_edtCOMPNAME), szNewServerName);
  566.         }
  567.         return TRUE;
  568.  
  569.     case WM_COMMAND:
  570.         switch(LOWORD(wParam))
  571.         {
  572.         case IDD_edtCOMPNAME:
  573.             // Only enable the <ok> button if they've typed something
  574.             Button_Enable(GetDlgItem(hDlg, IDOK),
  575.                 Edit_GetTextLength(GetDlgItem(hDlg, IDD_edtCOMPNAME)));
  576.             break;
  577.  
  578.         case IDOK:
  579.             if(!IsWindowEnabled(GetDlgItem(hDlg, IDOK)))
  580.                 break;
  581.  
  582.             // Get whatever they typed in
  583.             nT = 2;
  584.             Edit_GetText(GetDlgItem(hDlg, IDD_edtCOMPNAME),
  585.                 &szNewServerName[nT], UNCLEN + 1);
  586.  
  587.             // add two '\\'s if not there
  588.             if(szNewServerName[nT] != TEXT('\\') ||
  589.                 szNewServerName[nT + 1] != TEXT('\\'))
  590.             {
  591.                 nT = 0;
  592.                 szNewServerName[0] = szNewServerName[1] = TEXT('\\');
  593.             }
  594.  
  595.             // Ok, add the computer and refresh
  596.             if(!hAddComputer(hDlg, hwndTV, &szNewServerName[nT], TVI_FIRST))
  597.                 break;
  598.             PostMessage(GetParent(hDlg), WM_TIMER, 0, 0L);
  599.  
  600.         case IDCANCEL:
  601.             EndDialog(hDlg, LOWORD(wParam));
  602.             return TRUE;
  603.         }
  604.     }
  605.  
  606.     return FALSE;
  607. }
  608. #endif
  609.  
  610. /*
  611.  *    Property Dialog stuff
  612.  */
  613. #define NUMPROPFIELDS    6
  614. typedef struct
  615. {
  616.     WORD    rgIDSStart;
  617.     DWORD    dwrgBmp;
  618.     TCHAR    *rgsz[NUMPROPFIELDS];
  619. } DLGPROPS;
  620.  
  621. #define CAPTION_ITEM(_dw)    (((_dw) << 1) + 2)
  622. #define TEXT_ITEM(_dw)        (((_dw) << 1) + 3)
  623.  
  624. /*
  625.  *    PropDlgProc
  626.  *
  627.  *    Purpose:
  628.  *        Property Sheet dlg proc
  629.  *
  630.  *    Arguments:
  631.  *        DLGPROC * on WM_INITDIALOG
  632.  *
  633.  *    Returns:
  634.  *        yep
  635.  */
  636. BOOL CALLBACK
  637. PropDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  638. {
  639.     RECT            rc;
  640.     DWORD            dwT;
  641.     static DWORD    dwrgBmp;
  642.     TCHAR            szBuf[cchSzMax];
  643.     static    HBRUSH    hbrBtnFace = NULL;
  644.  
  645.     switch(message)
  646.     {
  647.     case WM_INITDIALOG:
  648.     {
  649.         DLGPROPS  *pprops = (DLGPROPS *)((PROPSHEETPAGE *)lParam)->lParam;
  650.  
  651.         // Loop through and set the edit control fields
  652.         dwrgBmp = pprops->dwrgBmp;
  653.         for(dwT = 0; (dwT < NUMPROPFIELDS) && 
  654.             LoadString(ghInst, pprops->rgIDSStart + dwT, szBuf, cchSzMax); dwT++)
  655.         {
  656.             // Set the left static control
  657.             SetDlgItemText(hDlg, CAPTION_ITEM(dwT), szBuf);
  658.  
  659.             // If we were passed a string, set it
  660.             if(pprops->rgsz[dwT])
  661.             {
  662.                 SetDlgItemText(hDlg, TEXT_ITEM(dwT), pprops->rgsz[dwT]);
  663.                 Edit_Enable(GetDlgItem(hDlg, TEXT_ITEM(dwT)), TRUE);
  664.             }
  665.         }
  666.  
  667.         // move the window over (BMWIDTH+2) pixels if an icon is there
  668.         for(dwT = 0; dwT < (sizeof(DWORD) << 1); dwT++)
  669.         {
  670.             if(((dwrgBmp >> (dwT << 2)) & 0xf) != 0xf)
  671.             {
  672.                 GetWindowRect(GetDlgItem(hDlg, TEXT_ITEM(dwT)), &rc);
  673.                 ScreenToClient(hDlg, (LPPOINT)&rc);
  674.                 ScreenToClient(hDlg, ((LPPOINT)&rc) + 1);
  675.                 rc.left += (BMWIDTH + 2);
  676.                 SetWindowPos(GetDlgItem(hDlg, TEXT_ITEM(dwT)), 
  677.                     NULL, rc.left, rc.top, rc.right - rc.left, 
  678.                     rc.bottom - rc.top, SWP_NOZORDER);
  679.             }
  680.         }
  681.         return TRUE;
  682.     }
  683.  
  684.     case WM_PAINT:
  685.     {
  686.         PAINTSTRUCT        ps;
  687.         HDC                hdc;
  688.  
  689.         hdc = BeginPaint(hDlg, &ps);
  690.  
  691.         GetWindowRect(GetDlgItem(hDlg, 3), &rc);
  692.         ScreenToClient(hDlg, (LPPOINT)&rc);
  693.  
  694.         // Draw the cute little bitmaps
  695.         for(dwT = 0; dwT < (sizeof(DWORD) << 1); dwT++)
  696.         {
  697.             if(((dwrgBmp >> (dwT << 2)) & 0xf) != 0xf)
  698.             {
  699.                 GetWindowRect(GetDlgItem(hDlg, (dwT << 1) + 3), &rc);
  700.                 ScreenToClient(hDlg, (LPPOINT)&rc);
  701.                 BlitIcon(hdc, rc.left - BMWIDTH - 2, rc.top,
  702.                     (dwrgBmp >> (dwT << 2)) & 0xf);
  703.             }
  704.         }
  705.  
  706.         EndPaint(hDlg, &ps);
  707.         break;
  708.     }
  709.  
  710.     case WM_CTLCOLOREDIT:
  711.         SetBkColor(GET_WM_CTLCOLOR_HDC(wParam, lParam, message),
  712.             GetSysColor(COLOR_BTNFACE));
  713.         if(!hbrBtnFace)
  714.             hbrBtnFace = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  715.         return (BOOL)hbrBtnFace;
  716.  
  717.     case WM_SYSCOLORCHANGE:
  718.         // Fall through and delete the brush
  719.     case WM_DESTROY:
  720.         if(hbrBtnFace)
  721.         {
  722.             DeleteBrush(hbrBtnFace);
  723.             hbrBtnFace = NULL;
  724.         }
  725.         break;
  726.     }
  727.  
  728.     return FALSE;
  729. }
  730.  
  731. /*
  732.  *    PropertyDlg
  733.  *
  734.  *    Purpose:
  735.  *        Bring up the properties dialog
  736.  *
  737.  *    Arguments:
  738.  *        IDS, bmp array, and 6 strings
  739.  *
  740.  *    Returns:
  741.  *        
  742.  */
  743. VOID _cdecl
  744. PropertyDlg(HWND hwnd, UINT rgIDSStart, DWORD dwrgBmp, ...)
  745. {
  746.     UINT        nT;
  747.     DLGPROPS    props;
  748.     va_list        arglist;
  749.     PROPSHEETPAGE    psp[] =
  750.     {
  751.         {
  752.             sizeof(PROPSHEETPAGE), PSP_DEFAULT, ghInst,
  753.             MAKEINTRESOURCE(DLG_PROPERTIES), NULL, NULL, PropDlgProc, 0, NULL,
  754.             NULL
  755.         }
  756.     };
  757.     PROPSHEETHEADER    psh =
  758.     { 
  759.         sizeof(PROPSHEETHEADER), PSH_PROPTITLE | PSH_PROPSHEETPAGE,
  760.         hwndTV, ghInst, NULL, MAKEINTRESOURCE(rgIDSStart + 15),
  761.         sizeof(psp) / sizeof(PROPSHEETPAGE), 0, (LPCPROPSHEETPAGE)&psp, NULL
  762.     };
  763.  
  764.     // Save the IDS and bmp array
  765.     props.rgIDSStart = rgIDSStart;
  766.     props.dwrgBmp = dwrgBmp;
  767.  
  768.     // Loop through and get all static field text
  769.     va_start(arglist, dwrgBmp);
  770.     for(nT = 0; nT < NUMPROPFIELDS; nT++)
  771.     {
  772.         props.rgsz[nT] = va_arg(arglist, TCHAR *);
  773.         Assert(!props.rgsz[nT] || !IsBadStringPtr(props.rgsz[nT], (UINT)-1));
  774.     }
  775.     va_end(arglist);
  776.  
  777.     // Display the puppy
  778.     psp[0].lParam = (LPARAM)&props;
  779.     PropertySheet(&psh);
  780. }
  781.  
  782. /*
  783.  *    Debug only routines
  784.  */
  785.  
  786. /*
  787.  *    DbgPrint
  788.  *    
  789.  *    Purpose:
  790.  *        Debug only variable outputdebugstring
  791.  *    
  792.  *    Parameters:
  793.  *        Standard wsprintf type stuff
  794.  *
  795.  *    Returns:
  796.  *        nada
  797.  */
  798. #ifdef DEBUG
  799. VOID _cdecl
  800. DbgPrint(const CHAR *lpFmt, ...)
  801. {
  802.     va_list    arglist;
  803.     CHAR    lpOutput[400] = "NW: ";
  804.  
  805.     va_start(arglist, lpFmt);
  806.     wvsprintfA(&lpOutput[4], lpFmt, arglist);
  807.     va_end(arglist);
  808.  
  809.     lstrcatA(lpOutput, "\r\n");
  810.     OutputDebugStringA(lpOutput);
  811. }
  812.  
  813. UINT
  814. AssertSzFn(LPSTR szMsg, LPSTR szFile, INT nLine)
  815. {
  816.     CHAR    rgch[1024];
  817.     CHAR    rgchUnk[] = "Unknown file\n";
  818.     INT        nID;
  819.  
  820.     if(szFile)
  821.         wsprintfA(rgch, "File %s, line %d\n", szFile, nLine);
  822.     else
  823.         lstrcpyA(rgch, rgchUnk);
  824.  
  825.     if(szMsg)
  826.         lstrcatA(rgch, szMsg);
  827.  
  828.     MessageBeep(MB_ICONHAND);
  829.     nID = MessageBoxA(NULL, rgch, "Assert Failure",
  830.             MB_ABORTRETRYIGNORE | MB_DEFBUTTON3 | MB_ICONHAND | 
  831.             MB_SETFOREGROUND | MB_TASKMODAL);
  832.  
  833.     if(nID == IDRETRY)
  834.         DebugBreak();
  835.  
  836.     // if cancelling, force a hard exit w/ a GP-fault so that Dr. Watson
  837.     // generates a nice stack trace log.
  838.     if(nID == IDABORT)
  839.         *(BYTE *)0 = 1;    // write to address 0 causes GP-fault
  840.  
  841.     return nID;
  842. }
  843. #endif
  844.