/* * CSTATHLP.CPP * * CStatusHelper class to assist managing the strings for the * status bar. Here we provide menu ID to string ID mapping * services using a mapping structure in the module's resources. * * This code assumes that the status bar is a standard Windows * status bar control as we use SetWindowText (WM_SETTEXT) to set * strings. This displays messages in the 0th pane of the bar, * which is all we need. * * with SCC Changes for SCC QuickView - SDN */ #include <windows.h> #include "cstrtabl.h" #include "cstathlp.h" #include "resource.h" /* * CStatusHelper::CStatusHelper * CStatusHelper::~CStatusHelper * * Constructor Parameters: * hWnd HWND of the Status Bar control to work with. * hInst HINSTANCE of the module we're in. */ CStatusHelper::CStatusHelper(HWND hWnd, HINSTANCE hInst) { m_hWnd=hWnd; m_hInst=hInst; m_uIDCur=0xFFFFFFFF; //Nothing shown yet. m_pST=NULL; m_pPMM=NULL; m_pSMM=NULL; m_hMemSMM=NULL; //With this FALSE, many other members are ignored. m_fMapped=FALSE; } CStatusHelper::~CStatusHelper(void) { //Free up anything from MessageMap if (NULL!=m_pPMM) { LocalFree((HLOCAL)m_pPMM); m_pPMM=NULL; } if (NULL!=m_pST) { delete m_pST; m_pST=NULL; } if (NULL!=m_pNewSMM) { // UnlockResource(m_hMemSMM); LocalFree ((HLOCAL)m_pNewSMM); m_pNewSMM = NULL; m_pSMM=NULL; } if (NULL!=m_hMemSMM) { //FreeResource(m_hMemSMM); m_hMemSMM=NULL; } return; } /* * CStatusHelper::MessageMap * * Purpose: * Initializes a CStatusHelper for automated processing of * WM_MENUSELECT messages as well as setting up a list of messages * that we can display using identifiers instead of string * pointers. See MenuSelect and MessageDisplay members. * * This function is the initializer for the CStatusHelper class. * If it fails, then the caller should delete the object. * * Parameters: * hWndOwner HWND of the window owning menus we're * interested in serving * uIDRMap UINT identifying a resource mapping ID values * to string ID values * idsMin UINT specifying the lowest string ID to load * idsMax UINT specifying the hightest string ID to load * cchMax UINT maximum string length * uIDPopupMin UINT of the lowest ID to assign to popup menus * uIDPopupMax UINT of the highest ID to assign to popup menus * uIDStatic UINT of the ID for the quiescent state message * uIDBlank UINT of the ID for a blank message * uIDSysMenu UINT of the ID for the system menu * * Return Value: * BOOL TRUE if the function was successful, * FALSE otherwise. */ BOOL CStatusHelper::MessageMap(HWND hWndOwner, UINT uIDRMap , UINT idsMin, UINT idsMax, UINT cchMax, UINT uIDPopupMin , UINT uIDPopupMax, UINT uIDStatic, UINT uIDBlank, UINT uIDSysMenu) { // HMENU hMenu; HRSRC hRes; UINT i; // USHORT uID; DWORD locSize; /* * Check if we even got a valid window in the constructor * or if we've already been called. */ if (!IsWindow(m_hWnd) || m_fMapped) return FALSE; //Parameter validation if (idsMax < idsMin || uIDPopupMax < uIDPopupMin) return FALSE; //Cache away all this vital information m_hWndOwner =hWndOwner; m_idsMin =idsMin; m_idsMax =idsMax; m_cMessages =(USHORT)(idsMax-idsMin+1); m_uIDPopupMin=uIDPopupMin; m_uIDPopupMax=uIDPopupMax; m_cPopups =(USHORT)(uIDPopupMax-uIDPopupMin+1); m_uIDStatic =uIDStatic; m_uIDBlank =uIDBlank; m_uIDSysMenu =uIDSysMenu; //Get a stringtable with all the messages m_pST=new CStringTable(m_hInst); if (NULL==m_pST) return FALSE; if (!m_pST->FInit(idsMin, idsMax, CCHSTATUSMSGMAX)) return FALSE; //Load the STATMESSAGEMAP array from resources hRes=FindResource(m_hInst, MAKEINTRESOURCE(uIDRMap), RT_RCDATA); if (NULL==hRes) return FALSE; m_hMemSMM=LoadResource(m_hInst, hRes); if (NULL==m_hMemSMM) return FALSE; m_pSMM=(PSTATMESSAGEMAP)LockResource(m_hMemSMM); if (NULL==m_pSMM) return FALSE; locSize = SizeofResource(m_hInst, hRes); if (locSize==0) locSize = 0x100; m_pNewSMM = (PSTATMESSAGEMAP)LocalAlloc(LPTR, locSize); for (i=0; i<locSize; i++) *((char*)m_pNewSMM+i) = *((char *)m_pSMM+i); UnlockResource(m_hMemSMM); FreeResource(m_hMemSMM); m_hMemSMM=NULL; //Sort these for binary search lookup. Sort(); // //Allocate an array of POPUPMENUMAP structures // m_pPMM=(PPOPUPMENUMAP)LocalAlloc(LPTR // , sizeof(POPUPMENUMAP)*m_cPopups); // // if (NULL==m_pPMM) // return FALSE; // // //Initialize the array mapping popup menus to specific IDs. // uID=uIDPopupMin; // hMenu=GetMenu(m_hWndOwner); // // for (i=0; i < m_cPopups; i++) // { // m_pPMM[i].hMenu=GetSubMenu(hMenu, i); // m_pPMM[i].uID =uID++; // } //All done! m_fMapped=TRUE; return TRUE; } /* * CStatusHelper::MenuSelect * * Purpose: * Displays the appropriate message for whatever is in the * parameters of a WM_MENUSELECT message. This can only be called * if StatStripMessageMap has already been called and must be used * with the same menu the owner window had at the time of that call. * * Parameters: * wItem WORD identifying the selected item * wFlags WORD specifying the type of menu item * hMenu HMENU of the menu selected. * * Return Value: * None */ void CStatusHelper::MenuSelect(WORD wItem, WORD wFlags, HMENU hMenu) { USHORT uID; if (!m_fMapped) return; //Case 1: Menu was cancelled, display static string if (0==wItem && (WORD)0xFFFF==wFlags) uID=m_uIDStatic; else { //Case 2: System menu selected by itself. if ((MF_POPUP & wFlags) && (MF_SYSMENU & wFlags)) uID=m_uIDSysMenu; else { /* * Case 3: A popup menu was chosen: * Find the ID for the popup menu index in wItem */ if (MF_POPUP & wFlags) uID=IDFromHMenu((HMENU)wItem); else if (MFT_SEPARATOR & wFlags) uID=(UINT)wItem; else //Case 4: A menu item is selected if ( (0!=wItem) && (-1!=wItem) ) uID=(UINT)wItem; else //Case 5: Nothing is selected (e.g. separator) uID=m_uIDBlank; } } //Display the message MessageDisplay(uID); return; } /* * CStatusHelper::MessageDisplay * * Purpose: * Displays the appropriate message for a given ID value. This * can only be called if MessageMap has already been called. * * Parameters: * uID UINT of the message to display. This is not * a string ID but an ID in the STATMESSAGEMAP * structure that maps to a string ID. * * Return Value: * None */ void CStatusHelper::MessageDisplay(UINT uID) { UINT idsMsg; if (!m_fMapped) return; //If we're already displaying this ID, nothing we need to do if (m_uIDCur==uID) return; //Go look up the string ID to display. idsMsg=IStringFromID(uID); //Display it. SetWindowText(m_hWnd, (*m_pST)[idsMsg]); m_uIDCur = uID; return; } /* | | CStatusHelper::Append (UINT uID, LPSTR lpStr) | */ BOOL CStatusHelper::Append (UINT uID, LPSTR lpStr) { /* Given an ID, add the lpstr to the entry indexed by uID */ /* To be used for adding the APPNAME to the msg strings.. */ if (NULL==m_pST) return FALSE; return m_pST->Append (uID, lpStr); } /* | | CStatusHelper::Replace (UINT uID, LPSTR lpStr) | */ BOOL CStatusHelper::Replace (UINT uID, LPSTR lpStr) { /* Given an ID, add the lpstr to the entry indexed by uID */ /* To be used for adding the APPNAME to the msg strings.. */ if (NULL==m_pST) return FALSE; return m_pST->Replace (uID, lpStr); } /** ** Private members follow. **/ /* * CStatusHelper::Sort * (Private) * * Purpose: * Performs a selection sort on the STATMESSAGEMAP array that we * load from resources. Since we expect that the data is partially * sorted (we tend to place things in resources in groups of * seqential values), since the number of messages is usually * less than 200, and since we're usually doing this stuff on startup * (which takes a long time anyway), a cimple selection sort is a * better choice than a more complex qsort. * * Parameters: * None * * Return Value: * None */ void CStatusHelper::Sort(void) { UINT i, j, k; STATMESSAGEMAP smm; for (j=0; j < (UINT)(m_cMessages-1); j++) { k=j; smm.uID =m_pNewSMM[j].uID; smm.idsMsg=m_pNewSMM[j].idsMsg; for (i=j+1; i < (UINT)m_cMessages; i++) { if (m_pNewSMM[i].uID < smm.uID) { smm.uID =m_pNewSMM[i].uID; smm.idsMsg=m_pNewSMM[i].idsMsg; k=i; } } smm.uID =m_pNewSMM[j].uID; smm.idsMsg =m_pNewSMM[j].idsMsg; m_pNewSMM[j].uID =m_pNewSMM[k].uID; ; m_pNewSMM[j].idsMsg=m_pNewSMM[k].idsMsg;; m_pNewSMM[k].uID =smm.uID; m_pNewSMM[k].idsMsg=smm.idsMsg; } return; } /* * CStatusHelper::IDFromHMenu * (Private) * * Purpose: * Given a specific popup menu index, searches through m_pPMM for * a match and returns the ID associated with that menu. * * Parameters: * hMenu HMENU to of he popup menu. * * Return Value: * USHORT ID associated with the menu handle. */ USHORT CStatusHelper::IDFromHMenu(HMENU hMenu) { USHORT uID=m_uIDBlank; //Default is empty UINT i; i = (UINT) hMenu; switch ( i ) { case 0: //File uID = IDM_FILE; break; case 1: //View uID = IDM_VIEW; break; case 2: // Help uID = IDM_HELP; break; default: break; } // for (i=0; i < m_cPopups; i++) // { // if (m_pPMM[i].hMenu==hMenu) // { // uID=m_pPMM[i].uID; // break; // } // } return uID; } /* * CStatusHelper::IStringFromID * (Private) * * Purpose: * Performs a binary search in a STATMESSAGEMAP array looking for * a specific item ID returning the string ID for that item. * * Parameters: * uID USHORT item ID to locate. * * Return Value: * UINT String ID associated with wItem. */ UINT CStatusHelper::IStringFromID(USHORT uID) { UINT iLow =0; UINT iHigh=m_cMessages-1; UINT iMid; while (TRUE) { iMid=(iLow+iHigh) >> 1; if (uID < m_pNewSMM[iMid].uID) iHigh=iMid-1; else { if (uID > m_pNewSMM[iMid].uID) iLow=iMid+1; else break; //Equality } if (iHigh < iLow) break; } return m_pNewSMM[iMid].idsMsg; }