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.

446 lines
14 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. regqmval.c
  5. Abstract:
  6. This module contains the client side wrappers for the Win32 Registry
  7. query multiple values APIs:
  8. - RegQueryMultipleValuesA
  9. - RegQueryMultipleValuesW
  10. Author:
  11. John Vert (jvert) 15-Jun-1995
  12. Revision History:
  13. --*/
  14. #include <rpc.h>
  15. #include "regrpc.h"
  16. #include "client.h"
  17. WINADVAPI
  18. LONG
  19. APIENTRY
  20. RegQueryMultipleValuesA (
  21. HKEY hKey,
  22. PVALENTA val_list,
  23. DWORD num_vals,
  24. LPSTR lpValueBuf,
  25. LPDWORD ldwTotsize
  26. )
  27. /*++
  28. Routine Description:
  29. The RegQueryMultipleValues function retrieves a list of
  30. data type/data pairs for a list of value names associated
  31. with an open registry key.
  32. Parameters:
  33. hKey
  34. Identifies a currently open key or any of the pre-defined reserved handle values:
  35. HKEY_CLASSES_ROOT
  36. HEY_CURRENT_USER
  37. HKEY_LOCAL_MACHINE
  38. HKEY_USERS
  39. valList
  40. Points to an array of structures describing one or more value entries. This
  41. contains the value names of the values to be queried. Refer to Appendix A for a
  42. description of VALUE_ENTRY structure.
  43. num_vals
  44. Size of valList in bytes. If valListLength is not a multiple of the sizeof pvalue, the
  45. fractional extra space pointed to by valList is ignored.
  46. lpValueBuf
  47. The output buffer for returning value information (value names and value data). Data
  48. is DWORD aligned with pads inserted as necessary.
  49. ldwTotsize
  50. The total size of the output buffer pointed to by lpvalueBuf. On output ldwTotsize
  51. contains the number of bytes used including pads. If lpValueBuf was too short, then on
  52. output ldwTotsize will be the size needed, and caller should assume that lpValueBuf was
  53. filled up to the size specified by ldwTotsize on input.
  54. Return value:
  55. If the function succeeds, the return value is ERROR_SUCCESS; otherwise it is one
  56. of the error value which can be returned by RegQueryValueEx. In addition, if
  57. either valList or lpValueBuf is too small then ERROR_INSUFFICIENT_BUFFER is returned
  58. If the function is unable to instantiate/access the provider of the
  59. dynamic key, it will return ERROR_CANTREAD. If the total length of the
  60. requested data (valListLength + ldwTotSize) is more than the system limit of one
  61. megabytes, then the function returns ERROR_TRANSFER_TOO_LONG and only the first
  62. megabyte of data is returned.
  63. --*/
  64. {
  65. NTSTATUS Status;
  66. PRVALENT Values;
  67. PUNICODE_STRING Names;
  68. LONG Error;
  69. ULONG i;
  70. ULONG DataLength;
  71. ULONG InputLength;
  72. LPDWORD pTotalSize;
  73. DWORD TotalSize;
  74. ANSI_STRING AnsiString;
  75. LPSTR NewValueBuf = NULL;
  76. DWORD DataOffset;
  77. ULONG AnsiLength;
  78. HKEY TempHandle = NULL;
  79. hKey = MapPredefinedHandle(hKey, &TempHandle);
  80. if (hKey == NULL) {
  81. Error = ERROR_INVALID_HANDLE;
  82. goto ExitCleanup;
  83. }
  84. //
  85. // Allocate an array of RVALENTs to describe the input value names
  86. //
  87. Values = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(RVALENT));
  88. if (Values == NULL) {
  89. Error = ERROR_OUTOFMEMORY;
  90. goto ExitCleanup;
  91. }
  92. ZeroMemory(Values, sizeof(RVALENT)*num_vals);
  93. //
  94. // Allocate an array of UNICODE_STRINGs to contain the input names
  95. //
  96. Names = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(UNICODE_STRING));
  97. if (Names == NULL) {
  98. Error = ERROR_OUTOFMEMORY;
  99. goto ExitCleanup;
  100. }
  101. ZeroMemory(Names, num_vals*sizeof(UNICODE_STRING));
  102. //
  103. // Convert the value names to UNICODE_STRINGs
  104. //
  105. for (i=0; i<num_vals; i++) {
  106. RtlInitAnsiString(&AnsiString, val_list[i].ve_valuename);
  107. Status = RtlAnsiStringToUnicodeString(&Names[i], &AnsiString, TRUE);
  108. if (!NT_SUCCESS(Status)) {
  109. Error = RtlNtStatusToDosError( Status );
  110. goto Cleanup;
  111. }
  112. //
  113. // Add the terminating NULL to the Length so that RPC transmits
  114. // it.
  115. //
  116. Names[i].Length += sizeof( UNICODE_NULL );
  117. Values[i].rv_valuename = &Names[i];
  118. }
  119. //
  120. // Allocate a data buffer twice the size of the input buffer
  121. // so that any Unicode value data will fit before it is converted
  122. // to Ansi.
  123. //
  124. if ((ldwTotsize == NULL) || (*ldwTotsize == 0)) {
  125. TotalSize = 0;
  126. } else {
  127. TotalSize = *ldwTotsize * sizeof(WCHAR);
  128. NewValueBuf = RtlAllocateHeap(RtlProcessHeap(),0,TotalSize);
  129. if (NewValueBuf == NULL) {
  130. Error = ERROR_OUTOFMEMORY;
  131. goto Cleanup;
  132. }
  133. }
  134. pTotalSize = &TotalSize;
  135. //
  136. // Call the Base API, passing it the supplied parameters and the
  137. // counted Unicode strings.
  138. //
  139. if (IsLocalHandle(hKey)) {
  140. Error = (LONG)LocalBaseRegQueryMultipleValues(hKey,
  141. Values,
  142. num_vals,
  143. NewValueBuf,
  144. pTotalSize);
  145. } else {
  146. DWORD dwVersion;
  147. Error = (LONG)BaseRegQueryMultipleValues(DereferenceRemoteHandle( hKey ),
  148. Values,
  149. num_vals,
  150. NewValueBuf,
  151. pTotalSize);
  152. if ((Error == ERROR_SUCCESS) &&
  153. (IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion))) {
  154. //
  155. // Win95's RegQueryMultipleValues doesn't return Unicode
  156. // value data, so do not try and convert it back to Ansi.
  157. //
  158. for (i=0; i<num_vals; i++) {
  159. val_list[i].ve_valuelen = Values[i].rv_valuelen;
  160. val_list[i].ve_type = Values[i].rv_type;
  161. val_list[i].ve_valueptr = (DWORD_PTR)(lpValueBuf + Values[i].rv_valueptr);
  162. }
  163. CopyMemory(lpValueBuf,NewValueBuf,TotalSize);
  164. if (ldwTotsize != NULL) {
  165. *ldwTotsize = TotalSize;
  166. }
  167. goto Cleanup;
  168. }
  169. }
  170. if (Error == ERROR_SUCCESS) {
  171. //
  172. // Convert results back.
  173. //
  174. DataOffset = 0;
  175. for (i=0; i < num_vals; i++) {
  176. val_list[i].ve_valuelen = Values[i].rv_valuelen;
  177. val_list[i].ve_type = Values[i].rv_type;
  178. val_list[i].ve_valueptr = (DWORD_PTR)(lpValueBuf + DataOffset);
  179. if ((val_list[i].ve_type == REG_SZ) ||
  180. (val_list[i].ve_type == REG_EXPAND_SZ) ||
  181. (val_list[i].ve_type == REG_MULTI_SZ)) {
  182. Status = RtlUnicodeToMultiByteN(lpValueBuf + DataOffset,
  183. Values[i].rv_valuelen/sizeof(WCHAR),
  184. &AnsiLength,
  185. (PWCH)(NewValueBuf + Values[i].rv_valueptr),
  186. Values[i].rv_valuelen);
  187. if (!NT_SUCCESS(Status)) {
  188. Error = RtlNtStatusToDosError( Status );
  189. }
  190. val_list[i].ve_valuelen = AnsiLength;
  191. DataOffset += AnsiLength;
  192. } else {
  193. CopyMemory(lpValueBuf + DataOffset,
  194. NewValueBuf + Values[i].rv_valueptr,
  195. Values[i].rv_valuelen);
  196. DataOffset += Values[i].rv_valuelen;
  197. }
  198. //
  199. // Round DataOffset up to dword boundary.
  200. //
  201. DataOffset = (DataOffset + sizeof(DWORD) - 1) & ~(sizeof(DWORD)-1);
  202. }
  203. if (ldwTotsize != NULL) {
  204. *ldwTotsize = DataOffset;
  205. }
  206. } else if (Error == ERROR_MORE_DATA) {
  207. //
  208. // We need to thunk the Unicode required bytes back to Ansi. But
  209. // there is not really any way to do this without having the data
  210. // available. So just return the required bytes for the Unicode
  211. // data, as this will always be enough.
  212. //
  213. if (ldwTotsize != NULL) {
  214. *ldwTotsize = *pTotalSize;
  215. }
  216. }
  217. Cleanup:
  218. if (NewValueBuf != NULL) {
  219. RtlFreeHeap(RtlProcessHeap(),0,NewValueBuf);
  220. }
  221. for (i=0; i<num_vals; i++) {
  222. if (Names[i].Buffer != NULL) {
  223. RtlFreeUnicodeString(&Names[i]);
  224. }
  225. }
  226. RtlFreeHeap(RtlProcessHeap(),0,Values);
  227. RtlFreeHeap(RtlProcessHeap(),0,Names);
  228. ExitCleanup:
  229. CLOSE_LOCAL_HANDLE(TempHandle);
  230. return Error;
  231. }
  232. WINADVAPI
  233. LONG
  234. APIENTRY
  235. RegQueryMultipleValuesW (
  236. HKEY hKey,
  237. PVALENTW val_list,
  238. DWORD num_vals,
  239. LPWSTR lpValueBuf,
  240. LPDWORD ldwTotsize
  241. )
  242. /*++
  243. Routine Description:
  244. The RegQueryMultipleValues function retrieves a list of
  245. data type/data pairs for a list of value names associated
  246. with an open registry key.
  247. Parameters:
  248. hKey
  249. Identifies a currently open key or any of the pre-defined reserved handle values:
  250. HKEY_CLASSES_ROOT
  251. HEY_CURRENT_USER
  252. HKEY_LOCAL_MACHINE
  253. HKEY_USERS
  254. valList
  255. Points to an array of structures describing one or more value entries. This
  256. contains the value names of the values to be queried. Refer to Appendix A for a
  257. description of VALUE_ENTRY structure.
  258. num_vals
  259. Size of valList in bytes. If valListLength is not a multiple of the sizeof pvalue, the
  260. fractional extra space pointed to by valList is ignored.
  261. lpValueBuf
  262. The output buffer for returning value information (value names and value data). Data
  263. is DWORD aligned with pads inserted as necessary.
  264. ldwTotsize
  265. The total size of the output buffer pointed to by lpValueBuf. On output ldwTotsize
  266. contains the number of bytes used including pads. If lpValueBuf was too short, then on
  267. output ldwTotsize will be the size needed, and caller should assume that lpValueBuf was
  268. filled up to the size specified by ldwTotsize on input.
  269. Return value:
  270. If the function succeeds, the return value is ERROR_SUCCESS; otherwise it is one
  271. of the error value which can be returned by RegQueryValueEx. In addition, if
  272. either valList or lpValueBuf is too small then ERROR_INSUFFICIENT_BUFFER is returned
  273. If the function is unable to instantiate/access the provider of the
  274. dynamic key, it will return ERROR_CANTREAD. If the total length of the
  275. requested data (valListLength + ldwTotSize) is more than the system limit of one
  276. megabytes, then the function returns ERROR_TRANSFER_TOO_LONG and only the first
  277. megabyte of data is returned.
  278. --*/
  279. {
  280. NTSTATUS Status;
  281. PRVALENT Values;
  282. PUNICODE_STRING Names;
  283. LONG Error;
  284. ULONG i;
  285. ULONG DataLength;
  286. ULONG InputLength;
  287. LPDWORD pTotalSize;
  288. DWORD TotalSize;
  289. DWORD StringLength;
  290. HKEY TempHandle = NULL;
  291. hKey = MapPredefinedHandle(hKey, &TempHandle);
  292. if (hKey == NULL) {
  293. Error = ERROR_INVALID_HANDLE;
  294. goto ExitCleanup;
  295. }
  296. //
  297. // Allocate an array of RVALENTs to describe the input value names
  298. //
  299. Values = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(RVALENT));
  300. if (Values == NULL) {
  301. Error = ERROR_OUTOFMEMORY;
  302. goto ExitCleanup;
  303. }
  304. ZeroMemory(Values, sizeof(RVALENT)*num_vals);
  305. //
  306. // Allocate an array of UNICODE_STRINGs to contain the input names
  307. //
  308. Names = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(UNICODE_STRING));
  309. if (Names == NULL) {
  310. RtlFreeHeap(RtlProcessHeap(), 0, Values);
  311. Error = ERROR_OUTOFMEMORY;
  312. goto ExitCleanup;
  313. }
  314. ZeroMemory(Names, num_vals*sizeof(UNICODE_STRING));
  315. //
  316. // Copy and convert the value names to UNICODE_STRINGs
  317. // Note that we have to copy the value names because RPC tromps
  318. // on them.
  319. //
  320. for (i=0; i<num_vals; i++) {
  321. StringLength = wcslen(val_list[i].ve_valuename)*sizeof(WCHAR);
  322. Names[i].Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, StringLength + sizeof(UNICODE_NULL));
  323. if (Names[i].Buffer == NULL) {
  324. goto error_exit;
  325. }
  326. Names[i].Length = Names[i].MaximumLength = (USHORT)StringLength + sizeof(UNICODE_NULL);
  327. CopyMemory(Names[i].Buffer, val_list[i].ve_valuename, StringLength + sizeof(UNICODE_NULL));
  328. Values[i].rv_valuename = &Names[i];
  329. }
  330. if (ldwTotsize == NULL) {
  331. TotalSize = 0;
  332. pTotalSize = &TotalSize;
  333. } else {
  334. pTotalSize = ldwTotsize;
  335. }
  336. //
  337. // Call the Base API, passing it the supplied parameters and the
  338. // counted Unicode strings.
  339. //
  340. if (IsLocalHandle(hKey)) {
  341. Error = (LONG)LocalBaseRegQueryMultipleValues(hKey,
  342. Values,
  343. num_vals,
  344. (LPSTR)lpValueBuf,
  345. pTotalSize);
  346. } else {
  347. DWORD dwVersion;
  348. if (IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion)) {
  349. //
  350. // We cannot support RegQueryMultipleValuesW to Win95 servers
  351. // since they do not return Unicode value data.
  352. //
  353. Error = ERROR_CALL_NOT_IMPLEMENTED;
  354. } else {
  355. Error = (LONG)BaseRegQueryMultipleValues(DereferenceRemoteHandle( hKey ),
  356. Values,
  357. num_vals,
  358. (LPSTR)lpValueBuf,
  359. pTotalSize);
  360. }
  361. }
  362. if (Error == ERROR_SUCCESS) {
  363. //
  364. // Convert results back.
  365. //
  366. for (i=0; i < num_vals; i++) {
  367. val_list[i].ve_valuelen = Values[i].rv_valuelen;
  368. val_list[i].ve_valueptr = (DWORD_PTR)((LPCSTR)lpValueBuf + Values[i].rv_valueptr);
  369. val_list[i].ve_type = Values[i].rv_type;
  370. }
  371. }
  372. error_exit:
  373. for (i=0; i < num_vals; i++) {
  374. if (Names[i].Buffer != NULL) {
  375. RtlFreeHeap(RtlProcessHeap(), 0, Names[i].Buffer);
  376. }
  377. }
  378. RtlFreeHeap(RtlProcessHeap(),0,Values);
  379. RtlFreeHeap(RtlProcessHeap(),0,Names);
  380. ExitCleanup:
  381. CLOSE_LOCAL_HANDLE(TempHandle);
  382. return Error;
  383. }