Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
11 KiB

  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. STDAPI
  29. SHLoadRegUIStringW(HKEY hkey,
  30. LPCWSTR pszValue,
  31. LPWSTR pszOutBuf,
  32. UINT cchOutBuf)
  33. {
  34. HRESULT hr;
  35. RIP(hkey != NULL);
  36. RIP(hkey != INVALID_HANDLE_VALUE);
  37. RIP(NULL == pszValue || IS_VALID_STRING_PTRW(pszValue, -1));
  38. RIP(IS_VALID_WRITE_BUFFER(pszOutBuf, WCHAR, cchOutBuf));
  39. DEBUGWhackPathBufferW(pszOutBuf, cchOutBuf);
  40. // Lots of people (regfldr.cpp, for example)
  41. // assume they'll get back an empty string on failure,
  42. // so let's give the public what it wants
  43. if (cchOutBuf)
  44. pszOutBuf[0] = 0;
  45. hr = E_INVALIDARG;
  46. if (hkey != INVALID_HANDLE_VALUE &&
  47. hkey != NULL &&
  48. pszOutBuf != NULL)
  49. {
  50. DWORD cb;
  51. DWORD dwRet;
  52. WCHAR * pszValueDataBuf;
  53. hr = E_FAIL;
  54. // first try to get the indirected text which will
  55. // point to a string id in a dll somewhere... this
  56. // allows plugUI enabled registry UI strings
  57. pszValueDataBuf = pszOutBuf;
  58. cb = CbFromCchW(cchOutBuf);
  59. dwRet = SHQueryValueExW(hkey, pszValue, NULL, NULL, (LPBYTE)pszValueDataBuf, &cb);
  60. if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA)
  61. {
  62. BOOL fAlloc;
  63. fAlloc = (dwRet == ERROR_MORE_DATA);
  64. // if we didn't have space, this is where we correct the problem.
  65. // we create a buffer big enough, load the data, and leave
  66. // ourselves with pszValueDataBuf pointing at a valid buffer
  67. // containing valid data, exactly what we hoped for in the
  68. // SHQueryValueExW above
  69. if (fAlloc)
  70. {
  71. pszValueDataBuf = new WCHAR[(cb+1)/2];
  72. if (pszValueDataBuf != NULL)
  73. {
  74. // try to load again... overwriting dwRet on purpose
  75. // because we only need to know whether we successfully filled
  76. // the buffer at some point (whether then or now)
  77. dwRet = SHQueryValueExW(hkey, pszValue, NULL, NULL, (LPBYTE)pszValueDataBuf, &cb);
  78. }
  79. else
  80. {
  81. hr = E_OUTOFMEMORY;
  82. }
  83. }
  84. // proceed if we succesfully loaded something via one of the
  85. // two SHQueryValueExW calls.
  86. // we should have the data we want in a buffer pointed
  87. // to by pszValueDataBuf.
  88. if (dwRet == ERROR_SUCCESS)
  89. {
  90. hr = SHLoadIndirectString(pszValueDataBuf, pszOutBuf, cchOutBuf, NULL);
  91. }
  92. if (fAlloc && pszValueDataBuf != NULL)
  93. {
  94. delete [] pszValueDataBuf;
  95. }
  96. }
  97. }
  98. return hr;
  99. }
  100. STDAPI
  101. SHLoadRegUIStringA(HKEY hkey,
  102. LPCSTR pszValue,
  103. LPSTR pszOutBuf,
  104. UINT cchOutBuf)
  105. {
  106. HRESULT hr;
  107. RIP(hkey != NULL);
  108. RIP(hkey != INVALID_HANDLE_VALUE);
  109. RIP(IS_VALID_STRING_PTRA(pszValue, -1));
  110. RIP(IS_VALID_WRITE_BUFFER(pszOutBuf, char, cchOutBuf));
  111. CStrInW strV(pszValue);
  112. CStrOutW strOut(pszOutBuf, cchOutBuf);
  113. hr = SHLoadRegUIStringW(hkey, strV, strOut, strOut.BufSize());
  114. return hr;
  115. }
  116. HRESULT _LoadDllString(LPCWSTR pszSource, LPWSTR pszOutBuf, UINT cchOutBuf)
  117. {
  118. HRESULT hr = E_FAIL;
  119. WCHAR * pszParseBuf = StrDupW(pszSource);
  120. if (pszParseBuf)
  121. {
  122. // see if this is a special string reference.
  123. // such strings take the form [path\]dllname.dll,-123
  124. // where 123 is the id of the string resource
  125. // note that reference by index is not permitted
  126. int nStrId = PathParseIconLocationW(pszParseBuf);
  127. nStrId *= -1;
  128. if (nStrId > 0)
  129. {
  130. LPWSTR pszDllName;
  131. HINSTANCE hinst;
  132. BOOL fUsedMLLoadLibrary = FALSE;
  133. pszDllName = PathFindFileNameW(pszParseBuf);
  134. ASSERT(pszDllName >= pszParseBuf);
  135. // try loading the dll with MLLoadLibrary, but
  136. // only if an explicit path was not provided.
  137. // we assume an explicit path means that
  138. // the caller knows precisely which dll is needed
  139. // use MLLoadLibrary first, otherwise we'll miss
  140. // out chance to have plugUI behavior
  141. hinst = NULL;
  142. if (pszDllName == pszParseBuf)
  143. {
  144. if (StrStrI(pszDllName, L"LC.DLL"))
  145. {
  146. // note: using HINST_THISDLL (below) is sort of a hack because that's
  147. // techinically supposed to be the *parent* dll's hinstance...
  148. // however we get called from lots of places and therefore
  149. // don't know the parent dll, and the hinst for browseui.dll
  150. // is good enough since all the hinst is really used for is to
  151. // find the path to check if the install language is the
  152. // currently selected UI language. this will usually be
  153. // something like "\winnt\system32"
  154. hinst = MLLoadLibraryW(pszDllName, HINST_THISDLL, ML_CROSSCODEPAGE);
  155. fUsedMLLoadLibrary = (hinst != NULL);
  156. }
  157. else
  158. hinst = LoadLibraryExW(pszDllName, NULL, LOAD_LIBRARY_AS_DATAFILE);
  159. }
  160. if (!hinst)
  161. {
  162. // our last chance to load something is if a full
  163. // path was provided... if there's a full path it
  164. // will start at the beginning of the pszParseBuf buffer
  165. if (pszDllName > pszParseBuf)
  166. {
  167. // don't bother if the file isn't there
  168. // failling in LoadLibrary is slow
  169. if (PathFileExistsW(pszParseBuf))
  170. {
  171. hinst = LoadLibraryExW(pszParseBuf, NULL, LOAD_LIBRARY_AS_DATAFILE);
  172. }
  173. }
  174. }
  175. if (hinst)
  176. {
  177. // dll found, so load the string
  178. if (LoadStringW(hinst, nStrId, pszOutBuf, cchOutBuf))
  179. {
  180. hr = S_OK;
  181. }
  182. else
  183. {
  184. TraceMsg(TF_WARNING,
  185. "SHLoadRegUIString(): Failure loading string %d from module %ws for valid load request %ws.",
  186. nStrId,
  187. pszParseBuf,
  188. pszSource);
  189. }
  190. if (fUsedMLLoadLibrary)
  191. {
  192. MLFreeLibrary(hinst);
  193. }
  194. else
  195. {
  196. FreeLibrary(hinst);
  197. }
  198. }
  199. }
  200. LocalFree(pszParseBuf);
  201. }
  202. else
  203. {
  204. hr = E_OUTOFMEMORY;
  205. }
  206. return hr;
  207. }
  208. inline BOOL _CanCacheMUI()
  209. {
  210. return TRUE;
  211. }
  212. // Note: pszSource and pszOutBuf may be the same buffer
  213. LWSTDAPI SHLoadIndirectString(LPCWSTR pszSource, LPWSTR pszOutBuf, UINT cchOutBuf, void **ppvReserved)
  214. {
  215. HRESULT hr = E_FAIL;
  216. RIP(IS_VALID_WRITE_BUFFER(pszOutBuf, WCHAR, cchOutBuf));
  217. RIP(!ppvReserved);
  218. if (pszSource[0] == L'@') // "@dllname,-id" or "@dllname,-id?lid,string"
  219. {
  220. LPWSTR pszResource = StrDupW(pszSource);
  221. if (pszResource)
  222. {
  223. LANGID lidUI =0;
  224. // the LidString is there to support our old caching model.
  225. // the new caching model doesnt require any work for the caller
  226. LPWSTR pszLidString = StrChrW(pszResource+1, L'?');
  227. DWORD cchResource = lstrlen(pszResource);
  228. // used to use '@' as the second delimiter as well.
  229. // but it has collisions with filesystem paths.
  230. if (!pszLidString)
  231. pszLidString = StrChrW(pszResource+1, L'@');
  232. if (pszLidString)
  233. {
  234. cchResource = (DWORD)(pszLidString - pszResource);
  235. // NULL terminate the dll,id just in case we need to actually load
  236. pszResource[cchResource] = 0;
  237. }
  238. DWORD cb = CbFromCchW(cchOutBuf);
  239. hr = SKGetValue(SHELLKEY_HKCULM_MUICACHE, NULL, pszResource, NULL, pszOutBuf, &cb);
  240. if (FAILED(hr))
  241. {
  242. WCHAR wszDllId[MAX_PATH + 1 + 6]; // path + comma + -65536
  243. SHExpandEnvironmentStringsW(pszResource+1, wszDllId, ARRAYSIZE(wszDllId));
  244. hr = _LoadDllString(wszDllId, pszOutBuf, cchOutBuf);
  245. // Might as well write the new string out so we don't have to load the DLL next time through
  246. // but we don't write cross codepage string on Win9x
  247. if (SUCCEEDED(hr) && _CanCacheMUI())
  248. {
  249. SKSetValue(SHELLKEY_HKCULM_MUICACHE, NULL, pszResource, REG_SZ, pszOutBuf, CbFromCchW(lstrlenW(pszOutBuf)+1));
  250. }
  251. }
  252. LocalFree(pszResource);
  253. }
  254. else
  255. hr = E_OUTOFMEMORY;
  256. if (FAILED(hr))
  257. {
  258. if (cchOutBuf)
  259. pszOutBuf[0] = L'\0'; // can't hand out an "@shell32.dll,-525" string
  260. }
  261. }
  262. else
  263. {
  264. if (pszOutBuf != pszSource)
  265. StrCpyN(pszOutBuf, pszSource, cchOutBuf);
  266. hr = S_OK;
  267. }
  268. return hr;
  269. }