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.

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