Source code of Windows XP (NT5)
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.

322 lines
8.6 KiB

  1. //
  2. // SafeReg.cpp
  3. //
  4. // Functions to ensure strings read from the registry are null-terminated.
  5. //
  6. // History:
  7. //
  8. // 2002-03-20 KenSh Created
  9. //
  10. // Copyright (c) 2002 Microsoft Corporation
  11. //
  12. #include "stdafx.h"
  13. #include "SafeReg.h"
  14. // SafeRegQueryValueCchHelper [private]
  15. //
  16. // Implementation of both "safe" kinds of string registry reads.
  17. //
  18. static HRESULT SafeRegQueryValueCchHelper
  19. (
  20. IN DWORD dwExpectedType,
  21. IN HKEY hkey,
  22. IN LPCTSTR pszValueName,
  23. OUT LPTSTR pszBuf,
  24. IN int cchBuf,
  25. OUT OPTIONAL int* pcchValueSize,
  26. OUT OPTIONAL BOOL* pfExpandSz
  27. )
  28. {
  29. HRESULT hr = S_OK;
  30. int cchValueSize = 0;
  31. BOOL fExpandSz = FALSE;
  32. // BLOCK
  33. {
  34. if ((!pszBuf && cchBuf != 0) || cchBuf < 0) // note: pszValueName can be null
  35. {
  36. hr = E_INVALIDARG;
  37. goto done;
  38. }
  39. DWORD dwType;
  40. DWORD cbData = cchBuf * sizeof(TCHAR);
  41. DWORD dwResult = RegQueryValueEx(
  42. hkey, pszValueName, NULL, &dwType, (LPBYTE)pszBuf, &cbData);
  43. if (dwResult != ERROR_SUCCESS)
  44. {
  45. hr = HRESULT_FROM_WIN32(dwResult);
  46. }
  47. else if (!pszBuf && cbData > 0)
  48. {
  49. hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
  50. }
  51. if (SUCCEEDED(hr))
  52. {
  53. fExpandSz = (dwType == REG_EXPAND_SZ);
  54. if ((dwType != dwExpectedType) &&
  55. !(dwExpectedType == REG_SZ && dwType == REG_EXPAND_SZ))
  56. {
  57. hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
  58. }
  59. }
  60. if (hr == HRESULT_FROM_WIN32(ERROR_MORE_DATA))
  61. {
  62. // Add 1-2 extra chars in case the registry data is not big enough.
  63. cchValueSize = cbData / sizeof(TCHAR);
  64. cchValueSize += (dwExpectedType == REG_MULTI_SZ) ? 2 : 1;
  65. }
  66. else if (SUCCEEDED(hr))
  67. {
  68. cchValueSize = cbData / sizeof(TCHAR);
  69. // check for lack of null-termination
  70. if (cchValueSize == 0 || pszBuf[cchValueSize-1] != _T('\0'))
  71. cchValueSize++;
  72. // check for lack of double null-termination (multi-sz only)
  73. if (dwExpectedType == REG_MULTI_SZ && (cchValueSize < 2 || pszBuf[cchValueSize-2] != _T('\0')))
  74. cchValueSize++;
  75. // check for overflow
  76. if (cchValueSize > cchBuf)
  77. {
  78. hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
  79. }
  80. else
  81. {
  82. cchValueSize--; // when successful, count doesn't include trailing null
  83. pszBuf[cchValueSize] = _T('\0');
  84. if (dwExpectedType == REG_MULTI_SZ)
  85. pszBuf[cchValueSize-1] = _T('\0');
  86. }
  87. }
  88. } // end BLOCK
  89. done:
  90. if (FAILED(hr) && pszBuf && cchBuf > 0)
  91. pszBuf[0] = _T('\0');
  92. if (pcchValueSize)
  93. *pcchValueSize = cchValueSize;
  94. if (pfExpandSz)
  95. *pfExpandSz = fExpandSz;
  96. return hr;
  97. }
  98. // SafeRegQueryValueCchAllocHelper [private]
  99. //
  100. // Implementation of the 2 "alloc" versions of the safe reg string functions.
  101. //
  102. HRESULT WINAPI SafeRegQueryValueCchAllocHelper
  103. (
  104. IN DWORD dwExpectedType,
  105. IN HKEY hkey,
  106. IN LPCTSTR pszValueName,
  107. OUT LPTSTR* ppszBuf,
  108. OUT OPTIONAL int* pcchValueSize,
  109. OUT OPTIONAL BOOL* pfExpandSz
  110. )
  111. {
  112. LPTSTR pszResult = NULL;
  113. int cchValueSize = 0;
  114. BOOL fExpandSz = FALSE;
  115. HRESULT hr = E_INVALIDARG;
  116. // BLOCK
  117. {
  118. if (!ppszBuf)
  119. {
  120. goto done; // hr is already E_INVALIDARG
  121. }
  122. DWORD cbNeeded = 0;
  123. DWORD dwErr = RegQueryValueEx(hkey, pszValueName, NULL, NULL, NULL, &cbNeeded);
  124. if (dwErr != 0 && dwErr != ERROR_MORE_DATA)
  125. {
  126. hr = HRESULT_FROM_WIN32(dwErr);
  127. goto done;
  128. }
  129. int cchBuf = (cbNeeded / sizeof(TCHAR)) + 2;
  130. pszResult = (LPTSTR)SafeRegMalloc(sizeof(TCHAR) * cchBuf);
  131. if (!pszResult)
  132. {
  133. hr = E_OUTOFMEMORY;
  134. goto done;
  135. }
  136. hr = SafeRegQueryValueCchHelper(dwExpectedType, hkey, pszValueName, pszResult, cchBuf, &cchValueSize, &fExpandSz);
  137. }
  138. done:
  139. if (FAILED(hr))
  140. {
  141. SafeRegFree(pszResult);
  142. pszResult = NULL;
  143. }
  144. if (ppszBuf)
  145. *ppszBuf = pszResult;
  146. if (pcchValueSize)
  147. *pcchValueSize = cchValueSize;
  148. if (pfExpandSz)
  149. *pfExpandSz = fExpandSz;
  150. return hr;
  151. }
  152. // SafeRegQueryStringValueCch [public]
  153. //
  154. // Reads a string out of the registry and ensures the result is null-
  155. // terminated. Optionally returns the number of characters retrieved,
  156. // excluding the trailing null.
  157. //
  158. // If the buffer is not big enough, the function returns REG_E_MORE_DATA
  159. // and stores the required size, in characters, in the pcchValueSize
  160. // parameter (including room for the trailing null). Note that the size
  161. // returned may be bigger than the actual size of the data in the registry.
  162. //
  163. HRESULT WINAPI SafeRegQueryStringValueCch
  164. (
  165. IN HKEY hkey,
  166. IN LPCTSTR pszValueName,
  167. OUT LPTSTR pszBuf,
  168. IN int cchBuf,
  169. OUT OPTIONAL int* pcchValueSize, // S_OK: chars written, excluding trailing null
  170. // REG_E_MORE_DATA: required size, including null
  171. OUT OPTIONAL BOOL* pfExpandSz // TRUE if reg string is actually REG_EXPAND_SZ
  172. )
  173. {
  174. return SafeRegQueryValueCchHelper(REG_SZ, hkey, pszValueName, pszBuf, cchBuf, pcchValueSize, pfExpandSz);
  175. }
  176. HRESULT WINAPI SafeRegQueryStringValueCb
  177. (
  178. IN HKEY hkey,
  179. IN LPCTSTR pszValueName,
  180. OUT LPTSTR pszBuf,
  181. IN int cbBuf,
  182. OUT OPTIONAL int* pcbValueSize, // S_OK: bytes written, excluding trailing null
  183. // REG_E_MORE_DATA: required size, including null
  184. OUT OPTIONAL BOOL* pfExpandSz // TRUE if reg string is actually REG_EXPAND_SZ
  185. )
  186. {
  187. int cchBuf = cbBuf / sizeof(TCHAR); // note: odd #'s for cbBuf are rounded down
  188. HRESULT hr = SafeRegQueryValueCchHelper(REG_SZ, hkey, pszValueName, pszBuf, cchBuf, pcbValueSize, pfExpandSz);
  189. if (pcbValueSize)
  190. *pcbValueSize *= sizeof(TCHAR);
  191. return hr;
  192. }
  193. // SafeRegQueryMultiStringValueCch [public]
  194. //
  195. // Reads a multi-string out of the registry and ensures the result is double
  196. // null-terminated. Optionally returns the number of characters retrieved,
  197. // excluding the second trailing NULL.
  198. //
  199. // If the buffer is not big enough, the function returns REG_E_MORE_DATA
  200. // and stores the required size, in characters, in the pcchValueSize
  201. // parameter (including room for the trailing nulls). Note that the size
  202. // returned may be bigger than the actual size of the data in the registry.
  203. //
  204. HRESULT WINAPI SafeRegQueryMultiStringValueCch
  205. (
  206. IN HKEY hkey,
  207. IN LPCTSTR pszValueName,
  208. OUT LPTSTR pszBuf,
  209. IN int cchBuf,
  210. OUT OPTIONAL int* pcchValueSize // S_OK: chars written, excluding final trailing null
  211. // REG_E_MORE_DATA: required size, including nulls
  212. )
  213. {
  214. return SafeRegQueryValueCchHelper(REG_MULTI_SZ, hkey, pszValueName, pszBuf, cchBuf, pcchValueSize, NULL);
  215. }
  216. HRESULT WINAPI SafeRegQueryMultiStringValueCb
  217. (
  218. IN HKEY hkey,
  219. IN LPCTSTR pszValueName,
  220. OUT LPTSTR pszBuf,
  221. IN int cbBuf,
  222. OUT OPTIONAL int* pcbValueSize // S_OK: bytes written, excluding final trailing null
  223. // REG_E_MORE_DATA: required size, including nulls
  224. )
  225. {
  226. int cchBuf = cbBuf / sizeof(TCHAR); // note: odd #'s for cbBuf are rounded down
  227. HRESULT hr = SafeRegQueryValueCchHelper(REG_MULTI_SZ, hkey, pszValueName, pszBuf, cchBuf, pcbValueSize, NULL);
  228. if (pcbValueSize)
  229. *pcbValueSize *= sizeof(TCHAR);
  230. return hr;
  231. }
  232. // SafeRegQueryStringValueCchAlloc [public]
  233. //
  234. // Allocates room for the registry string via SafeRegMalloc, and returns
  235. // the resulting string. Caller should free via SafeRegFree.
  236. //
  237. HRESULT WINAPI SafeRegQueryStringValueCchAlloc
  238. (
  239. IN HKEY hkey,
  240. IN LPCTSTR pszValueName,
  241. OUT LPTSTR* ppszBuf,
  242. OUT OPTIONAL int* pcchValueSize, // chars written, excluding trailing null
  243. OUT OPTIONAL BOOL* pfExpandSz // TRUE if reg string is actually REG_EXPAND_SZ
  244. )
  245. {
  246. return SafeRegQueryValueCchAllocHelper(REG_SZ, hkey, pszValueName, ppszBuf, pcchValueSize, pfExpandSz);
  247. }
  248. HRESULT WINAPI SafeRegQueryStringValueCbAlloc
  249. (
  250. IN HKEY hkey,
  251. IN LPCTSTR pszValueName,
  252. OUT LPTSTR* ppszBuf,
  253. OUT OPTIONAL int* pcbValueSize, // bytes written, excluding trailing null
  254. OUT OPTIONAL BOOL* pfExpandSz // TRUE if reg string is actually REG_EXPAND_SZ
  255. )
  256. {
  257. HRESULT hr = SafeRegQueryValueCchAllocHelper(REG_SZ, hkey, pszValueName, ppszBuf, pcbValueSize, pfExpandSz);
  258. if (pcbValueSize)
  259. *pcbValueSize *= sizeof(TCHAR);
  260. return hr;
  261. }
  262. // SafeRegQueryMultiStringValueCchAlloc [public]
  263. //
  264. // Allocates room for the registry string via SafeRegMalloc, and returns
  265. // the resulting string. Caller should free via SafeRegFree.
  266. //
  267. HRESULT WINAPI SafeRegQueryMultiStringValueCchAlloc
  268. (
  269. IN HKEY hkey,
  270. IN LPCTSTR pszValueName,
  271. OUT LPTSTR* ppszBuf,
  272. OUT OPTIONAL int* pcchValueSize // chars written, excluding final trailing null
  273. )
  274. {
  275. return SafeRegQueryValueCchAllocHelper(REG_MULTI_SZ, hkey, pszValueName, ppszBuf, pcchValueSize, NULL);
  276. }
  277. HRESULT WINAPI SafeRegQueryMultiStringValueCbAlloc
  278. (
  279. IN HKEY hkey,
  280. IN LPCTSTR pszValueName,
  281. OUT LPTSTR* ppszBuf,
  282. OUT OPTIONAL int* pcbValueSize // bytes written, excluding final trailing null
  283. )
  284. {
  285. HRESULT hr = SafeRegQueryValueCchAllocHelper(REG_MULTI_SZ, hkey, pszValueName, ppszBuf, pcbValueSize, NULL);
  286. if (pcbValueSize)
  287. *pcbValueSize *= sizeof(TCHAR);
  288. return hr;
  289. }