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.

1191 lines
31 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. registry.c
  5. Abstract:
  6. Registry interface routines for Windows NT Setup API Dll.
  7. Author:
  8. Ted Miller (tedm) 6-Feb-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Private function prototypes.
  15. //
  16. DWORD
  17. QueryMultiSzDevRegPropToArray(
  18. IN DEVINST DevInst,
  19. IN ULONG CmPropertyCode,
  20. OUT PTSTR **StringArray,
  21. OUT PUINT StringCount
  22. );
  23. DWORD
  24. SetArrayToMultiSzDevRegProp(
  25. IN DEVINST DevInst,
  26. IN ULONG CmPropertyCode,
  27. IN PTSTR *StringArray,
  28. IN UINT StringCount
  29. );
  30. #if MEM_DBG
  31. DWORD
  32. TrackedQueryRegistryValue(
  33. IN TRACK_ARG_DECLARE TRACK_ARG_COMMA
  34. IN HKEY KeyHandle,
  35. IN PCTSTR ValueName,
  36. OUT PTSTR *Value,
  37. OUT PDWORD DataType,
  38. OUT PDWORD DataSizeBytes
  39. )
  40. {
  41. DWORD d;
  42. TRACK_PUSH
  43. // defined again below
  44. #undef QueryRegistryValue
  45. d = QueryRegistryValue (
  46. KeyHandle,
  47. ValueName,
  48. Value,
  49. DataType,
  50. DataSizeBytes
  51. );
  52. TRACK_POP
  53. return d;
  54. }
  55. #endif
  56. DWORD
  57. QueryRegistryValue(
  58. IN HKEY KeyHandle,
  59. IN PCTSTR ValueName,
  60. OUT PTSTR *Value,
  61. OUT PDWORD DataType,
  62. OUT PDWORD DataSizeBytes
  63. )
  64. {
  65. LONG l;
  66. DWORD sz;
  67. sz = 0;
  68. l = RegQueryValueEx(KeyHandle,ValueName,NULL,DataType,NULL,&sz);
  69. *DataSizeBytes = sz;
  70. if(l != NO_ERROR) {
  71. return((DWORD)l);
  72. }
  73. //
  74. // If the size of the value entry is 0 bytes, then return success, but with
  75. // Value set to NULL.
  76. //
  77. if(!sz) {
  78. *Value = NULL;
  79. return NO_ERROR;
  80. }
  81. sz += sizeof(TCHAR)*2; // always pad the buffer with extra zero's
  82. *Value = MyMalloc(sz);
  83. if(*Value == NULL) {
  84. return(ERROR_NOT_ENOUGH_MEMORY);
  85. }
  86. l = RegQueryValueEx(KeyHandle,ValueName,NULL,DataType,(PVOID)*Value,DataSizeBytes);
  87. if(l != NO_ERROR) {
  88. MyFree(*Value);
  89. } else {
  90. //
  91. // write 2 NULL chars to end of buffer
  92. //
  93. ZeroMemory(((LPBYTE)*Value)+*DataSizeBytes,sizeof(TCHAR)*2);
  94. }
  95. return((DWORD)l);
  96. }
  97. #if MEM_DBG
  98. #define QueryRegistryValue(a,b,c,d,e) TrackedQueryRegistryValue(TRACK_ARG_CALL,a,b,c,d,e)
  99. #endif
  100. DWORD
  101. QueryRegistryDwordValue(
  102. IN HKEY KeyHandle,
  103. IN PCTSTR ValueName,
  104. OUT PDWORD Value
  105. )
  106. {
  107. DWORD Err;
  108. DWORD DataType;
  109. DWORD DataSize;
  110. PTSTR Data;
  111. Err = QueryRegistryValue(KeyHandle,ValueName,&Data,&DataType,&DataSize);
  112. if(Err != NO_ERROR) {
  113. *Value = 0;
  114. return Err;
  115. }
  116. switch (DataType) {
  117. case REG_DWORD:
  118. *Value = *(PDWORD)Data;
  119. break;
  120. case REG_SZ:
  121. case REG_EXPAND_SZ:
  122. case REG_MULTI_SZ:
  123. *Value = (DWORD)_tcstoul(Data,NULL,0);
  124. break;
  125. default:
  126. *Value = 0;
  127. break;
  128. }
  129. MyFree(Data);
  130. return NO_ERROR;
  131. }
  132. #if MEM_DBG
  133. DWORD
  134. TrackedQueryDeviceRegistryProperty(
  135. IN TRACK_ARG_DECLARE TRACK_ARG_COMMA
  136. IN HDEVINFO DeviceInfoSet,
  137. IN PSP_DEVINFO_DATA DeviceInfoData,
  138. IN DWORD Property,
  139. OUT PTSTR *Value,
  140. OUT PDWORD DataType,
  141. OUT PDWORD DataSizeBytes
  142. )
  143. {
  144. DWORD d;
  145. TRACK_PUSH
  146. // defined again below
  147. #undef QueryDeviceRegistryProperty
  148. d = QueryDeviceRegistryProperty (
  149. DeviceInfoSet,
  150. DeviceInfoData,
  151. Property,
  152. Value,
  153. DataType,
  154. DataSizeBytes
  155. );
  156. TRACK_POP
  157. return d;
  158. }
  159. #endif
  160. DWORD
  161. QueryDeviceRegistryProperty(
  162. IN HDEVINFO DeviceInfoSet,
  163. IN PSP_DEVINFO_DATA DeviceInfoData,
  164. IN DWORD Property,
  165. OUT PTSTR *Value,
  166. OUT PDWORD DataType,
  167. OUT PDWORD DataSizeBytes
  168. )
  169. {
  170. DWORD Err;
  171. DWORD sz;
  172. sz = 0;
  173. Err = SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  174. DeviceInfoData,
  175. Property,
  176. DataType,
  177. NULL,
  178. 0,
  179. &sz)
  180. ? NO_ERROR : GetLastError();
  181. *DataSizeBytes = sz;
  182. if((Err != NO_ERROR) && (Err != ERROR_INSUFFICIENT_BUFFER)) {
  183. return Err;
  184. }
  185. //
  186. // If the size of the value entry is 0 bytes, then return success, but with
  187. // Value set to NULL.
  188. //
  189. if(!sz) {
  190. *Value = NULL;
  191. return NO_ERROR;
  192. }
  193. sz += sizeof(TCHAR)*2; // always pad the buffer with extra zero's
  194. *Value = MyMalloc(sz);
  195. if(*Value == NULL) {
  196. return(ERROR_NOT_ENOUGH_MEMORY);
  197. }
  198. Err = SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  199. DeviceInfoData,
  200. Property,
  201. DataType,
  202. (PVOID)*Value,
  203. *DataSizeBytes,
  204. DataSizeBytes)
  205. ? NO_ERROR : GetLastError();
  206. if(Err != NO_ERROR) {
  207. MyFree(*Value);
  208. } else {
  209. //
  210. // write 2 NULL chars to end of buffer
  211. //
  212. ZeroMemory(((LPBYTE)*Value)+*DataSizeBytes,sizeof(TCHAR)*2);
  213. }
  214. return Err;
  215. }
  216. #if MEM_DBG
  217. #define QueryDeviceRegistryProperty(a,b,c,d,e,f) TrackedQueryDeviceRegistryProperty(TRACK_ARG_CALL,a,b,c,d,e,f)
  218. #endif
  219. DWORD
  220. pSetupQueryMultiSzValueToArray(
  221. IN HKEY Root,
  222. IN PCTSTR Subkey,
  223. IN PCTSTR ValueName,
  224. OUT PTSTR **Array,
  225. OUT PUINT StringCount,
  226. IN BOOL FailIfDoesntExist
  227. )
  228. {
  229. DWORD d;
  230. HKEY hKey;
  231. DWORD DataType;
  232. DWORD DataSizeBytes;
  233. PTSTR Value;
  234. DWORD DataSizeChars;
  235. INT Count,i;
  236. PTSTR *array;
  237. PTSTR p;
  238. //
  239. // Open the subkey
  240. //
  241. d = RegOpenKeyEx(Root,Subkey,0,KEY_READ,&hKey);
  242. if((d != NO_ERROR) && FailIfDoesntExist) {
  243. return(d);
  244. }
  245. if(d != NO_ERROR) {
  246. Value = MyMalloc(sizeof(TCHAR));
  247. if(!Value) {
  248. return(ERROR_NOT_ENOUGH_MEMORY);
  249. }
  250. *Value = 0;
  251. DataSizeChars = 1;
  252. Count = 0;
  253. } else {
  254. //
  255. // Query the value and close the subkey.
  256. // If the data is not multisz type, we don't know what to
  257. // do with it here.
  258. // note that QueryRegistryValue ensures that the string is
  259. // always correctly double-NULL terminated
  260. //
  261. d = QueryRegistryValue(hKey,ValueName,&Value,&DataType,&DataSizeBytes);
  262. RegCloseKey(hKey);
  263. if(d != NO_ERROR) {
  264. if(FailIfDoesntExist) {
  265. return(d);
  266. }
  267. } else if(!DataSizeBytes) {
  268. //
  269. // Value entry was zero bytes in length--that's OK as long as the
  270. // datatype is right.
  271. //
  272. if(DataType != REG_MULTI_SZ) {
  273. return(ERROR_INVALID_DATA);
  274. }
  275. }
  276. if((d != NO_ERROR) || !DataSizeBytes) {
  277. Value = MyMalloc(sizeof(TCHAR));
  278. if(!Value) {
  279. return(ERROR_NOT_ENOUGH_MEMORY);
  280. }
  281. *Value = 0;
  282. DataSizeChars = 1;
  283. Count = 0;
  284. } else {
  285. if(DataType != REG_MULTI_SZ) {
  286. MyFree(Value);
  287. return(ERROR_INVALID_DATA);
  288. }
  289. DataSizeChars = DataSizeBytes/sizeof(TCHAR);
  290. for(i=0,p=Value; p[0]; i++,p+=lstrlen(p)+1) {
  291. //
  292. // this will always be ok as QueryRegistryValue
  293. // appends two NULLS onto end of string
  294. //
  295. MYASSERT((DWORD)(p-Value) < DataSizeChars);
  296. }
  297. Count = i;
  298. }
  299. }
  300. //
  301. // Allocate an array to hold the pointers (never allocate a zero-length array!)
  302. //
  303. if(!(array = MyMalloc(Count ? (Count * sizeof(PTSTR)) : sizeof(PTSTR)))) {
  304. MyFree(Value);
  305. return(ERROR_INVALID_DATA);
  306. }
  307. //
  308. // Walk through the multi sz and build the string array.
  309. //
  310. for(i=0,p=Value; p[0]; i++,p+=lstrlen(p)+1) {
  311. MYASSERT(i<Count);
  312. array[i] = DuplicateString(p);
  313. if(array[i] == NULL) {
  314. for(Count=0; Count<i; Count++) {
  315. MyFree(array[Count]);
  316. }
  317. MyFree(array);
  318. MyFree(Value);
  319. return(ERROR_NOT_ENOUGH_MEMORY);
  320. }
  321. }
  322. MyFree(Value);
  323. *Array = array;
  324. *StringCount = Count;
  325. return(NO_ERROR);
  326. }
  327. DWORD
  328. pSetupSetArrayToMultiSzValue(
  329. IN HKEY Root,
  330. IN PCTSTR Subkey,
  331. IN PCTSTR ValueName,
  332. IN PTSTR *Array,
  333. IN UINT StringCount
  334. )
  335. {
  336. UINT i;
  337. UINT Length;
  338. UINT BufferSize;
  339. PTCHAR Buffer;
  340. PTCHAR p;
  341. DWORD d;
  342. HKEY hKey;
  343. DWORD ActionTaken;
  344. //
  345. // Calculate the length of the buffer needed to hold the
  346. // multi sz value. Note that empty strings are not allowed.
  347. //
  348. BufferSize = sizeof(TCHAR);
  349. for(i=0; i<StringCount; i++) {
  350. if(Length = lstrlen(Array[i])) {
  351. BufferSize += (Length + 1) * sizeof(TCHAR);
  352. } else {
  353. return(ERROR_INVALID_DATA);
  354. }
  355. }
  356. //
  357. // Allocate a buffer to hold the data.
  358. //
  359. Buffer = MyMalloc(BufferSize);
  360. if(Buffer == NULL) {
  361. return(ERROR_NOT_ENOUGH_MEMORY);
  362. }
  363. //
  364. // Copy the string data into the buffer, forming a multi sz.
  365. //
  366. for(p=Buffer,i=0; i<StringCount; i++,p+=Length+1) {
  367. Length = lstrlen(Array[i]);
  368. lstrcpy(p,Array[i]);
  369. }
  370. *p = 0;
  371. //
  372. // Open/create the subkey.
  373. //
  374. if(Subkey && *Subkey) {
  375. d = RegCreateKeyEx(
  376. Root,
  377. Subkey,
  378. 0,
  379. NULL,
  380. REG_OPTION_NON_VOLATILE,
  381. KEY_SET_VALUE,
  382. NULL,
  383. &hKey,
  384. &ActionTaken
  385. );
  386. } else {
  387. hKey = Root;
  388. d = NO_ERROR;
  389. }
  390. if(d == NO_ERROR) {
  391. d = RegSetValueEx(
  392. hKey,
  393. ValueName,
  394. 0,
  395. REG_MULTI_SZ,
  396. (PVOID)Buffer,
  397. BufferSize
  398. );
  399. if(hKey != Root) {
  400. RegCloseKey(hKey);
  401. }
  402. }
  403. MyFree(Buffer);
  404. return(d);
  405. }
  406. DWORD
  407. pSetupAppendStringToMultiSz(
  408. IN HKEY Key,
  409. IN PCTSTR SubKeyName, OPTIONAL
  410. IN DWORD DevInst, OPTIONAL
  411. IN PCTSTR ValueName, OPTIONAL
  412. IN PCTSTR String,
  413. IN BOOL AllowDuplicates
  414. )
  415. /*++
  416. Routine Description:
  417. "Old" Exported version of pSetupAppendStringToMultiSz
  418. This doesn't seem to be used anywhere
  419. --*/
  420. {
  421. REGMOD_CONTEXT RegContext;
  422. RegContext.Flags = DevInst ? INF_PFLAG_DEVPROP : 0;
  423. RegContext.UserRootKey = Key;
  424. RegContext.DevInst = DevInst;
  425. return _AppendStringToMultiSz(SubKeyName,ValueName,String,AllowDuplicates,&RegContext,0);
  426. }
  427. DWORD
  428. _AppendStringToMultiSz(
  429. IN PCTSTR SubKeyName, OPTIONAL
  430. IN PCTSTR ValueName, OPTIONAL
  431. IN PCTSTR String,
  432. IN BOOL AllowDuplicates,
  433. IN PREGMOD_CONTEXT RegContext, OPTIONAL
  434. IN UINT Flags OPTIONAL
  435. )
  436. /*++
  437. Routine Description:
  438. Append a string value to a multi_sz.
  439. Arguments:
  440. RegContext->UserRootKey - supplies handle to open registry key. The key must have
  441. KEY_SET_VALUE access.
  442. SubKeyName - if specified, supplies the name of a subkey of Key
  443. where the value is to be stored. If not specified or if ""
  444. then the value is stored in Key. If supplied and the key
  445. doesn't exist, the key is created.
  446. RegContext->DevInst - Optionally, supplies a DEVINST handle for the device
  447. instance corresponding to the hardware storage key specified
  448. by 'Key'. If this handle is specified, and if SubKeyName is
  449. not specified, then the value name being appended will be
  450. checked to see whether it is the name of a device registry
  451. property. If so, then CM APIs will be used to modify the
  452. the corresponding registry property, since the Key handle
  453. represents a separate location under Windows NT.
  454. ValueName - supplies the value entry name of the multi_sz.
  455. If not specified or "" then the unnamed entry is used.
  456. If the value entry does not exist it is created.
  457. String - supplies the string to be added in to the multi_sz.
  458. Must not be an empty string.
  459. AllowDuplicates - if TRUE, then the string is simply appended
  460. to the multi_sz. Otherwise the string is only appended if
  461. no instance of it currently exists in the multi_sz.
  462. RegContext - Passed in from _SetupInstallFromInfSection
  463. Flags - Flags that may have been got from the INF and passed to us
  464. Return Value:
  465. Handle to setup file queue. INVALID_HANDLE_VALUE if insufficient
  466. memory to create the queue.
  467. --*/
  468. {
  469. DWORD d;
  470. DWORD Disposition;
  471. HKEY hKey;
  472. PTSTR *Array;
  473. PVOID p;
  474. BOOL Append;
  475. UINT StringCount;
  476. UINT i;
  477. BOOL IsDevRegProp = FALSE;
  478. BOOL IsClassRegProp = FALSE;
  479. UINT_PTR CmPropertyCode;
  480. MYASSERT(RegContext);
  481. //
  482. // Empty strings really mess up a multi_sz.
  483. //
  484. if(!String || !(*String)) {
  485. return(ERROR_INVALID_PARAMETER);
  486. }
  487. //
  488. // Open/create the key.
  489. //
  490. if(SubKeyName && *SubKeyName) {
  491. d = RegCreateKeyEx(
  492. RegContext->UserRootKey,
  493. SubKeyName,
  494. 0,
  495. NULL,
  496. REG_OPTION_NON_VOLATILE,
  497. #ifdef _WIN64
  498. (( Flags & FLG_ADDREG_32BITKEY ) ? KEY_WOW64_32KEY:0) |
  499. #else
  500. (( Flags & FLG_ADDREG_64BITKEY ) ? KEY_WOW64_64KEY:0) |
  501. #endif
  502. KEY_SET_VALUE,
  503. NULL,
  504. &hKey,
  505. &Disposition
  506. );
  507. if(d != NO_ERROR) {
  508. return(d);
  509. }
  510. } else {
  511. //
  512. // If DevInst was specified, then determine whether the specified value is a Plug&Play
  513. // device registry property.
  514. //
  515. if (ValueName && *ValueName) {
  516. if((RegContext->Flags & INF_PFLAG_CLASSPROP) &&
  517. (IsClassRegProp = LookUpStringInTable(InfRegValToClassRegProp, ValueName, &CmPropertyCode))) {
  518. //
  519. // This value is a class registry property. Retrieve the current property's data, and
  520. // format it into the same string array as returned by the pSetupQueryMultiSzValueToArray call
  521. // below.
  522. //
  523. //d = QueryMultiSzClassRegPropToArray(RegModContext->ClassGuid, CmPropertyCode, &Array, &StringCount);
  524. //
  525. // No class properties have MultiSz characteristics, so not implemented
  526. //
  527. d = ERROR_INVALID_DATA;
  528. } else if((RegContext->Flags & INF_PFLAG_DEVPROP) &&
  529. (IsDevRegProp = LookUpStringInTable(InfRegValToDevRegProp, ValueName, &CmPropertyCode))) {
  530. //
  531. // This value is a device registry property. Retrieve the current property's data, and
  532. // format it into the same string array as returned by the pSetupQueryMultiSzValueToArray call
  533. // below.
  534. //
  535. d = QueryMultiSzDevRegPropToArray(RegContext->DevInst, (ULONG)CmPropertyCode, &Array, &StringCount);
  536. }
  537. }
  538. hKey = RegContext->UserRootKey;
  539. }
  540. if(!IsDevRegProp && !IsClassRegProp) {
  541. //
  542. // Query the existing registry value.
  543. //
  544. d = pSetupQueryMultiSzValueToArray(hKey,NULL,ValueName,&Array,&StringCount,FALSE);
  545. }
  546. if(d == NO_ERROR) {
  547. //
  548. // Determine whether to append or replace.
  549. // If replacing, we don't need to do anything!
  550. //
  551. Append = TRUE;
  552. if(!AllowDuplicates) {
  553. for(i=0; i<StringCount; i++) {
  554. if(!lstrcmpi(Array[i],String)) {
  555. Append = FALSE;
  556. break;
  557. }
  558. }
  559. }
  560. if(Append) {
  561. //
  562. // Stick the string on the end.
  563. //
  564. if(p = MyRealloc(Array, (StringCount+1)*sizeof(PTSTR))) {
  565. Array = p;
  566. p = DuplicateString(String);
  567. if(p) {
  568. Array[StringCount++] = p;
  569. } else {
  570. d = ERROR_NOT_ENOUGH_MEMORY;
  571. }
  572. } else {
  573. d = ERROR_NOT_ENOUGH_MEMORY;
  574. }
  575. if(IsDevRegProp) {
  576. d = SetArrayToMultiSzDevRegProp(RegContext->DevInst, (ULONG)CmPropertyCode, Array, StringCount);
  577. } else if(IsClassRegProp) {
  578. //
  579. // not implemented yet, and should return an error before getting here
  580. //
  581. MYASSERT(IsClassRegProp == FALSE);
  582. } else {
  583. d = pSetupSetArrayToMultiSzValue(hKey,NULL,ValueName,Array,StringCount);
  584. }
  585. }
  586. pSetupFreeStringArray(Array,StringCount);
  587. }
  588. if(hKey != RegContext->UserRootKey) {
  589. RegCloseKey(hKey);
  590. }
  591. return(d);
  592. }
  593. DWORD
  594. _DeleteStringFromMultiSz(
  595. IN PCTSTR SubKeyName, OPTIONAL
  596. IN PCTSTR ValueName, OPTIONAL
  597. IN PCTSTR String,
  598. IN UINT Flags,
  599. IN PREGMOD_CONTEXT RegContext OPTIONAL
  600. )
  601. /*++
  602. Routine Description:
  603. Delete a string value from a multi_sz.
  604. Arguments:
  605. RegContext->UserRootKey - supplies handle to open registry key. The key must have
  606. KEY_SET_VALUE access.
  607. SubKeyName - if specified, supplies the name of a subkey of Key
  608. where the value is to be stored. If not specified or if ""
  609. then the value is stored in Key.
  610. RegContext->DevInst - Optionally, supplies a DEVINST handle for the device
  611. instance corresponding to the hardware storage key specified
  612. by 'Key'. If this handle is specified, and if SubKeyName is
  613. not specified, then the value name being appended will be
  614. checked to see whether it is the name of a device registry
  615. property. If so, then CM APIs will be used to modify the
  616. the corresponding registry property, since the Key handle
  617. represents a separate location under Windows NT.
  618. ValueName - supplies the value entry name of the multi_sz.
  619. If not specified or "" then the unnamed entry is used.
  620. String - supplies the string to be added in to the multi_sz.
  621. Must not be an empty string.
  622. Flags - indicates what kind of delete operation
  623. FLG_DELREG_MULTI_SZ_DELSTRING - delete all occurances of string
  624. RegContext - Passed in from _SetupInstallFromInfSection
  625. Return Value:
  626. Handle to setup file queue. INVALID_HANDLE_VALUE if insufficient
  627. memory to create the queue.
  628. --*/
  629. {
  630. DWORD d;
  631. DWORD Disposition;
  632. HKEY hKey;
  633. PTSTR *Array;
  634. PVOID p;
  635. UINT StringCount;
  636. UINT i;
  637. BOOL IsDevRegProp = FALSE;
  638. BOOL IsClassRegProp = FALSE;
  639. BOOL Modified = FALSE;
  640. UINT_PTR CmPropertyCode;
  641. MYASSERT(RegContext);
  642. //
  643. // Can't delete an empty string from multi-sz
  644. //
  645. if(!String || !(*String)) {
  646. return(ERROR_INVALID_PARAMETER);
  647. }
  648. //
  649. // Open the key.
  650. //
  651. if(SubKeyName && *SubKeyName) {
  652. d = RegOpenKeyEx(
  653. RegContext->UserRootKey,
  654. SubKeyName,
  655. 0,
  656. #ifdef _WIN64
  657. ((Flags & FLG_DELREG_32BITKEY) ? KEY_WOW64_32KEY:0) |
  658. #else
  659. ((Flags & FLG_DELREG_64BITKEY) ? KEY_WOW64_64KEY:0) |
  660. #endif
  661. KEY_SET_VALUE | KEY_QUERY_VALUE,
  662. &hKey
  663. );
  664. if(d != NO_ERROR) {
  665. return(d);
  666. }
  667. } else {
  668. if (ValueName && *ValueName) {
  669. //
  670. // If DevInst was specified, then determine whether the specified value is a Plug&Play
  671. // device registry property.
  672. //
  673. if((RegContext->Flags & INF_PFLAG_CLASSPROP) &&
  674. (IsClassRegProp = LookUpStringInTable(InfRegValToClassRegProp, ValueName, &CmPropertyCode))) {
  675. //
  676. // This value is a class registry property. Retrieve the current property's data, and
  677. // format it into the same string array as returned by the pSetupQueryMultiSzValueToArray call
  678. // below.
  679. //
  680. //d = QueryMultiSzClassRegPropToArray(RegModContext->ClassGuid, CmPropertyCode, &Array, &StringCount);
  681. //
  682. // No class properties have MultiSz characteristics, so not implemented
  683. //
  684. d = ERROR_INVALID_DATA;
  685. } else if((RegContext->Flags & INF_PFLAG_DEVPROP) &&
  686. (IsDevRegProp = LookUpStringInTable(InfRegValToDevRegProp, ValueName, &CmPropertyCode))) {
  687. //
  688. // This value is a device registry property. Retrieve the current property's data, and
  689. // format it into the same string array as returned by the pSetupQueryMultiSzValueToArray call
  690. // below.
  691. // fails if not multi-sz
  692. //
  693. d = QueryMultiSzDevRegPropToArray(RegContext->DevInst, (ULONG)CmPropertyCode, &Array, &StringCount);
  694. }
  695. }
  696. hKey = RegContext->UserRootKey;
  697. }
  698. if(!IsDevRegProp && !IsClassRegProp) {
  699. //
  700. // Query the existing registry value.
  701. // fails if not multi-sz
  702. //
  703. d = pSetupQueryMultiSzValueToArray(hKey,NULL,ValueName,&Array,&StringCount,FALSE);
  704. }
  705. if(d == NO_ERROR) {
  706. switch (Flags) {
  707. case FLG_DELREG_32BITKEY | FLG_DELREG_MULTI_SZ_DELSTRING:
  708. case FLG_DELREG_64BITKEY | FLG_DELREG_MULTI_SZ_DELSTRING:
  709. case FLG_DELREG_MULTI_SZ_DELSTRING:
  710. for(i=0; i<StringCount; i++) {
  711. if(lstrcmpi(Array[i],String)==0) {
  712. //
  713. // Need to remove this item.
  714. // and re-adjust the list
  715. //
  716. MyFree(Array[i]);
  717. StringCount--;
  718. if (i<StringCount) {
  719. MoveMemory(
  720. &Array[i],
  721. &Array[i+1],
  722. (StringCount - i) * sizeof(PTSTR)
  723. );
  724. }
  725. i--;
  726. Modified = TRUE;
  727. }
  728. }
  729. break;
  730. default:
  731. MYASSERT(FALSE);
  732. break;
  733. }
  734. if (Modified) {
  735. if(IsDevRegProp) {
  736. d = SetArrayToMultiSzDevRegProp(RegContext->DevInst, (ULONG)CmPropertyCode, Array, StringCount);
  737. } else if(IsClassRegProp) {
  738. //
  739. // not implemented yet, and should return an error before getting here
  740. //
  741. MYASSERT(IsClassRegProp == FALSE);
  742. } else {
  743. d = pSetupSetArrayToMultiSzValue(hKey,NULL,ValueName,Array,StringCount);
  744. }
  745. }
  746. pSetupFreeStringArray(Array,StringCount);
  747. }
  748. if(hKey != RegContext->UserRootKey) {
  749. RegCloseKey(hKey);
  750. }
  751. return(d);
  752. }
  753. VOID
  754. pSetupFreeStringArray(
  755. IN PTSTR *Array,
  756. IN UINT StringCount
  757. )
  758. {
  759. UINT i;
  760. for(i=0; i<StringCount; i++) {
  761. MyFree(Array[i]);
  762. }
  763. MyFree(Array);
  764. }
  765. DWORD
  766. QueryMultiSzDevRegPropToArray(
  767. IN DEVINST DevInst,
  768. IN ULONG CmPropertyCode,
  769. OUT PTSTR **StringArray,
  770. OUT PUINT StringCount
  771. )
  772. /*++
  773. Routine Description:
  774. This routine retrieves a multi-sz device registry property, and
  775. formats it into an array of strings. The caller must free this
  776. string array by calling pSetupFreeStringArray().
  777. Arguments:
  778. DevInst - supplies the handle to the device instance for which the
  779. registry property is to be retrieved.
  780. CmPropertyCode - specifies the property to be retrieved. This is
  781. a CM_DRP value.
  782. StringArray - supplies the address of a variable that will be set to
  783. point to the newly-allocated array of strings.
  784. StringCount - supplies the address of a variable that will receive
  785. the number of strings in the string array.
  786. Return Value:
  787. If successful, the return value is NO_ERROR, otherwise, it is an
  788. ERROR_* code.
  789. --*/
  790. {
  791. DWORD Err = NO_ERROR;
  792. CONFIGRET cr;
  793. ULONG PropDataType, BufferSize = 0;
  794. PTSTR Buffer = NULL;
  795. PTSTR *Array = NULL;
  796. UINT Count, i;
  797. PTSTR CurString;
  798. try {
  799. //
  800. // Retrieve the device registry property.
  801. //
  802. do {
  803. if((cr = CM_Get_DevInst_Registry_Property(DevInst,
  804. CmPropertyCode,
  805. &PropDataType,
  806. Buffer,
  807. &BufferSize,
  808. 0)) != CR_SUCCESS) {
  809. switch(cr) {
  810. case CR_BUFFER_SMALL :
  811. //
  812. // Allocate a larger buffer.
  813. //
  814. if(Buffer) {
  815. MyFree(Buffer);
  816. Buffer = NULL;
  817. }
  818. if(!(Buffer = MyMalloc(BufferSize))) {
  819. Err = ERROR_NOT_ENOUGH_MEMORY;
  820. goto clean0;
  821. }
  822. break;
  823. case CR_NO_SUCH_VALUE :
  824. //
  825. // The specified property doesn't currently exist. That's
  826. // OK--we'll just return an empty string array.
  827. //
  828. break;
  829. case CR_INVALID_DEVINST :
  830. Err = ERROR_NO_SUCH_DEVINST;
  831. goto clean0;
  832. default :
  833. Err = ERROR_INVALID_DATA;
  834. goto clean0;
  835. }
  836. }
  837. } while(cr == CR_BUFFER_SMALL);
  838. //
  839. // By this point, we've either retrieved the property data (CR_SUCCESS), or we've
  840. // discovered that it doesn't presently exist (CR_NO_SUCH_VALUE). Allocate space
  841. // for the array (at least one element, even if there are no strings).
  842. //
  843. Count = 0;
  844. if(cr == CR_SUCCESS) {
  845. if(PropDataType != REG_MULTI_SZ) {
  846. Err = ERROR_INVALID_DATA;
  847. goto clean0;
  848. }
  849. if (Buffer) {
  850. for(CurString = Buffer;
  851. *CurString;
  852. CurString += (lstrlen(CurString) + 1)) {
  853. Count++;
  854. }
  855. }
  856. }
  857. i = 0;
  858. if(!(Array = MyMalloc(Count ? (Count * sizeof(PTSTR)) : sizeof(PTSTR)))) {
  859. Err = ERROR_NOT_ENOUGH_MEMORY;
  860. goto clean0;
  861. }
  862. if(cr == CR_SUCCESS) {
  863. if (Buffer) {
  864. for(CurString = Buffer;
  865. *CurString;
  866. CurString += (lstrlen(CurString) + 1)) {
  867. if(Array[i] = DuplicateString(CurString)) {
  868. i++;
  869. } else {
  870. Err = ERROR_NOT_ENOUGH_MEMORY;
  871. goto clean0;
  872. }
  873. }
  874. }
  875. }
  876. *StringArray = Array;
  877. *StringCount = Count;
  878. clean0: ; // nothing to do
  879. } except(EXCEPTION_EXECUTE_HANDLER) {
  880. Err = ERROR_INVALID_PARAMETER;
  881. //
  882. // Access the following variables here so that the compiler will respect our statement
  883. // ordering w.r.t. these values. Otherwise, we can't be sure that the values are accurate
  884. // at the point where the exception occurred.
  885. //
  886. Buffer = Buffer;
  887. Array = Array;
  888. i = i;
  889. }
  890. if(Buffer) {
  891. MyFree(Buffer);
  892. }
  893. if((Err != NO_ERROR) && Array) {
  894. pSetupFreeStringArray(Array, i);
  895. }
  896. return Err;
  897. }
  898. DWORD
  899. SetArrayToMultiSzDevRegProp(
  900. IN DEVINST DevInst,
  901. IN ULONG CmPropertyCode,
  902. IN PTSTR *StringArray,
  903. IN UINT StringCount
  904. )
  905. /*++
  906. Routine Description:
  907. This routine converts a string array into a multi-sz buffer, and
  908. sets the specified device registry property to its contents.
  909. Arguments:
  910. DevInst - supplies the handle to the device instance for which the
  911. registry property is to be set.
  912. CmPropertyCode - specifies the property to be set. This is a
  913. CM_DRP value.
  914. StringArray - supplies the string array to use in creating the
  915. multi-sz buffer.
  916. StringCount - supplies the number of strings in the array.
  917. Return Value:
  918. If successful, the return value is NO_ERROR, otherwise, it is an
  919. ERROR_* code.
  920. --*/
  921. {
  922. UINT i;
  923. UINT Length;
  924. UINT BufferSize;
  925. PTCHAR Buffer;
  926. PTCHAR p;
  927. DWORD d;
  928. CONFIGRET cr;
  929. //
  930. // Calculate the length of the buffer needed to hold the
  931. // multi sz value. Note that empty strings are not allowed.
  932. //
  933. BufferSize = StringCount ? sizeof(TCHAR) : (2 * sizeof(TCHAR));
  934. for(i=0; i<StringCount; i++) {
  935. if(Length = lstrlen(StringArray[i])) {
  936. BufferSize += (Length + 1) * sizeof(TCHAR);
  937. } else {
  938. return(ERROR_INVALID_DATA);
  939. }
  940. }
  941. d = NO_ERROR;
  942. //
  943. // Allocate a buffer to hold the data.
  944. //
  945. if(!(Buffer = MyMalloc(BufferSize))) {
  946. return(ERROR_NOT_ENOUGH_MEMORY);
  947. }
  948. try {
  949. //
  950. // Copy the string data into the buffer, forming a multi sz.
  951. //
  952. p = Buffer;
  953. if(StringCount) {
  954. for(i=0; i<StringCount; i++, p+=Length+1) {
  955. Length = lstrlen(StringArray[i]);
  956. lstrcpy(p, StringArray[i]);
  957. }
  958. } else {
  959. *(p++) = TEXT('\0');
  960. }
  961. *p = TEXT('\0');
  962. if((cr = CM_Set_DevInst_Registry_Property(DevInst,
  963. CmPropertyCode,
  964. Buffer,
  965. BufferSize,
  966. 0)) != CR_SUCCESS) {
  967. d = (cr == CR_INVALID_DEVINST) ? ERROR_NO_SUCH_DEVINST
  968. : ERROR_INVALID_DATA;
  969. }
  970. } except(EXCEPTION_EXECUTE_HANDLER) {
  971. d = ERROR_INVALID_PARAMETER;
  972. }
  973. MyFree(Buffer);
  974. return(d);
  975. }