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.

477 lines
13 KiB

  1. /*****************************************************************/
  2. /** Microsoft Windows for Workgroups **/
  3. /** Copyright (C) Microsoft Corp., 1995-1996 **/
  4. /*****************************************************************/
  5. /*
  6. regentry.cpp
  7. registry access classes
  8. This file contains classes which enable
  9. convenient access the registry for entries.
  10. FILE HISTORY:
  11. lens 10/15/95 Created
  12. ChrisPi 6/21/96 Added GetBinary(), SetValue() for binary
  13. */
  14. #include "precomp.h"
  15. #include <regentry.h>
  16. #include <strutil.h>
  17. RegEntry::RegEntry(LPCTSTR pszSubKey, HKEY hkey, BOOL fCreate, REGSAM samDesired)
  18. : m_pbValueBuffer(NULL),
  19. m_cbValueBuffer(0),
  20. m_fValuesWritten(FALSE),
  21. m_szNULL('\0')
  22. {
  23. // Open with desired access if it is specified explicitly; otherwise, use
  24. // the default access.
  25. if (samDesired) {
  26. if (fCreate) {
  27. DWORD dwDisposition;
  28. m_error = ::RegCreateKeyEx(hkey,
  29. pszSubKey,
  30. 0,
  31. NULL,
  32. REG_OPTION_NON_VOLATILE,
  33. samDesired,
  34. NULL,
  35. &m_hkey,
  36. &dwDisposition);
  37. }
  38. else {
  39. m_error = ::RegOpenKeyEx(hkey, pszSubKey, 0, samDesired, &m_hkey);
  40. }
  41. }
  42. else {
  43. if (fCreate) {
  44. m_error = ::RegCreateKey(hkey, pszSubKey, &m_hkey);
  45. }
  46. else {
  47. m_error = ::RegOpenKey(hkey, pszSubKey, &m_hkey);
  48. }
  49. }
  50. m_fhkeyValid = (m_error == ERROR_SUCCESS);
  51. }
  52. RegEntry::~RegEntry()
  53. {
  54. ChangeKey(NULL);
  55. delete [] m_pbValueBuffer;
  56. }
  57. VOID RegEntry::ChangeKey(HKEY hNewKey)
  58. {
  59. // hNewKey assumed to be valid or never used
  60. // (as in destructor).
  61. if (m_fValuesWritten) {
  62. FlushKey();
  63. }
  64. if (m_fhkeyValid) {
  65. ::RegCloseKey(m_hkey);
  66. }
  67. m_hkey = hNewKey;
  68. }
  69. VOID RegEntry::UpdateWrittenStatus()
  70. {
  71. if (m_error == ERROR_SUCCESS) {
  72. m_fValuesWritten = TRUE;
  73. }
  74. }
  75. long RegEntry::SetValue(LPCTSTR pszValue, LPCTSTR string)
  76. {
  77. if (m_fhkeyValid) {
  78. m_error = ::RegSetValueEx(m_hkey, pszValue, 0, REG_SZ,
  79. (LPBYTE)string, (lstrlen(string)+1) * sizeof(*string));
  80. UpdateWrittenStatus();
  81. }
  82. return m_error;
  83. }
  84. long RegEntry::SetValue(LPCTSTR pszValue, unsigned long dwNumber)
  85. {
  86. if (m_fhkeyValid) {
  87. m_error = ::RegSetValueEx(m_hkey, pszValue, 0, REG_BINARY,
  88. (LPBYTE)&dwNumber, sizeof(dwNumber));
  89. UpdateWrittenStatus();
  90. }
  91. return m_error;
  92. }
  93. long RegEntry::SetValue(LPCTSTR pszValue,
  94. void* pData,
  95. DWORD cbLength)
  96. {
  97. if (m_fhkeyValid) {
  98. m_error = ::RegSetValueEx( m_hkey,
  99. pszValue,
  100. 0,
  101. REG_BINARY,
  102. (LPBYTE) pData,
  103. cbLength);
  104. UpdateWrittenStatus();
  105. }
  106. return m_error;
  107. }
  108. long RegEntry::DeleteValue(LPCTSTR pszValue)
  109. {
  110. if (m_fhkeyValid) {
  111. m_error = ::RegDeleteValue(m_hkey, pszValue);
  112. UpdateWrittenStatus();
  113. }
  114. return m_error;
  115. }
  116. long RegEntry::GetNumber(LPCTSTR pszValue, long dwDefault)
  117. {
  118. DWORD dwType = REG_BINARY;
  119. long dwNumber = 0L;
  120. DWORD dwSize = sizeof(dwNumber);
  121. if (m_fhkeyValid) {
  122. m_error = ::RegQueryValueEx(m_hkey, pszValue, 0, &dwType, (LPBYTE)&dwNumber,
  123. &dwSize);
  124. }
  125. // If the call succeeded, make sure that the returned data matches our
  126. // expectations.
  127. ASSERT(m_error != ERROR_SUCCESS ||
  128. (REG_BINARY == dwType && sizeof(dwNumber) == dwSize) ||
  129. REG_DWORD == dwType);
  130. if (m_error != ERROR_SUCCESS)
  131. dwNumber = dwDefault;
  132. return dwNumber;
  133. }
  134. // The GetNumberIniStyle method performs the same function as GetNumber,
  135. // but in a style compatible with the old GetPrivateProfileInt API.
  136. // Specfically it means:
  137. // - If the value is stored in the registry as a string, it attempts to
  138. // convert it to an integer.
  139. // - If the value is negative, it returns 0.
  140. ULONG RegEntry::GetNumberIniStyle(LPCTSTR pszValueName, ULONG dwDefault)
  141. {
  142. DWORD dwType = REG_BINARY;
  143. ULONG dwNumber = 0L;
  144. DWORD cbLength = m_cbValueBuffer;
  145. if (m_fhkeyValid) {
  146. m_error = ::RegQueryValueEx(m_hkey,
  147. pszValueName,
  148. 0,
  149. &dwType,
  150. m_pbValueBuffer,
  151. &cbLength);
  152. // Try again with a larger buffer if the first one is too small,
  153. // or if there wasn't already a buffer allocated.
  154. if ((ERROR_SUCCESS == m_error && NULL == m_pbValueBuffer)
  155. || ERROR_MORE_DATA == m_error) {
  156. ASSERT(cbLength > m_cbValueBuffer);
  157. ResizeValueBuffer(cbLength);
  158. m_error = RegQueryValueEx( m_hkey,
  159. pszValueName,
  160. 0,
  161. &dwType,
  162. m_pbValueBuffer,
  163. &cbLength );
  164. }
  165. if (ERROR_SUCCESS == m_error) {
  166. switch(dwType) {
  167. case REG_DWORD:
  168. case REG_BINARY:
  169. ASSERT(sizeof(dwNumber) == cbLength);
  170. dwNumber = * (LPDWORD) m_pbValueBuffer;
  171. break;
  172. case REG_SZ:
  173. {
  174. LONG lNumber = RtStrToInt((LPCTSTR) m_pbValueBuffer);
  175. // Convert negative numbers to zero, to match
  176. // GetPrivateProfileInt's behavior.
  177. dwNumber = lNumber < 0 ? 0 : lNumber;
  178. }
  179. break;
  180. default:
  181. ERROR_OUT(("Invalid value type (%lu) returned by RegQueryValueEx()",
  182. dwType));
  183. break;
  184. }
  185. }
  186. }
  187. if (m_error != ERROR_SUCCESS) {
  188. dwNumber = dwDefault;
  189. }
  190. return dwNumber;
  191. }
  192. LPTSTR RegEntry::GetString(LPCTSTR pszValueName)
  193. {
  194. DWORD dwType = REG_SZ;
  195. DWORD length = m_cbValueBuffer;
  196. if (m_fhkeyValid) {
  197. m_error = ::RegQueryValueEx( m_hkey,
  198. pszValueName,
  199. 0,
  200. &dwType,
  201. m_pbValueBuffer,
  202. &length );
  203. // Try again with a larger buffer if the first one is too small,
  204. // or if there wasn't already a buffer allocated.
  205. if ((ERROR_SUCCESS == m_error && NULL == m_pbValueBuffer)
  206. || ERROR_MORE_DATA == m_error) {
  207. ASSERT(length > m_cbValueBuffer);
  208. ResizeValueBuffer(length);
  209. m_error = ::RegQueryValueEx( m_hkey,
  210. pszValueName,
  211. 0,
  212. &dwType,
  213. m_pbValueBuffer,
  214. &length );
  215. }
  216. if (m_error == ERROR_SUCCESS) {
  217. if ((dwType != REG_SZ) && (dwType != REG_EXPAND_SZ)) {
  218. m_error = ERROR_INVALID_PARAMETER;
  219. }
  220. }
  221. }
  222. if ((m_error != ERROR_SUCCESS) || (length == 0)) {
  223. return &m_szNULL;
  224. }
  225. return (LPTSTR) m_pbValueBuffer;
  226. }
  227. DWORD RegEntry::GetBinary( LPCTSTR pszValueName,
  228. void** ppvData)
  229. {
  230. ASSERT(ppvData);
  231. DWORD dwType = REG_BINARY;
  232. DWORD length = m_cbValueBuffer;
  233. if (m_fhkeyValid) {
  234. m_error = ::RegQueryValueEx( m_hkey,
  235. pszValueName,
  236. 0,
  237. &dwType,
  238. m_pbValueBuffer,
  239. &length );
  240. // Try again with a larger buffer if the first one is too small,
  241. // or if there wasn't already a buffer allocated.
  242. if ((ERROR_SUCCESS == m_error && NULL == m_pbValueBuffer)
  243. || ERROR_MORE_DATA == m_error) {
  244. ASSERT(length > m_cbValueBuffer);
  245. ResizeValueBuffer(length);
  246. m_error = ::RegQueryValueEx( m_hkey,
  247. pszValueName,
  248. 0,
  249. &dwType,
  250. m_pbValueBuffer,
  251. &length );
  252. }
  253. if (m_error == ERROR_SUCCESS) {
  254. if (dwType != REG_BINARY) {
  255. m_error = ERROR_INVALID_PARAMETER;
  256. }
  257. }
  258. }
  259. if ((m_error != ERROR_SUCCESS) || (length == 0)) {
  260. *ppvData = NULL;
  261. length = 0;
  262. }
  263. else
  264. {
  265. *ppvData = m_pbValueBuffer;
  266. }
  267. return length;
  268. }
  269. // BUGBUG - Use LocalReAlloc instead of new/delete?
  270. VOID RegEntry::ResizeValueBuffer(DWORD length)
  271. {
  272. LPBYTE pbNewBuffer;
  273. if ((m_error == ERROR_SUCCESS || m_error == ERROR_MORE_DATA)
  274. && (length > m_cbValueBuffer)) {
  275. pbNewBuffer = new BYTE[length];
  276. if (pbNewBuffer) {
  277. delete [] m_pbValueBuffer;
  278. m_pbValueBuffer = pbNewBuffer;
  279. m_cbValueBuffer = length;
  280. }
  281. else {
  282. m_error = ERROR_NOT_ENOUGH_MEMORY;
  283. }
  284. }
  285. }
  286. // BUGBUG - Support other OpenKey switches from constructor
  287. VOID RegEntry::MoveToSubKey(LPCTSTR pszSubKeyName)
  288. {
  289. HKEY _hNewKey;
  290. if (m_fhkeyValid) {
  291. m_error = ::RegOpenKey ( m_hkey,
  292. pszSubKeyName,
  293. &_hNewKey );
  294. if (m_error == ERROR_SUCCESS) {
  295. ChangeKey(_hNewKey);
  296. }
  297. }
  298. }
  299. RegEnumValues::RegEnumValues(RegEntry *pReqRegEntry)
  300. : m_pRegEntry(pReqRegEntry),
  301. m_iEnum(0),
  302. m_pchName(NULL),
  303. m_pbValue(NULL)
  304. {
  305. m_error = m_pRegEntry->GetError();
  306. if (m_error == ERROR_SUCCESS) {
  307. m_error = ::RegQueryInfoKey (m_pRegEntry->GetKey(), // Key
  308. NULL, // Buffer for class string
  309. NULL, // Size of class string buffer
  310. NULL, // Reserved
  311. NULL, // Number of subkeys
  312. NULL, // Longest subkey name
  313. NULL, // Longest class string
  314. &m_cEntries, // Number of value entries
  315. &m_cMaxValueName, // Longest value name
  316. &m_cMaxData, // Longest value data
  317. NULL, // Security descriptor
  318. NULL ); // Last write time
  319. }
  320. if (m_error == ERROR_SUCCESS) {
  321. if (m_cEntries != 0) {
  322. m_cMaxValueName++; // REG_SZ needs one more for null
  323. m_cMaxData++; // REG_SZ needs one more for null
  324. m_pchName = new TCHAR[m_cMaxValueName];
  325. if (!m_pchName) {
  326. m_error = ERROR_NOT_ENOUGH_MEMORY;
  327. }
  328. else {
  329. if (m_cMaxData) {
  330. m_pbValue = new BYTE[m_cMaxData];
  331. if (!m_pbValue) {
  332. m_error = ERROR_NOT_ENOUGH_MEMORY;
  333. }
  334. }
  335. }
  336. }
  337. }
  338. }
  339. RegEnumValues::~RegEnumValues()
  340. {
  341. delete m_pchName;
  342. delete m_pbValue;
  343. }
  344. long RegEnumValues::Next()
  345. {
  346. if (m_error != ERROR_SUCCESS) {
  347. return m_error;
  348. }
  349. if (m_cEntries == m_iEnum) {
  350. return ERROR_NO_MORE_ITEMS;
  351. }
  352. DWORD cchName = m_cMaxValueName;
  353. m_dwDataLength = m_cMaxData;
  354. m_error = ::RegEnumValue ( m_pRegEntry->GetKey(), // Key
  355. m_iEnum, // Index of value
  356. m_pchName, // Address of buffer for value name
  357. &cchName, // Address for size of buffer
  358. NULL, // Reserved
  359. &m_dwType, // Data type
  360. m_pbValue, // Address of buffer for value data
  361. &m_dwDataLength ); // Address for size of data
  362. m_iEnum++;
  363. return m_error;
  364. }
  365. RegEnumSubKeys::RegEnumSubKeys(RegEntry *pReqRegEntry)
  366. : m_pRegEntry(pReqRegEntry),
  367. m_iEnum(0),
  368. m_pchName(NULL)
  369. {
  370. m_error = m_pRegEntry->GetError();
  371. if (m_error == ERROR_SUCCESS) {
  372. m_error = ::RegQueryInfoKey ( m_pRegEntry->GetKey(), // Key
  373. NULL, // Buffer for class string
  374. NULL, // Size of class string buffer
  375. NULL, // Reserved
  376. &m_cEntries, // Number of subkeys
  377. &m_cMaxKeyName, // Longest subkey name
  378. NULL, // Longest class string
  379. NULL, // Number of value entries
  380. NULL, // Longest value name
  381. NULL, // Longest value data
  382. NULL, // Security descriptor
  383. NULL ); // Last write time
  384. }
  385. if (m_error == ERROR_SUCCESS) {
  386. if (m_cEntries != 0) {
  387. m_cMaxKeyName = m_cMaxKeyName + 1; // needs one more for null
  388. m_pchName = new TCHAR[m_cMaxKeyName];
  389. if (!m_pchName) {
  390. m_error = ERROR_NOT_ENOUGH_MEMORY;
  391. }
  392. }
  393. }
  394. }
  395. RegEnumSubKeys::~RegEnumSubKeys()
  396. {
  397. delete m_pchName;
  398. }
  399. long RegEnumSubKeys::Next()
  400. {
  401. if (m_error != ERROR_SUCCESS) {
  402. return m_error;
  403. }
  404. if (m_cEntries == m_iEnum) {
  405. return ERROR_NO_MORE_ITEMS;
  406. }
  407. DWORD cchName = m_cMaxKeyName;
  408. m_error = ::RegEnumKey ( m_pRegEntry->GetKey(), // Key
  409. m_iEnum, // Index of value
  410. m_pchName, // Address of buffer for subkey name
  411. cchName); // Size of buffer
  412. m_iEnum++;
  413. return m_error;
  414. }