regw.cpp
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 12k
Category:

Windows Develop

Development Platform:

Visual C++

  1. #include "priv.h"
  2. #include "unicwrap.h"
  3. /*****************************************************************************
  4.     FUNCTION: SHLoadRegUIString
  5.     DESCRIPTION:
  6.         loads the data from the value given the hkey and
  7.         pszValue. if the data is of the form:
  8.         @[path]<dllname>,-<strId>
  9.         the string with id <strId> from <dllname> will be
  10.         loaded. if not explicit path is provided then the
  11.         dll will be chosen according to pluggable UI
  12.         specifications, if possible.
  13.         if the value's data doesn't yield a successful
  14.         string load, then the data itself is returned
  15.     NOTE:
  16.         These strings are always loaded with cross codepage support.
  17.     WARNING:
  18.         This function can end up calling LoadLibrary and FreeLibrary.
  19.         Therefore, you must not call SHLoadRegUIString during process
  20.         attach or process detach.
  21.     PARAMETERS:
  22.         hkey        - hkey of where to look for pszValue
  23.         pszValue    - value with text string or indirector (see above) to use
  24.         pszOutBuf   - buffer in which to return the data or indirected string
  25.         cchOutBuf   - size of pszOutBuf
  26. *****************************************************************************/
  27. LANGID GetNormalizedLangId(DWORD dwFlag);
  28. HRESULT _LoadIndirectString(LPWSTR pszSource, LPWSTR pszOutBuf, UINT cchOutBuf, LPWSTR * ppszUpdate);
  29. STDAPI
  30. SHLoadRegUIStringW(HKEY     hkey,
  31.                    LPCWSTR  pszValue,
  32.                    LPWSTR   pszOutBuf,
  33.                    UINT     cchOutBuf)
  34. {
  35.     HRESULT hr;
  36.     RIP(hkey != NULL);
  37.     RIP(hkey != INVALID_HANDLE_VALUE);
  38.     RIP(IS_VALID_STRING_PTRW(pszValue, -1));
  39.     RIP(IS_VALID_WRITE_BUFFER(pszOutBuf, WCHAR, cchOutBuf));
  40.     DEBUGWhackPathBufferW(pszOutBuf, cchOutBuf);
  41.     // Lots of people (regfldr.cpp, for example)
  42.     // assume they'll get back an empty string on failure,
  43.     // so let's give the public what it wants
  44.     if (cchOutBuf)
  45.         pszOutBuf[0] = 0;
  46.     hr = E_INVALIDARG;
  47.     if (hkey != INVALID_HANDLE_VALUE &&
  48.         hkey != NULL &&
  49.         pszValue != NULL &&
  50.         pszOutBuf != NULL)
  51.     {
  52.         DWORD   cb;
  53.         DWORD   dwRet;
  54.         WCHAR * pszValueDataBuf;
  55.         hr = E_FAIL;
  56.         // first try to get the indirected text which will
  57.         // point to a string id in a dll somewhere... this
  58.         // allows plugUI enabled registry UI strings
  59.         pszValueDataBuf = pszOutBuf;
  60.         cb = cchOutBuf * sizeof(pszOutBuf[0]);
  61.         dwRet = SHQueryValueExW(hkey, pszValue, NULL, NULL, (LPBYTE)pszValueDataBuf, &cb);
  62.         if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA)
  63.         {
  64.             BOOL fAlloc;
  65.             fAlloc = (dwRet == ERROR_MORE_DATA);
  66.             // if we didn't have space, this is where we correct the problem.
  67.             // we create a buffer big enough, load the data, and leave
  68.             // ourselves with pszValueDataBuf pointing at a valid buffer
  69.             // containing valid data, exactly what we hoped for in the
  70.             // SHQueryValueExW above
  71.             if (fAlloc)
  72.             {
  73.                 pszValueDataBuf = new WCHAR[(cb+1)/2];
  74.                 
  75.                 if (pszValueDataBuf != NULL)
  76.                 {
  77.                     // try to load again... overwriting dwRet on purpose
  78.                     // because we only need to know whether we successfully filled
  79.                     // the buffer at some point (whether then or now)
  80.                     
  81.                     dwRet = SHQueryValueExW(hkey, pszValue, NULL, NULL, (LPBYTE)pszValueDataBuf, &cb);
  82.                 }
  83.                 else
  84.                 {
  85.                     hr = E_OUTOFMEMORY;
  86.                 }                
  87.             }
  88.             // proceed if we succesfully loaded something via one of the
  89.             // two SHQueryValueExW calls.
  90.             // we should have the data we want in a buffer pointed
  91.             // to by pszValueDataBuf.
  92.             
  93.             if (dwRet == ERROR_SUCCESS)
  94.             {
  95.                 LPWSTR pszUpdate;
  96.                 hr = _LoadIndirectString(pszValueDataBuf, pszOutBuf, cchOutBuf, &pszUpdate);
  97.                 if (SUCCEEDED(hr))
  98.                 {
  99.                     if (pszUpdate)
  100.                     {
  101.                         SHSetValueW(hkey, NULL, pszValue, REG_SZ, pszUpdate, (lstrlenW(pszUpdate)+1)*2);
  102.                         delete [] pszUpdate;
  103.                     }
  104.                 }
  105.                 else
  106.                 {
  107.                     // the indirect load failed, so we use
  108.                     // the text of the reg string directly
  109.                     if (pszValueDataBuf != pszOutBuf)
  110.                     {
  111.                         StrCpyNW(pszOutBuf, pszValueDataBuf, cchOutBuf);
  112.                     }
  113.                     hr = S_OK;
  114.                 }
  115.             }
  116.             if (fAlloc && pszValueDataBuf != NULL)
  117.             {
  118.                 delete [] pszValueDataBuf;
  119.             }
  120.         }
  121.     }
  122.     return hr;
  123. }
  124. STDAPI
  125. SHLoadRegUIStringA(HKEY     hkey,
  126.                    LPCSTR   pszValue,
  127.                    LPSTR    pszOutBuf,
  128.                    UINT     cchOutBuf)
  129. {
  130.     HRESULT     hr;
  131.     RIP(hkey != NULL);
  132.     RIP(hkey != INVALID_HANDLE_VALUE);
  133.     RIP(IS_VALID_STRING_PTRA(pszValue, -1));
  134.     RIP(IS_VALID_WRITE_BUFFER(pszOutBuf, char, cchOutBuf));
  135.     CStrInW     strV(pszValue);
  136.     CStrOutW    strOut(pszOutBuf, cchOutBuf);
  137.     hr = SHLoadRegUIStringW(hkey, strV, strOut, strOut.BufSize());
  138.     return hr;
  139. }
  140. HRESULT _LoadDllString(LPCWSTR pszSource, LPWSTR pszOutBuf, UINT cchOutBuf)
  141. {
  142.     HRESULT hr = E_FAIL;
  143.     WCHAR * szParseBuf;
  144.     int     nStrId;
  145.     UINT cchSource = lstrlenW(pszSource)+1;
  146.     szParseBuf = new WCHAR[cchSource];
  147.     if (szParseBuf != NULL)
  148.     {
  149.         StrCpyW(szParseBuf, pszSource);
  150.         // see if this is a special string reference.
  151.         // such strings take the form [path]dllname.dll,-123
  152.         // where 123 is the id of the string resource
  153.         // note that reference by index is not permitted
  154.         nStrId = PathParseIconLocationW(szParseBuf);
  155.         nStrId *= -1;
  156.         if (nStrId > 0)
  157.         {
  158.             LPWSTR      pszDllName;
  159.             HINSTANCE   hinst;
  160.             BOOL        fUsedMLLoadLibrary;
  161.             pszDllName = PathFindFileNameW(szParseBuf);
  162.             ASSERT(pszDllName >= szParseBuf);
  163.             // try loading the dll with MLLoadLibrary, but
  164.             // only if an explicit path was not provided.
  165.             // we assume an explicit path means that
  166.             // the caller knows precisely which dll is needed
  167.             // use MLLoadLibrary first, otherwise we'll miss
  168.             // out chance to have plugUI behavior
  169.             hinst = NULL;
  170.             if (pszDllName == szParseBuf)
  171.             {
  172.                 // note: using HINST_THISDLL (below) is sort of a hack because that's
  173.                 // techinically supposed to be the *parent* dll's hinstance...
  174.                 // however we get called from lots of places and therefore
  175.                 // don't know the parent dll, and the hinst for browseui.dll
  176.                 // is good enough since all the hinst is really used for is to
  177.                 // find the path to check if the install language is the
  178.                 // currently selected UI language. this will usually be
  179.                 // something like "winntsystem32"
  180.                 hinst = MLLoadLibraryW(pszDllName, HINST_THISDLL, ML_CROSSCODEPAGE);
  181.             }
  182.             if (hinst != NULL)
  183.             {
  184.                 fUsedMLLoadLibrary = TRUE;
  185.             }
  186.             else
  187.             {
  188.                 fUsedMLLoadLibrary = FALSE;
  189.                 // our last chance to load something is if a full
  190.                 // path was provided... if there's a full path it
  191.                 // will start at the beginning of the szParseBuf buffer
  192.                 if (pszDllName > szParseBuf)
  193.                 {
  194.                     BOOL    fFileExists;
  195.                     // don't bother if the file isn't there
  196.                     // failling in LoadLibrary is slow
  197.                     fFileExists = PathFileExistsW(szParseBuf);
  198.                     if (fFileExists)
  199.                     {
  200.                         hinst = LoadLibraryWrapW(szParseBuf);
  201.                     }
  202.                 }
  203.             }
  204.             if (hinst != NULL)
  205.             {
  206.                 int nLSRet;
  207.                 // dll found, so load the string
  208.                 nLSRet = LoadStringWrapW(hinst, nStrId, pszOutBuf, cchOutBuf);
  209.                 if (nLSRet != 0)
  210.                 {
  211.                     hr = S_OK;
  212.                 }
  213.                 else
  214.                 {
  215.                     TraceMsg(TF_WARNING,
  216.                              "SHLoadRegUIString(): Failure loading string %d from module %ws for valid load request %ws.",
  217.                              nStrId,
  218.                              szParseBuf,
  219.                              pszSource);
  220.                 }
  221.                 // BUGBUG
  222.                 // This is bad. Since these dlls aren't
  223.                 // loaded as data files, loading them and
  224.                 // not freeing them (precisely what you
  225.                 // are about to witness) is really scrungy.
  226.                 // We *NEED* to load these resource dlls
  227.                 // as data files
  228.                 
  229.                 if (fUsedMLLoadLibrary)
  230.                 {
  231.                     MLClearMLHInstance(hinst);
  232.                 }
  233.             }
  234.         }
  235.         delete [] szParseBuf;
  236.     }
  237.     else
  238.     {
  239.         hr = E_OUTOFMEMORY;
  240.     }
  241.     return hr;
  242. }
  243. // Note: pszSource and pszOutBuf may be the same buffer
  244. // *ppszUpdate is the [OUT] LocalAlloc()d return buffer if we need to update the registry value
  245. HRESULT _LoadIndirectString(LPWSTR pszSource, LPWSTR pszOutBuf, UINT cchOutBuf, LPWSTR *ppszUpdate)
  246. {
  247.     HRESULT hr;
  248.     RIP(IS_VALID_WRITE_BUFFER(pszOutBuf, WCHAR, cchOutBuf));
  249.     hr = E_FAIL;
  250.     *ppszUpdate = NULL;
  251.     if (pszSource[0] == L'@') // "@dllname,-id" or "@dllname,-id@lid,string"
  252.     {
  253.         LPWSTR pszLidString = StrChrW(pszSource+1, L'@');
  254.         LANGID lidUI = MLGetUILanguage();
  255.         WCHAR wszDllId[MAX_PATH + 1 + 6]; // path + comma + -65536
  256.         StrCpyNW(wszDllId, pszSource+1, ARRAYSIZE(wszDllId));
  257.         if (pszLidString)
  258.         {
  259.             // NULL terminate the dll,id just in case we need to actually load
  260.             wszDllId[pszLidString-(pszSource+1)] = L'';
  261.             // If the langid matches the ML language, then the string is valid
  262.             //
  263.             pszLidString++;
  264.             LANGID lid = (UINT)StrToInt(pszLidString);
  265.             if (lid == lidUI)
  266.             {
  267.                 pszLidString = StrChrW(pszLidString, L',');
  268.                 if (pszLidString)
  269.                 {
  270.                     StrCpyNW(pszOutBuf, pszLidString+1, cchOutBuf);
  271.                     return S_OK;
  272.                 }
  273.                 else
  274.                 {
  275.                     TraceMsg(TF_WARNING, "Invalid string in registry, we're needlessly hosing perf");
  276.                 }
  277.             }
  278.             else
  279.             {
  280.                 TraceMsg(TF_GENERAL, "SHLoadRegUIString mis-matched lidUI, loading new string");
  281.             }
  282.         }
  283.         hr = _LoadDllString(wszDllId, pszOutBuf, cchOutBuf);
  284.         // Might as well write the new string out so we don't have to load the DLL next time through
  285.         // but we don't write cross codepage string on Win9x
  286.         if (SUCCEEDED(hr) && (GetNormalizedLangId(ML_CROSSCODEPAGE_NT) == lidUI))
  287.         {
  288.             int cch = 1 + lstrlen(wszDllId) + 7 + lstrlen(pszOutBuf) + 1; // 7 for @#####,
  289.             *ppszUpdate = new WCHAR[cch];
  290.             if (*ppszUpdate)
  291.             {
  292.                 wnsprintfW(*ppszUpdate, cch, L"@%s@%d,%s", wszDllId, lidUI, pszOutBuf);
  293.             }
  294.         }
  295.     }
  296.     return hr;
  297. }