mruex.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 16k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. //#include "mruex.h"
  4. // this is swiped from comctl32mru.c
  5. #define MRU_ORDERDIRTY 0x1000
  6. #define DM_MRULAZY  DM_TRACE
  7. typedef struct tagMRUDATA
  8. {
  9.     UINT fFlags;
  10.     UINT uMax;
  11.     MRUCMPPROC lpfnCompare;
  12.     HKEY hKey;
  13. #ifdef DEBUG
  14.     TCHAR szSubKey[32];
  15. #endif
  16.     LPDWORD cOrder;
  17. } MRUDATA, *PMRUDATA;
  18. #define szMRUEX         TEXT("MRUListEx")
  19. #define szMRUEX_OLD     TEXT("MRUList")
  20. #define c_szShell       TEXT("Shell")
  21. #define NTHSTRING(p, n) (*((LPTSTR FAR *)((LPBYTE)p+sizeof(MRUDATA))+n))
  22. #define NTHDATA(p, n) (*((LPBYTE FAR *)((LPBYTE)p+sizeof(MRUDATA))+n))
  23. #define NUM_OVERHEAD 3
  24. #define MAX_MRU_INDEXSTR        15
  25. //----------------------------------------------------------------------------
  26. //  For binary data we stick the size of the data at the begining and store the
  27. //  whole thing in one go.
  28. // Use this macro to get the original size of the data.
  29. #define DATASIZE(p)  (*((LPDWORD)p))
  30. // And this to get a pointer to the original data.
  31. #define DATAPDATA(p) (p + sizeof(DWORD))
  32. #define DATAPDATAEX(p) ((LPDWORD)(((DWORD)p) + sizeof(DWORD)))
  33. HRESULT GetIndexStrFromIndex(DWORD dwIndex, LPTSTR pszIndexStr, DWORD cchIndexStrSize)
  34. {
  35.     wsprintf(pszIndexStr, TEXT("%d"), dwIndex);
  36.     return S_OK;
  37. }
  38. #define MAX_CHAR 126
  39. #define BASE_CHAR TEXT('a')
  40. DWORD ConvertOldIndexToNewIndex(TCHAR chOldMRUIndex)
  41. {
  42.     //  limit to 126 so that we don't use extended chars
  43.     ASSERT(chOldMRUIndex <= MAX_CHAR);
  44.     return (chOldMRUIndex - BASE_CHAR);
  45. }
  46. LPDWORD GetMRUValue(HKEY hkeySubKey, LPCTSTR pszRegValue)
  47. {
  48.     LPDWORD pResult = NULL;
  49.     DWORD cbVal;
  50.     // Get the size
  51.     if (ERROR_SUCCESS == RegQueryValueEx(hkeySubKey, pszRegValue, NULL, NULL, NULL, &cbVal))
  52.     {
  53.         // Binary data has the size at the begining so we'll need a little extra room.
  54.         pResult = (LPDWORD)Alloc(cbVal + sizeof(DWORD));
  55.         if (pResult)
  56.         {
  57.             DATASIZE(pResult) = cbVal;     // Set the size.
  58.             // Can we successfully get the data?
  59.             if (ERROR_SUCCESS != RegQueryValueEx(hkeySubKey, pszRegValue, NULL, NULL, (LPBYTE) DATAPDATAEX(pResult), &cbVal))
  60.             {
  61.                 // No, so free the buffer and make sure we return NULL.
  62.                 Free((HLOCAL)pResult);
  63.                 pResult = NULL;
  64.             }
  65.         }
  66.     }
  67.     return pResult;
  68. }
  69. HRESULT SetMRUValue(HKEY hkeySubKey, LPCTSTR pszRegValue, LPDWORD pData)
  70. {
  71.     HRESULT hr = E_FAIL;
  72.     // The first DWORD in pData is the size of the rest of pData.
  73.     // The real data is stored starting in the second DWORD.
  74.     if (ERROR_SUCCESS == RegSetValueEx(hkeySubKey, pszRegValue, NULL, REG_BINARY, (LPBYTE)DATAPDATAEX(pData), DATASIZE(pData)))
  75.         hr = S_OK;
  76.     return hr;
  77. }
  78. HRESULT ImportOldMRU(HKEY hkeySubKey, LPDWORD pOrder, LPDWORD pcbVal)
  79. {
  80.     HRESULT hr = E_FAIL;
  81.     TCHAR szOldMRU[MAX_PATH];   // The old MRU where chars and less than MAX_PATH
  82.     DWORD cbOldMRUStr = sizeof(szOldMRU);
  83.     if (ERROR_SUCCESS == RegQueryValueEx(hkeySubKey, (LPTSTR)szMRUEX_OLD, NULL, NULL, (LPBYTE)szOldMRU, &cbOldMRUStr))
  84.     {
  85.         DWORD dwIndex = 0;
  86.         TCHAR szOldIndex[2];
  87.         szOldIndex[1] = TEXT(''); // Terminate the 2 char string.
  88.         while (TEXT('') != szOldMRU[dwIndex]) // While we aren't at the end of the list
  89.         {
  90.             DWORD dwNewIndex = ConvertOldIndexToNewIndex(szOldMRU[dwIndex]);
  91.             LPDWORD pData;
  92.             szOldIndex[0] = szOldMRU[dwIndex]; // Create the Old MRU Index in the form of a string.
  93.             pData = GetMRUValue(hkeySubKey, szOldIndex);
  94.             if (pData)
  95.             {
  96.                 TCHAR szNewIndexStr[MAX_MRU_INDEXSTR];
  97.                 GetIndexStrFromIndex(dwNewIndex, szNewIndexStr, ARRAYSIZE(szNewIndexStr));
  98.                 SetMRUValue(hkeySubKey, szNewIndexStr, pData);
  99.                 Free((HLOCAL)pData);
  100.             }
  101.             pOrder[dwIndex] = dwNewIndex;    // Copy from the old Index to the new one.
  102.             dwIndex++;
  103.         }
  104.         pOrder[dwIndex] = -1;    // Terminate the index.
  105.         *pcbVal = sizeof(*pOrder) * dwIndex;    // Set the size.
  106.         hr = S_OK;
  107.     }
  108.     return hr;
  109. }
  110. //----------------------------------------------------------------------------
  111. // Internal memcmp - saves loading crt's, cdecl so we can use
  112. // as MRUCMPDATAPROC
  113. int CDECL _mymemcmp(const void *pBuf1, const void *pBuf2, size_t cb)
  114. {
  115.     UINT i;
  116.     const BYTE *lpb1, *lpb2;
  117.     ASSERT(pBuf1);
  118.     ASSERT(pBuf2);
  119.     lpb1 = (const BYTE *)pBuf1; lpb2 = (const BYTE *)pBuf2;
  120.     for (i=0; i < cb; i++)
  121.     {
  122.         if (*lpb1 > *lpb2)
  123.             return 1;
  124.         else if (*lpb1 < *lpb2)
  125.             return -1;
  126.         lpb1++;
  127.         lpb2++;
  128.     }
  129.     return 0;
  130. }
  131. BOOL MRUIsSameData(PMRUDATA pMRU, BYTE FAR* pVal, const void FAR *lpData, UINT cbData)
  132. {
  133.     int cbUseSize;
  134.     MRUCMPDATAPROC lpfnCompare;
  135.     lpfnCompare = (MRUCMPDATAPROC)(pMRU->lpfnCompare);
  136.     // if there's something other than a mem compare,
  137.     // don't require the sizes to be equal in order for the
  138.     // data to be equivalent.
  139.     if ((LPVOID)(pMRU->lpfnCompare) == (LPVOID)(_mymemcmp)) {
  140.         if (DATASIZE(pVal) != cbData)
  141.             return FALSE;
  142.         cbUseSize = cbData;
  143.     }  else {
  144.         cbUseSize = min(DATASIZE(pVal), cbData);
  145.     }
  146.     return ((*lpfnCompare)(lpData, DATAPDATA(pVal), cbUseSize) == 0);
  147. }
  148. //----------------------------------------------------------------------------
  149. HANDLE CreateMRUListLazyEx(LPMRUINFO lpmi, const void FAR *lpData, UINT cbData, LPINT lpiSlot)
  150. {
  151.     HANDLE hMRU = NULL;
  152.     LPDWORD pOrder, pNewOrder, pTemp;
  153.     LPBYTE pVal;
  154.     DWORD cbVal;
  155. #ifdef WIN32
  156.     DWORD dwDisposition;
  157. #endif
  158.     DWORD dwType;
  159.     PMRUDATA pMRU = NULL;
  160.     HKEY hkeySubKey = NULL;
  161.     TCHAR szTemp[10];
  162.     UINT uMax = lpmi->uMax;
  163.     HKEY hKey = lpmi->hKey;
  164.     LPCTSTR lpszSubKey = lpmi->lpszSubKey;
  165.     MRUCMPPROC lpfnCompare = lpmi->lpfnCompare;
  166.     int cb;
  167. #ifdef DEBUG
  168.     DWORD dwStart = GetTickCount();
  169. #endif
  170.     if (!lpfnCompare) {
  171.         lpfnCompare = (lpmi->fFlags & MRU_BINARY) ? (MRUCMPPROC)_mymemcmp : (MRUCMPPROC)lstrcmpi;
  172.     }
  173.     if (RegCreateKeyEx(hKey, lpszSubKey, 0L, (LPTSTR)c_szShell, REG_OPTION_NON_VOLATILE,
  174.                        KEY_READ | KEY_WRITE, NULL, &hkeySubKey, &dwDisposition) != ERROR_SUCCESS)
  175.         goto Error1;
  176.     cbVal = ((LONG)uMax + 1) * sizeof(DWORD);
  177.     pOrder = (LPDWORD)Alloc(cbVal);
  178.     if (!pOrder) {
  179.         goto Error1;
  180.     }
  181.     // Do we already have the new MRU Index?
  182.     if (RegQueryValueEx(hkeySubKey, (LPTSTR)szMRUEX, NULL, &dwType, (LPBYTE)pOrder, &cbVal) == ERROR_SUCCESS)
  183.     {
  184.         // Then validate it.  You can never trust the registry not to be
  185.         // corrupted.
  186.         // Must be at least the size of a DWORD
  187.         if (cbVal < sizeof(DWORD)) goto NotInRegistry;
  188.         // Must be a multiple of DWORD in length
  189.         if (cbVal % sizeof(DWORD)) goto NotInRegistry;
  190.         // Must end in a -1
  191.         if (pOrder[cbVal/sizeof(DWORD) - 1] != (DWORD)-1) goto NotInRegistry;
  192.         // If any interior values are corrupted, we will detect that
  193.         // during the traversal loop.
  194.     }
  195.     else
  196.     {
  197. NotInRegistry:
  198.         // The new MRU didn't exist, so look for an old one to import.
  199.         if (FAILED(ImportOldMRU(hkeySubKey, pOrder, &cbVal)))
  200.         {
  201.             // There wasn't an old MRU to import, so start fresh
  202.             *pOrder = (DWORD)-1;
  203.         }
  204.     }
  205.     // We allocate room for the MRUDATA structure, plus the order list,
  206.     // and the list of strings.
  207.     cb = (lpmi->fFlags & MRU_BINARY) ? sizeof(LPBYTE) : sizeof(LPTSTR);
  208.     pMRU = (PMRUDATA)Alloc(sizeof(MRUDATA)+(uMax*cb));
  209.     if (!pMRU) {
  210.         goto Error2;
  211.     }
  212.     // Allocate space for the order list
  213.     pMRU->cOrder = (LPDWORD)Alloc((uMax+1)*sizeof(DWORD));
  214.     if (!pMRU->cOrder) {
  215.         Free(pMRU);
  216.         pMRU = NULL;
  217.         goto Error2;
  218.     }
  219.     pMRU->fFlags = lpmi->fFlags;
  220.     pMRU->uMax = uMax;
  221.     pMRU->lpfnCompare = lpfnCompare;
  222.     pMRU->hKey = hkeySubKey;
  223. #ifdef DEBUG
  224.     lstrcpyn(pMRU->szSubKey, lpszSubKey, ARRAYSIZE(pMRU->szSubKey));
  225. #endif
  226.     // Traverse through the MRU list, adding strings to the end of the
  227.     // list.
  228.     for (pTemp = pOrder, pNewOrder = pMRU->cOrder; *pTemp != (DWORD)-1; ++pTemp)
  229.     {
  230.         GetIndexStrFromIndex(*pTemp, szTemp, ARRAYSIZE(szTemp));
  231.         if (lpmi->fFlags & MRU_BINARY) {
  232.             // Check if in range and if we have already used this letter.
  233.             if (*pTemp>=uMax || NTHDATA(pMRU, *pTemp)) {
  234.                 continue;
  235.             }
  236.             // BUGBUG: Convert to use GetMRUValue();
  237.             // Get the value from the registry
  238.             cbVal = 0;
  239.             // first find the size
  240.             if ((RegQueryValueEx(hkeySubKey, szTemp, NULL, &dwType, NULL, &cbVal)
  241.                  != ERROR_SUCCESS) || (dwType != REG_BINARY))
  242.                 continue;
  243.             // Binary data has the size at the begining so we'll need a little extra room.
  244.             pVal = (LPBYTE)Alloc(cbVal + sizeof(DWORD));
  245.             if (!pVal) {
  246.                 // BUGBUG perhaps sort of error is in order.
  247.                 continue;
  248.             }
  249.             // now really get it
  250.             DATASIZE(pVal) = cbVal;
  251.             if (RegQueryValueEx(hkeySubKey, szTemp, NULL, &dwType, pVal+sizeof(DWORD),
  252.                                 (LPDWORD)pVal) != ERROR_SUCCESS)
  253.                 continue;
  254.             // Note that blank elements ARE allowed in the list.
  255.             NTHDATA(pMRU, *pTemp) = pVal;
  256.             *pNewOrder++ = *pTemp;
  257.             //
  258.             // OPTIMIZATION
  259.             //   If lpData and lpiSlot are specified, we stop the enumeratation
  260.             //  when we find the item. 
  261.             //
  262.             if (lpData && lpiSlot) {
  263.                 // Check if we have the specified one or not.
  264.                 if (MRUIsSameData(pMRU, pVal, lpData, cbData)) {
  265.                     // Found it. 
  266.                     *lpiSlot = pNewOrder - pMRU->cOrder;
  267.                     TraceMsg(DM_MRULAZY, "CreateMRUListLazy found it. Copying %d", *pTemp);
  268.                     pMRU->fFlags |= MRU_LAZY;
  269.                     //
  270.                     // Copy the rest of slot. Notice that we don't load
  271.                     // data for those slot.
  272.                     //
  273.                     for (pTemp++; -1 != *pTemp; pTemp++) {
  274.                         *pNewOrder++ = *pTemp;
  275.                     }
  276.                     break;
  277.                 }
  278.             }
  279.         } else {
  280.             AssertMsg(0, TEXT("Functionality NOT IMPLEMENTED"));
  281.         }
  282.     }
  283.     // terminate the order list
  284.     *pNewOrder = (DWORD)-1;
  285.     if (lpData && lpiSlot) {
  286.         TraceMsg(DM_MRULAZY, "CreateMRUListLazy. End of loop. %c", pMRU->cOrder);
  287.         // If we failed to find, put -1 in it. 
  288.         if (!(pMRU->fFlags & MRU_LAZY)) {
  289.             *lpiSlot = -1;
  290.         }
  291.     }
  292.     /* Actually, this is success rather than an error.
  293.      */
  294.     goto Error2;
  295. Error2:
  296.     if (pOrder)
  297.         Free((HLOCAL)pOrder);
  298. Error1:
  299.     if (!pMRU && hkeySubKey)
  300.         RegCloseKey(hkeySubKey);
  301. #ifdef DEBUG
  302.     //DebugMsg(DM_TRACE, TEXT("CreateMRU: %d msec"), LOWORD(GetTickCount()-dwStart));
  303. #endif
  304.     return((HANDLE)pMRU);
  305. }
  306. HANDLE CreateMRUListEx(LPMRUINFO lpmi)
  307. {
  308.     return CreateMRUListLazyEx(lpmi, NULL, 0, NULL);
  309. }
  310. LPDWORD OrderStrChr(LPDWORD pdwOrder, DWORD dwVal)
  311. {
  312.     while (*pdwOrder != (DWORD)-1)
  313.     {
  314.         if (*pdwOrder == dwVal)
  315.             return pdwOrder;
  316.         pdwOrder++;
  317.     }
  318.     return NULL;
  319. }
  320. int OrderLength(LPDWORD pdwOrder)
  321. {
  322.     int len = 0;
  323.     do {
  324.         len++;
  325.     } while (*pdwOrder++ != (DWORD)-1);
  326.     return len;
  327. }
  328. void SaveMRUOrder(PMRUDATA pMRU)
  329. {
  330.     if (EVAL(pMRU->cOrder)) // See BryanSt if this assert.
  331.     {
  332.         RegSetValueEx(pMRU->hKey, 
  333.                       szMRUEX,
  334.                       0L,
  335.                       REG_BINARY, (CONST BYTE *)pMRU->cOrder, sizeof(DWORD) * OrderLength(pMRU->cOrder));
  336.     }
  337.     pMRU->fFlags &= ~MRU_ORDERDIRTY;
  338. }
  339. #define pMRU ((PMRUDATA)hMRU)
  340. //----------------------------------------------------------------------------
  341. void FreeMRUListEx(HANDLE hMRU)
  342. {
  343.     int i;
  344.     LPBYTE *pTemp;
  345.     pTemp = (pMRU->fFlags & MRU_BINARY) ?
  346.         &NTHDATA(pMRU, 0) : (LPBYTE FAR *)&NTHSTRING(pMRU, 0);
  347.     if (pMRU->fFlags & MRU_ORDERDIRTY)
  348.     {
  349.         SaveMRUOrder(pMRU);
  350.     }                      
  351.     for (i=pMRU->uMax-1; i>=0; --i, ++pTemp)
  352.     {
  353.         if (*pTemp) {
  354.             if (pMRU->fFlags & MRU_BINARY) {
  355.                 Free(*pTemp);
  356.                 *pTemp = NULL;
  357.             } else {
  358.                 Str_SetPtr((LPTSTR FAR *)pTemp, NULL);
  359.             }
  360.         }
  361.     }
  362.     RegCloseKey(pMRU->hKey);
  363.     Free(pMRU->cOrder);
  364.     Free((HLOCAL)pMRU);
  365. }
  366. //----------------------------------------------------------------------------
  367. // Add data to an MRU list.
  368. int AddMRUDataEx(HANDLE hMRU, const void FAR *lpData, UINT cbData)
  369. {
  370.     DWORD cFirst;
  371.     int iSlot = -1;
  372.     LPDWORD lpTemp;
  373.     LPBYTE FAR *ppData;
  374.     int i;
  375.     UINT uMax;
  376.     MRUCMPDATAPROC lpfnCompare;
  377.     BOOL fShouldWrite = !(pMRU->fFlags & MRU_CACHEWRITE);
  378. #ifdef DEBUG
  379.     DWORD dwStart = GetTickCount();
  380. #endif
  381.     if (hMRU == NULL)
  382.         return(-1);     // Error
  383.     uMax = pMRU->uMax;
  384.     lpfnCompare = (MRUCMPDATAPROC)pMRU->lpfnCompare;
  385.     // Check if the data already exists in the list.
  386.     for (i=0, ppData=&NTHDATA(pMRU, 0); (UINT)i<uMax; ++i, ++ppData)
  387.     {
  388.         if (*ppData && MRUIsSameData(pMRU, *ppData, lpData, cbData))
  389.         {
  390.             // found it, so don't do the write out
  391.             cFirst = i;
  392.             iSlot = i;
  393.             goto FoundEntry;
  394.         }
  395.     }
  396.     //
  397.     // When created "lazy", we are not supposed to add a new item.
  398.     //
  399.     if (pMRU->fFlags & MRU_LAZY) {
  400.         ASSERT(0);
  401.         return -1;
  402.     }
  403.     // Attempt to find an unused entry.  Count up the used entries at the
  404.     // same time.
  405.     for (i=0, ppData=&NTHDATA(pMRU, 0); ; ++i, ++ppData)
  406.     {
  407.         // If we got to the end of the list.
  408.         if ((UINT)i >= uMax)
  409.         {
  410.             // use the entry at the end of the cOrder list
  411.             cFirst = pMRU->cOrder[uMax-1];
  412.             ppData = &NTHDATA(pMRU, cFirst);
  413.             break;
  414.         }
  415.         // If the entry is not used.
  416.         if (!*ppData)
  417.         {
  418.             cFirst = i;
  419.             break;
  420.         }
  421.     }
  422.     *ppData = (LPBYTE)ReAlloc(*ppData, cbData+sizeof(DWORD));
  423.     if (*ppData)
  424.     {
  425.         TCHAR szTemp[MAX_MRU_INDEXSTR];
  426.         *((LPDWORD)(*ppData)) = cbData;
  427.         hmemcpy(DATAPDATA(*ppData), lpData, cbData);
  428.         iSlot = (int)(cFirst);
  429.         GetIndexStrFromIndex(cFirst, szTemp, ARRAYSIZE(szTemp));
  430.         RegSetValueEx(pMRU->hKey, szTemp, 0L, REG_BINARY, (LPBYTE)lpData, cbData);
  431.         fShouldWrite = TRUE;
  432.     }
  433.     else
  434.     {
  435.         // Since iSlot == -1, we will remove the reference to cFirst
  436.         // below.
  437.     }
  438. FoundEntry:
  439.     // Remove any previous reference to cFirst.
  440.     lpTemp = OrderStrChr(pMRU->cOrder, cFirst);
  441.     if (lpTemp)
  442.     {
  443.         MoveMemory(lpTemp, lpTemp+1, (pMRU->uMax - (lpTemp-pMRU->cOrder))*sizeof(DWORD));
  444.     }
  445.     if (iSlot != -1)
  446.     {
  447.         // shift everything over and put cFirst at the front
  448.         hmemcpy(pMRU->cOrder+1, pMRU->cOrder, pMRU->uMax*sizeof(DWORD));
  449.         pMRU->cOrder[0] = cFirst;
  450.     }
  451.     if (fShouldWrite) {
  452.         SaveMRUOrder(pMRU);
  453.     } else
  454.         pMRU->fFlags |= MRU_ORDERDIRTY;
  455. #ifdef DEBUG
  456.     // DebugMsg(DM_TRACE, TEXT("AddMRU: %d msec"), LOWORD(GetTickCount()-dwStart));
  457. #endif
  458.     return(iSlot);
  459. }