home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / inole / stastrip.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  22KB  |  855 lines

  1. /*
  2.  * STASTRIP.C
  3.  * StatStrip Control
  4.  *
  5.  * Window procedure and other functions that are frequently used in
  6.  * the life of a StatStrip.
  7.  *
  8.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Microsoft
  11.  * Internet  :  kraigb@microsoft.com
  12.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  13.  */
  14.  
  15.  
  16. #include "inoledll.h"
  17.  
  18.  
  19. /*
  20.  * StatStripWndProc
  21.  *
  22.  * Purpose:
  23.  *  Window procedure for the StatStrip control.
  24.  */
  25.  
  26. LRESULT APIENTRY StatStripWndProc(HWND hWnd, UINT iMsg
  27.     , WPARAM wParam, LPARAM lParam)
  28.     {
  29.     PSTATSTRIP      pST;
  30.     int             cyFont;
  31.     HDC             hDC;
  32.     LRESULT         lRet;
  33.  
  34.     pST=(PSTATSTRIP)GetWindowLong(hWnd, STATWL_STRUCTURE);
  35.  
  36.     switch (iMsg)
  37.         {
  38.         case WM_NCCREATE:
  39.             pST=(PSTATSTRIP)(void *)LocalAlloc(LPTR, CBSTATSTRIP);
  40.  
  41.             if (NULL==pST)
  42.                 return -1L;
  43.  
  44.             //Calc size of 0 point font, which we'll use as default.
  45.             hDC=GetDC(NULL);
  46.             cyFont=-MulDiv(10, GetDeviceCaps(hDC, LOGPIXELSY), 72);
  47.             ReleaseDC(NULL, hDC);
  48.  
  49.             pST->hFont=CreateFont(cyFont, 0, 0, 0, FW_NORMAL, FALSE
  50.                 , FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS
  51.                 , CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY
  52.                 , VARIABLE_PITCH | FF_SWISS, TEXT("MS Sans Serif"));
  53.  
  54.             /*
  55.              * If we could create the font, remember that we own it.
  56.              * If font creation failed, then we'll just do with the
  57.              * system font.
  58.              */
  59.             pST->fMyFont=(NULL!=pST->hFont);
  60.  
  61.             SetWindowLong(hWnd, STATWL_STRUCTURE, (LONG)pST);
  62.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  63.  
  64.  
  65.         case WM_DESTROY:
  66.             StatStripClean(pST, TRUE);
  67.             LocalFree((HLOCAL)(UINT)(LONG)pST);
  68.             break;
  69.  
  70.  
  71.         case WM_ERASEBKGND:
  72.             /*
  73.              * Eat this message to avoid erasing portions that we are
  74.              * going to repaint in WM_PAINT.  Part of a change-state-
  75.              * and-repaint strategy is to rely on WM_PAINT to do
  76.              * anything visual, which includes erasing invalid
  77.              * portions.  Letting WM_ERASEBKGND erase the background
  78.              * is redundant.
  79.              */
  80.             return TRUE;
  81.  
  82.  
  83.         case WM_PAINT:
  84.             StatStripPaint(hWnd, pST);
  85.             break;
  86.  
  87.  
  88.         case WM_SETFONT:
  89.             if (!IsWindowEnabled(hWnd))
  90.                 break;
  91.  
  92.             /*
  93.              * wParam has the new font.  Always repaint immediately.
  94.              * First, delete the old font only if we own it.
  95.              */
  96.             if (NULL!=pST->hFont && pST->fMyFont)
  97.                 DeleteObject(pST->hFont);
  98.  
  99.             //Save the new font but mark that we don't own it.
  100.             pST->hFont=(HFONT)wParam;
  101.             pST->fMyFont=FALSE;
  102.  
  103.             InvalidateRect(hWnd, NULL, FALSE);
  104.             UpdateWindow(hWnd);
  105.             break;
  106.  
  107.  
  108.         case WM_GETFONT:
  109.             return (LRESULT)(UINT)pST->hFont;
  110.  
  111.  
  112.         case WM_SETTEXT:
  113.             if (!IsWindowEnabled(hWnd))
  114.                 break;
  115.  
  116.             //This saves the text for us, so we only have to repaint.
  117.             lRet=DefWindowProc(hWnd, iMsg, wParam, lParam);
  118.  
  119.             InvalidateRect(hWnd, NULL, FALSE);
  120.             UpdateWindow(hWnd);
  121.             break;
  122.  
  123.  
  124.         case WM_ENABLE:
  125.             //Repaint on enabling or disabling either way.
  126.             InvalidateRect(hWnd, NULL, FALSE);
  127.             UpdateWindow(hWnd);
  128.             break;
  129.  
  130.  
  131.         //Control-specific messages
  132.         case STATM_MESSAGEMAP:
  133.             //lParam is an LPSTATMESSAGEMAPINIT
  134.             if (0L!=lParam)
  135.                 {
  136.                 LPSTATMESSAGEMAPINIT  pMI=(LPSTATMESSAGEMAPINIT)lParam;
  137.  
  138.                 return (LRESULT)StatStripMessageMap(hWnd
  139.                     , pMI->hWndOwner, pMI->hInst, pMI->uIDRMap
  140.                     , pMI->idsMin, pMI->idsMax, pMI->cchMax
  141.                     , pMI->uIDPopupMin, pMI->uIDPopupMax
  142.                     , pMI->uIDStatic, pMI->uIDBlank
  143.                     , pMI->uIDSysMenu);
  144.                 }
  145.             break;
  146.  
  147.  
  148.         case STATM_MENUSELECT:
  149.             //wParam and lParam from caller's WM_MENUSELECT message
  150.             StatStripMenuSelect(hWnd, wParam, lParam);
  151.             break;
  152.  
  153.  
  154.         case STATM_MESSAGEDISPLAY:
  155.             //wParam is ID to display
  156.             StatStripMessageDisplay(hWnd, (USHORT)wParam);
  157.             break;
  158.  
  159.  
  160.         default:
  161.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  162.         }
  163.  
  164.     return 0L;
  165.     }
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173. /*
  174.  * StatStripPaint
  175.  * Internal
  176.  *
  177.  * Purpose:
  178.  *  Provides drawing the StatStrip window with the 3-D effect and the
  179.  *  current message and the current font.
  180.  *
  181.  * Parameters:
  182.  *  hWnd            HWND of the window;
  183.  *  pST             PSTATSTRIP containing control information.
  184.  *
  185.  * Return Value:
  186.  *  None
  187.  */
  188.  
  189. void StatStripPaint(HWND hWnd, PSTATSTRIP pST)
  190.     {
  191.     int             y;
  192.     HDC             hDC;
  193.     RECT            rc;
  194.     UINT            cch;
  195.     TCHAR           szMsg[512];
  196.     HPEN            hPenFrame, hPenHigh;
  197.     HFONT           hFontT;
  198.     HBRUSH          hBr;
  199.     COLORREF        crHighlight;
  200.     TEXTMETRIC      tm;
  201.     PAINTSTRUCT     ps;
  202.  
  203.     hDC=BeginPaint(hWnd, &ps);
  204.     GetClientRect(hWnd, &rc);
  205.  
  206.     //Draw the top line using the frame color
  207.     hPenFrame=CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
  208.  
  209.     if (NULL!=hPenFrame)
  210.         {
  211.         SelectObject(hDC, hPenFrame);
  212.         MoveToEx(hDC, rc.left, rc.top, NULL);
  213.         LineTo(hDC, rc.right, rc.top);
  214.         }
  215.  
  216.     //Draw the two highlight lines
  217.     crHighlight=GetSysColor(COLOR_BTNHIGHLIGHT);
  218.  
  219.     hPenHigh=CreatePen(PS_SOLID, 1, crHighlight);
  220.  
  221.     if (NULL!=hPenHigh)
  222.         {
  223.         SelectObject(hDC, hPenHigh);
  224.         MoveToEx(hDC, rc.left, rc.bottom, NULL);
  225.         LineTo(hDC, rc.left, rc.top+1);
  226.         LineTo(hDC, rc.right, rc.top+1);
  227.         }
  228.  
  229.  
  230.     //Draw the face color avoiding the frame and highlight
  231.     rc.top +=2;
  232.     rc.left+=1;
  233.  
  234.     hBr=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  235.     FillRect(hDC, &rc, hBr);
  236.     DeleteObject(hBr);
  237.  
  238.  
  239.     //Now write the text, color sensitive to the enabled state
  240.     SetBkMode(hDC, TRANSPARENT);
  241.     SetTextColor(hDC, GetSysColor(IsWindowEnabled(hWnd)
  242.         ? COLOR_BTNTEXT : COLOR_BTNSHADOW));
  243.  
  244.     //Center the font vertically, accounting for borders on the rect.
  245.     hFontT=SelectObject(hDC, pST->hFont);
  246.  
  247.     GetTextMetrics(hDC, &tm);
  248.     y=rc.top+(((rc.bottom-rc.top)-tm.tmHeight) >> 1);
  249.     y=max(y, rc.top);
  250.  
  251.     cch=GetWindowText(hWnd, szMsg, sizeof(szMsg));
  252.     TextOut(hDC, 4, y, szMsg, cch);
  253.     SelectObject(hDC, hFontT);
  254.  
  255.     //Clean up
  256.     EndPaint(hWnd, &ps);
  257.  
  258.     DeleteObject(hPenHigh);
  259.     DeleteObject(hPenFrame);
  260.     return;
  261.     }
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269. /*
  270.  * StatStripMenuSelect
  271.  * External
  272.  *
  273.  * Purpose:
  274.  *  Displays the appropriate message for whatever is in the
  275.  *  parameters of a WM_MENUSELECT message.  This can only be called
  276.  *  if StatStripMessageMap has already been called and must be used
  277.  *  with the same menu the owner window had at the time of that call.
  278.  *
  279.  *  Since we're unpacking an application's messages for it, the app
  280.  *  and this DLL must match 16-16 and 32-32 bits.
  281.  *
  282.  * Parameters:
  283.  *  hWnd            HWND of the StatStrip
  284.  *  wParam          WPARAM of the WM_MENUSELECT message.
  285.  *  lParam          LPARAM of the WM_MENUSELECT message.
  286.  *
  287.  * Return Value:
  288.  *  None
  289.  */
  290.  
  291. void WINAPI StatStripMenuSelect(HWND hWnd, WPARAM wParam
  292.     , LPARAM lParam)
  293.     {
  294.     PSTATSTRIP      pST;
  295.     USHORT          uID;
  296.  
  297.     MENUSELECTPARAMS(wItem, wMenuFlags, hMenu);
  298.  
  299.     if (!IsWindow(hWnd) || !IsWindowEnabled(hWnd))
  300.         return;
  301.  
  302.     pST=(PSTATSTRIP)GetWindowLong(hWnd, STATWL_STRUCTURE);
  303.  
  304.     //Case 1:  Menu was cancelled, display static string
  305.     if (0==wItem && 0xFFFF==wMenuFlags)
  306.         uID=pST->uIDStatic;
  307.     else
  308.         //Case 2:  System menu selected by itself.
  309.         if (MF_POPUP & wMenuFlags && MF_SYSMENU & wMenuFlags)
  310.             uID=pST->uIDSysMenu;
  311.         else
  312.             /*
  313.              * Case 3:  A popup menu was chosen:  Find the ID for
  314.              * hMenu (in wItem)
  315.              */
  316.             if (MF_POPUP & wMenuFlags)
  317.                 uID=IDFromHMenu(pST, (HMENU)wItem);
  318.             else
  319.                 //Case 4:  A menu item is selected
  320.                 if (0!=wItem)
  321.                     uID=(UINT)wItem;
  322.                 else
  323.                     //Case 5:  Nothing is selected (like a separator)
  324.                     uID=pST->uIDBlank;
  325.  
  326.  
  327.     /*
  328.      * Go display the message.  Since all this function does extra
  329.      * that we may not have to do here is a GetWindowLong, which
  330.      * is quick, so by doing this we keep the code in one place and
  331.      * only have to test this API to test the other.
  332.      */
  333.     StatStripMessageDisplay(hWnd, uID);
  334.     return;
  335.     }
  336.  
  337.  
  338.  
  339.  
  340.  
  341.  
  342. /*
  343.  * StatStripMessageDisplay
  344.  * External
  345.  *
  346.  * Purpose:
  347.  *  Displays the appropriate message for a given ID value.   This can
  348.  *  only be called if StatStripMessageMap has already been called.
  349.  *
  350.  * Parameters:
  351.  *  hWnd            HWND of the StatStrip
  352.  *  uID             USHORT of the message to display.
  353.  *
  354.  * Return Value:
  355.  *  None
  356.  */
  357.  
  358. void WINAPI StatStripMessageDisplay(HWND hWnd, USHORT uID)
  359.     {
  360.     PSTATSTRIP      pST;
  361.     UINT            idsMsg;
  362.  
  363.     if (!IsWindow(hWnd) || !IsWindowEnabled(hWnd))
  364.         return;
  365.  
  366.     pST=(PSTATSTRIP)GetWindowLong(hWnd, STATWL_STRUCTURE);
  367.  
  368.     //Go look up the string ID to display.
  369.     idsMsg=IStringFromID(pST->pSMM, pST->cMessages, uID);
  370.     SetWindowText(hWnd, pST->ppsz[idsMsg-pST->idsMin]);
  371.     return;
  372.     }
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379. /*
  380.  * IDFromHMenu
  381.  *
  382.  * Purpose:
  383.  *  Given a specific menu handle, searches through pST->pPMM for a
  384.  *  match and returns the ID associated with that menu.
  385.  *
  386.  * Parameters:
  387.  *  pST             PSTATSTRIP of the control
  388.  *  hMenu           HMENU to search for
  389.  *
  390.  * Return Value:
  391.  *  USHORT          ID associated with the menu handle.
  392.  */
  393.  
  394. USHORT IDFromHMenu(PSTATSTRIP pST, HMENU hMenu)
  395.     {
  396.     USHORT      uID=pST->uIDBlank;      //Default is empty
  397.     UINT        i;
  398.  
  399.    #ifdef WIN32
  400.     /*
  401.      * Under Win32 the hMenu passed here from the WM_MENUSELECT
  402.      * message will only be the index to the actual menu.  We
  403.      * have to use GetSubMenu from the top-level menu using this
  404.      * index to actually get the menu handle.
  405.      */
  406.  
  407.     hMenu=GetSubMenu(GetMenu(pST->hWndOwner), (UINT)hMenu);
  408.    #endif
  409.  
  410.     for (i=0; i < pST->cPopups; i++)
  411.         {
  412.         if (pST->pPMM[i].hMenu==hMenu)
  413.             {
  414.             uID=pST->pPMM[i].uID;
  415.             break;
  416.             }
  417.         }
  418.  
  419.     return uID;
  420.     }
  421.  
  422.  
  423.  
  424.  
  425.  
  426.  
  427.  
  428. /*
  429.  * IStringFromID
  430.  *
  431.  * Purpose:
  432.  *  Performs a binary search in a STATMESSAGEMAP array looking for
  433.  *  a specific item ID returning the string ID for that item.
  434.  *
  435.  * Parameters:
  436.  *  pSMM            PSTATMESSAGEMAP to search
  437.  *  cItems          USHORT size of the map in elements
  438.  *  uID             USHORT item ID to locate.
  439.  *
  440.  * Return Value:
  441.  *  UINT            String ID associated with wItem.
  442.  */
  443.  
  444. UINT IStringFromID(PSTATMESSAGEMAP pSMM, USHORT cItems, USHORT uID)
  445.     {
  446.     UINT        iLow =0;
  447.     UINT        iHigh=cItems-1;
  448.     UINT        iMid;
  449.  
  450.     while (TRUE)
  451.         {
  452.         iMid=(iLow+iHigh) >> 1;
  453.  
  454.         if (uID < pSMM[iMid].uID)
  455.             iHigh=iMid-1;
  456.         else
  457.             {
  458.             if (uID > pSMM[iMid].uID)
  459.                 iLow=iMid+1;
  460.             else
  461.                 break;    //Equality
  462.             }
  463.  
  464.         if (iHigh < iLow)
  465.             break;
  466.         }
  467.  
  468.     return pSMM[iMid].idsMsg;
  469.     }
  470.  
  471.  
  472.  
  473.  
  474. /*
  475.  * StatStripMessageMap
  476.  *
  477.  * Purpose:
  478.  *  Initializes the message mappings in the StatStrip for subsequent
  479.  *  use with StatMessageMenuSelect.  If this function is called more
  480.  *  than once then any previous initialization is cleaned up so
  481.  *  previous message IDs will then be invalid.
  482.  *
  483.  *  The total number of messages is inferred by (idsMax-idsMin+1).
  484.  *  The maximum number of popup menu items we'll hold is inferred by
  485.  *  (uIDPopupMax-uIDPopupMin+1).
  486.  *
  487.  * Parameters:
  488.  *  hWnd            HWND of the StatStrip control.
  489.  *  hWndOwner       HWND of the window owning menus.
  490.  *  hInst           HINSTANCE of the app from which to load resources
  491.  *  uIDRMap         UINT identifying a resource mapping ID values
  492.  *                  to string ID values.
  493.  *  idsMin          UINT specifying the lowest string ID to load.
  494.  *  idsMax          UINT specifying the hightest string ID to load.
  495.  *  cchMax          UINT maximum string length.
  496.  *  uIDPopupMin     USHORT lowest ID to assign to popup menus.
  497.  *  uIDPopupMax     USHORT highest ID to assign to popup menus.
  498.  *  uIDStatic       USHORT ID for the quiescent message.
  499.  *  uIDBlank        USHORT ID for a blank message.
  500.  *  uIDSysMenu      USHORT ID for the system menu.
  501.  *
  502.  * Return Value:
  503.  *  BOOL            TRUE if the function was successful, FALSE
  504.  *                  otherwise.
  505.  */
  506.  
  507. BOOL WINAPI StatStripMessageMap(HWND hWnd, HWND hWndOwner
  508.     , HINSTANCE hInst , UINT uIDRMap, UINT idsMin, UINT idsMax
  509.     , UINT cchMax, USHORT uIDPopupMin, USHORT uIDPopupMax
  510.     , USHORT uIDStatic, USHORT uIDBlank, USHORT uIDSysMenu)
  511.     {
  512.     PSTATSTRIP      pST;
  513.     HMENU           hMenu;
  514.     HRSRC           hRes;
  515.     UINT            i;
  516.     USHORT          uID;
  517.  
  518.    #ifdef WIN32
  519.     DWORD           cbRes;
  520.     DWORD           dwPrevProt;
  521.    #endif
  522.  
  523.     if (!IsWindow(hWnd))
  524.         return FALSE;
  525.  
  526.     pST=(PSTATSTRIP)GetWindowLong(hWnd, STATWL_STRUCTURE);
  527.  
  528.     if (NULL==pST)
  529.         return FALSE;
  530.  
  531.     //Parameter validation
  532.     if (NULL==hInst || idsMax < idsMin || uIDPopupMax < uIDPopupMin)
  533.         return FALSE;
  534.  
  535.     //Clean ourselves out if we've already initialized.
  536.     if (pST->fMapped)
  537.         StatStripClean(pST, FALSE);
  538.  
  539.     pST->hWndOwner  =hWndOwner;
  540.  
  541.     pST->idsMin     =idsMin;
  542.     pST->idsMax     =idsMax;
  543.     pST->cMessages  =(USHORT)(idsMax-idsMin+1);
  544.  
  545.     pST->uIDPopupMin=uIDPopupMin;
  546.     pST->uIDPopupMax=uIDPopupMax;
  547.     pST->cPopups    =(USHORT)(uIDPopupMax-uIDPopupMin+1);
  548.  
  549.     pST->uIDStatic  =uIDStatic;
  550.     pST->uIDBlank   =uIDBlank;
  551.     pST->uIDSysMenu =uIDSysMenu;
  552.  
  553.     //Load the STATMESSAGEMAP array from our resources.
  554.     hRes=FindResource(hInst, MAKEINTRESOURCE(uIDRMap), RT_RCDATA);
  555.  
  556.     if (NULL==hRes)
  557.         return FALSE;
  558.  
  559.  
  560.     pST->hMemSMM=LoadResource(hInst, hRes);
  561.  
  562.     if (NULL==pST->hMemSMM)
  563.         return FALSE;
  564.  
  565.     pST->pSMM=(PSTATMESSAGEMAP)LockResource(pST->hMemSMM);
  566.  
  567.     if (NULL==pST->pSMM)
  568.         {
  569.         StatStripClean(pST, FALSE);
  570.         return FALSE;
  571.         }
  572.  
  573.    #ifdef WIN32
  574.     /*
  575.      * In Win32 resource pages are read-only when loaded.
  576.      * Change to read-write for the purposes of sorting
  577.      * initially.
  578.      */
  579.     cbRes=SizeofResource(hInst, hRes);
  580.     VirtualProtect(pST->pSMM, cbRes, PAGE_READWRITE, &dwPrevProt);
  581.    #endif
  582.  
  583.     //Sort these for binary search lookup.
  584.     StatMessageMapSort(pST->pSMM, pST->cMessages);
  585.  
  586.    #ifdef WIN32
  587.     VirtualProtect(pST->pSMM, cbRes, dwPrevProt, &dwPrevProt);
  588.    #endif
  589.  
  590.     //Allocate space for string pointers
  591.     pST->ppsz=(LPTSTR *)LocalAlloc(LPTR
  592.         , sizeof(LPTSTR)*pST->cMessages);
  593.  
  594.     if (NULL==pST->ppsz)
  595.         {
  596.         StatStripClean(pST, FALSE);
  597.         return FALSE;
  598.         }
  599.  
  600.     //Load the stringtable for messages.
  601.     pST->hMemSzStat=HStringCache(hInst, idsMin, idsMax, cchMax
  602.         , pST->ppsz);
  603.  
  604.     if (NULL==pST->hMemSzStat)
  605.         {
  606.         StatStripClean(pST, FALSE);
  607.         return FALSE;
  608.         }
  609.  
  610.     //Allocate an array of POPUPMENUMAP structures
  611.     pST->pPMM=(PPOPUPMENUMAP)(void *)LocalAlloc(LPTR
  612.         , sizeof(POPUPMENUMAP)*pST->cPopups);
  613.  
  614.     if (NULL==pST->pPMM)
  615.         {
  616.         StatStripClean(pST, FALSE);
  617.         return FALSE;
  618.         }
  619.  
  620.     //Initialize the array mapping popup menus to specific IDs.
  621.     uID=uIDPopupMin;
  622.     hMenu=GetMenu(hWndOwner);
  623.  
  624.     for (i=0; i < pST->cPopups; i++)
  625.         {
  626.         pST->pPMM[i].hMenu=GetSubMenu(hMenu, i);
  627.         pST->pPMM[i].uID  =uID++;
  628.         }
  629.  
  630.     pST->fMapped=TRUE;
  631.     return TRUE;
  632.     }
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640. /*
  641.  * StatStripClean
  642.  *
  643.  * Purpose:
  644.  *  Cleans out any allocations in a STATSTRIP.
  645.  *
  646.  * Parameters:
  647.  *  pST             PSTATSTRIP to clean
  648.  *  fIncludeFont    BOOL indicates if we're to also clean the font.
  649.  *                  This is FALSE from StatMessageMap, TRUE from
  650.  *                  WM_DESTROY.
  651.  *
  652.  * Return Value:
  653.  *  None
  654.  */
  655.  
  656. void StatStripClean(PSTATSTRIP pST, BOOL fIncludeFont)
  657.     {
  658.     //Free up anything from StatMessageMap
  659.     if (NULL!=pST->pPMM)
  660.         {
  661.         LocalFree((HLOCAL)(UINT)(LONG)pST->pPMM);
  662.         pST->pPMM=NULL;
  663.         }
  664.  
  665.     if (NULL!=pST->ppsz)
  666.         {
  667.         LocalFree((HLOCAL)(UINT)(LONG)pST->ppsz);
  668.         pST->ppsz=NULL;
  669.         }
  670.  
  671.     if (NULL!=pST->hMemSzStat)
  672.         {
  673.         HStringCacheFree(pST->hMemSzStat);
  674.         pST->hMemSzStat=NULL;
  675.         }
  676.  
  677.     if (NULL!=pST->pSMM)
  678.         {
  679.        #ifndef WIN32
  680.         UnlockResource(pST->hMemSMM);
  681.        #endif
  682.         pST->pSMM=NULL;
  683.         }
  684.  
  685.     if (NULL!=pST->hMemSMM)
  686.         {
  687.         FreeResource(pST->hMemSMM);
  688.         pST->hMemSMM=NULL;
  689.         }
  690.  
  691.     //Delete the old font only if we own it.
  692.     if (fIncludeFont)
  693.         {
  694.         if (NULL!=pST->hFont && pST->fMyFont)
  695.             {
  696.             DeleteObject(pST->hFont);
  697.             pST->hFont=NULL;
  698.             }
  699.         }
  700.  
  701.     return;
  702.     }
  703.  
  704.  
  705.  
  706.  
  707.  
  708. /*
  709.  * HStringCache
  710.  *
  711.  * Purpose:
  712.  *  Allocates memory and reads a stringtable into that memory.
  713.  *  Pointers to the strings in the memory are then stored at ppsz
  714.  *  which is assumed to be (idsMax-idsMin+1) strings long.
  715.  *
  716.  * Parameters:
  717.  *  hInst           HINSTANCE of the application
  718.  *  idsMin          UINT string index to start loading
  719.  *  idsMax          UINT maximum string index in this table.
  720.  *  cchMax          UINT length of the longest string in TCHARs.
  721.  *  ppsz            LPTSTR * to an array in which to store pointers.
  722.  *
  723.  * Return Value:
  724.  *  HGLOBAL         Handle to the memory.  NULL if memory could
  725.  *                  not be allocated.
  726.  */
  727.  
  728. HGLOBAL HStringCache(HINSTANCE hInst, UINT idsMin, UINT idsMax
  729.     , UINT cchMax, LPTSTR *ppsz)
  730.     {
  731.     HANDLE      hMem;
  732.     LPTSTR      pch;
  733.     UINT        cchUsed=0;
  734.     UINT        cch;
  735.     UINT        i, cStrings;
  736.  
  737.     cStrings=idsMax-idsMin+1;
  738.     hMem=GlobalAlloc(GHND, cStrings * cchMax * sizeof(TCHAR));
  739.  
  740.     if (NULL!=hMem)
  741.         {
  742.         pch=GlobalLock(hMem);
  743.  
  744.         /*
  745.          * Load the strings into the memory and retain the specific
  746.          * pointer to that string.
  747.          */
  748.         for (i=0; i < cStrings; i++)
  749.             {
  750.             cch=LoadString(hInst, i+idsMin, (LPTSTR)(pch+cchUsed)
  751.                 , cchMax-1);
  752.             ppsz[i]=(LPTSTR)(pch+cchUsed);
  753.  
  754.             /*
  755.              * Add one char to cch to include a NULL.  The memory
  756.              * was ZEROINITed on allocation so by skipping a TCHAR
  757.              * we get the NULL.
  758.              */
  759.             cchUsed+=cch+sizeof(TCHAR);
  760.             }
  761.  
  762.         /*
  763.          * Memory is locked for the duration of the app.  Don't
  764.          * bother reallocating since we might have to recalc
  765.          * all the pointers to the strings again.
  766.          */
  767.         }
  768.  
  769.     return hMem;
  770.     }
  771.  
  772.  
  773.  
  774.  
  775.  
  776. /*
  777.  * HStringCacheFree
  778.  *
  779.  * Purpose:
  780.  *  Frees up any memory associated with the string cache from
  781.  *  HStringCache.
  782.  *
  783.  * Parameters:
  784.  *  hMem            HGLOBAL to the memory containing the cahce.
  785.  *
  786.  * Return Value:
  787.  *  None
  788.  */
  789.  
  790. void HStringCacheFree(HGLOBAL hMem)
  791.     {
  792.     if (NULL!=hMem)
  793.         {
  794.         GlobalUnlock(hMem);
  795.         GlobalFree(hMem);
  796.         }
  797.     return;
  798.     }
  799.  
  800.  
  801.  
  802.  
  803.  
  804. /*
  805.  * StatMessageMapSort
  806.  *
  807.  * Purpose:
  808.  *  Performs a selection sort on the STATMESSAGEMAP array that we
  809.  *  load from our resource.  Since we expect that the data is
  810.  *  partially sorted (we tend to place things in resources in groups
  811.  *  of seqential values), since the number of messages is usually
  812.  *  < 200, and since we're in startup (which takes a long time
  813.  *  anyway), selection sort is a better choice to implement over
  814.  *  qsort saving much code.
  815.  *
  816.  * Parameters:
  817.  *  pSMM            PSTATMESSAGEMAP to sort
  818.  *  n               USHORT number of elements in the array.
  819.  *
  820.  * Return Value:
  821.  *  None
  822.  */
  823.  
  824. void StatMessageMapSort(PSTATMESSAGEMAP pSMM, USHORT n)
  825.     {
  826.     USHORT          i, j, k;
  827.     STATMESSAGEMAP  smm;
  828.  
  829.     for (j=0; j < (UINT)(n-1); j++)
  830.         {
  831.         k=j;
  832.         smm.uID   =pSMM[j].uID;
  833.         smm.idsMsg=pSMM[j].idsMsg;
  834.  
  835.         for (i=j+1; i < (UINT)n; i++)
  836.             {
  837.             if (pSMM[i].uID < smm.uID)
  838.                 {
  839.                 smm.uID   =pSMM[i].uID;
  840.                 smm.idsMsg=pSMM[i].idsMsg;
  841.                 k=i;
  842.                 }
  843.             }
  844.  
  845.         smm.uID       =pSMM[j].uID;
  846.         smm.idsMsg    =pSMM[j].idsMsg;
  847.         pSMM[j].uID   =pSMM[k].uID;
  848.         pSMM[j].idsMsg=pSMM[k].idsMsg;
  849.         pSMM[k].uID   =smm.uID;
  850.         pSMM[k].idsMsg=smm.idsMsg;
  851.         }
  852.  
  853.     return;
  854.     }
  855.