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.

1532 lines
45 KiB

  1. /*************************************************************************
  2. *
  3. * query.c
  4. *
  5. * Query Register APIs
  6. *
  7. * Copyright (c) 1998 Microsoft Corporation
  8. *
  9. *
  10. *************************************************************************/
  11. /*
  12. * Includes
  13. */
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <windows.h>
  21. #include <ntddkbd.h>
  22. #include <ntddmou.h>
  23. #include <winstaw.h>
  24. #include <regapi.h>
  25. /*
  26. * Procedures defined
  27. */
  28. VOID QueryWinStaCreate( HKEY, PWINSTATIONCREATE );
  29. VOID QueryUserConfig( HKEY, PUSERCONFIG, PWINSTATIONNAMEW );
  30. VOID QueryConfig( HKEY, PWINSTATIONCONFIG, PWINSTATIONNAMEW );
  31. VOID QueryNetwork( HKEY, PNETWORKCONFIG );
  32. VOID QueryNasi( HKEY, PNASICONFIG );
  33. VOID QueryAsync( HKEY, PASYNCCONFIG );
  34. VOID QueryOemTd( HKEY, POEMTDCONFIG );
  35. VOID QueryFlow( HKEY, PFLOWCONTROLCONFIG );
  36. VOID QueryConnect( HKEY, PCONNECTCONFIG );
  37. VOID QueryCd( HKEY, PCDCONFIG );
  38. VOID QueryWd( HKEY, PWDCONFIG );
  39. VOID QueryPdConfig( HKEY, PPDCONFIG, PULONG );
  40. VOID QueryPdConfig2( HKEY, PPDCONFIG2, ULONG );
  41. VOID QueryPdConfig3( HKEY, PPDCONFIG3, ULONG );
  42. VOID QueryPdParams( HKEY, SDCLASS, PPDPARAMS );
  43. BOOLEAN WINAPI RegBuildNumberQuery( PULONG );
  44. BOOLEAN RegQueryOEMId( PBYTE, ULONG );
  45. BOOLEAN WINAPI RegGetCitrixVersion(WCHAR *, PULONG);
  46. BOOLEAN IsWallPaperDisabled( HKEY );
  47. BOOLEAN IsCursorBlinkDisabled( HKEY );
  48. /*
  49. * procedures used
  50. */
  51. DWORD GetNumValue( HKEY, LPWSTR, DWORD );
  52. DWORD GetNumValueEx( HKEY, LPWSTR, DWORD, DWORD );
  53. LONG GetStringValue( HKEY, LPWSTR, LPWSTR, LPWSTR, DWORD );
  54. LONG GetStringValueEx( HKEY, LPWSTR, DWORD, LPWSTR, LPWSTR, DWORD );
  55. VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * );
  56. DWORD GetStringFromLSA( LPWSTR, LPWSTR, DWORD );
  57. //
  58. //From gpdata.cpp
  59. //
  60. BOOLEAN
  61. GPGetStringValue( HKEY policyKey,
  62. LPWSTR ValueName,
  63. LPWSTR pValueData,
  64. DWORD MaxValueSize,
  65. BOOLEAN *pbValueExists);
  66. /*******************************************************************************
  67. *
  68. * QueryWinStaCreate
  69. *
  70. * query WINSTATIONCREATE structure
  71. *
  72. * ENTRY:
  73. *
  74. * Handle (input)
  75. * registry handle
  76. * pCreate (output)
  77. * address to return WINSTATIONCREATE structure
  78. *
  79. * EXIT:
  80. * nothing
  81. *
  82. ******************************************************************************/
  83. VOID
  84. QueryWinStaCreate( HKEY Handle,
  85. PWINSTATIONCREATE pCreate )
  86. {
  87. pCreate->fEnableWinStation = (BOOLEAN) GetNumValue( Handle,
  88. WIN_ENABLEWINSTATION,
  89. TRUE );
  90. pCreate->MaxInstanceCount = GetNumValue( Handle,
  91. WIN_MAXINSTANCECOUNT,
  92. 1 );
  93. }
  94. /*******************************************************************************
  95. *
  96. * QueryTSProfileAndHomePaths
  97. *
  98. * query WFProfilePath and WFHomeDir from Machine settings
  99. *
  100. * ENTRY:
  101. *
  102. * pUser (input)
  103. * pointer to USERCONFIG structure
  104. *
  105. * EXIT:
  106. * nothing
  107. *
  108. ******************************************************************************/
  109. VOID QueryTSProfileAndHomePaths(PUSERCONFIG pUser)
  110. {
  111. HKEY hTSControlKey = NULL; //handle to REG_CONTROL_TSERVER key
  112. BOOLEAN bValueExists;
  113. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0, KEY_READ, &hTSControlKey) == ERROR_SUCCESS)
  114. {
  115. if (hTSControlKey )
  116. {
  117. pUser->fErrorInvalidProfile = !GPGetStringValue(hTSControlKey, WIN_WFPROFILEPATH,
  118. pUser->WFProfilePath, DIRECTORY_LENGTH + 1, &bValueExists);
  119. GetStringValue(hTSControlKey, WIN_WFHOMEDIR, NULL, pUser->WFHomeDir, DIRECTORY_LENGTH + 1);
  120. }
  121. if (hTSControlKey)
  122. RegCloseKey(hTSControlKey);
  123. }
  124. }
  125. /*******************************************************************************
  126. *
  127. * QueryUserConfig
  128. *
  129. * query USERCONFIG structure
  130. *
  131. * ENTRY:
  132. *
  133. * Handle (input)
  134. * registry handle
  135. * pUser (input)
  136. * pointer to USERCONFIG structure
  137. * pwszWinStationName (input)
  138. * winstation name (string) that we're querying the user config for
  139. *
  140. * EXIT:
  141. * nothing
  142. *
  143. ******************************************************************************/
  144. VOID
  145. QueryUserConfig( HKEY Handle,
  146. PUSERCONFIG pUser,
  147. PWINSTATIONNAMEW pwszWinStationName )
  148. {
  149. UCHAR seed;
  150. UNICODE_STRING UnicodePassword;
  151. WCHAR encPassword[ PASSWORD_LENGTH + 2 ];
  152. LPWSTR pwszPasswordKeyName = NULL;
  153. DWORD dwKeyNameLength;
  154. // set an empty password
  155. encPassword[0] = (WCHAR) NULL;
  156. pUser->fInheritAutoLogon =
  157. (BOOLEAN) GetNumValue( Handle, WIN_INHERITAUTOLOGON, TRUE );
  158. pUser->fInheritResetBroken =
  159. (BOOLEAN) GetNumValue( Handle, WIN_INHERITRESETBROKEN, TRUE );
  160. pUser->fInheritReconnectSame =
  161. (BOOLEAN) GetNumValue( Handle, WIN_INHERITRECONNECTSAME, TRUE );
  162. pUser->fInheritInitialProgram =
  163. (BOOLEAN) GetNumValue( Handle, WIN_INHERITINITIALPROGRAM, TRUE );
  164. pUser->fInheritCallback =
  165. (BOOLEAN) GetNumValue( Handle, WIN_INHERITCALLBACK, FALSE );
  166. pUser->fInheritCallbackNumber =
  167. (BOOLEAN) GetNumValue( Handle, WIN_INHERITCALLBACKNUMBER, TRUE );
  168. pUser->fInheritShadow =
  169. (BOOLEAN) GetNumValue( Handle, WIN_INHERITSHADOW, TRUE );
  170. pUser->fInheritMaxSessionTime =
  171. (BOOLEAN) GetNumValue( Handle, WIN_INHERITMAXSESSIONTIME, TRUE );
  172. pUser->fInheritMaxDisconnectionTime =
  173. (BOOLEAN) GetNumValue( Handle, WIN_INHERITMAXDISCONNECTIONTIME, TRUE );
  174. pUser->fInheritMaxIdleTime =
  175. (BOOLEAN) GetNumValue( Handle, WIN_INHERITMAXIDLETIME, TRUE );
  176. pUser->fInheritAutoClient =
  177. (BOOLEAN) GetNumValue( Handle, WIN_INHERITAUTOCLIENT, TRUE );
  178. pUser->fInheritSecurity =
  179. (BOOLEAN) GetNumValue( Handle, WIN_INHERITSECURITY, FALSE );
  180. //NA 2/23/01
  181. pUser->fInheritColorDepth =
  182. (BOOLEAN) GetNumValue( Handle, WIN_INHERITCOLORDEPTH, TRUE );
  183. pUser->fPromptForPassword =
  184. (BOOLEAN) GetNumValue( Handle, WIN_PROMPTFORPASSWORD, FALSE );
  185. pUser->fResetBroken =
  186. (BOOLEAN) GetNumValue( Handle, WIN_RESETBROKEN, FALSE );
  187. pUser->fReconnectSame =
  188. (BOOLEAN) GetNumValue( Handle, WIN_RECONNECTSAME, FALSE );
  189. pUser->fLogonDisabled =
  190. (BOOLEAN) GetNumValue( Handle, WIN_LOGONDISABLED, FALSE );
  191. pUser->fAutoClientDrives =
  192. (BOOLEAN) GetNumValue( Handle, WIN_AUTOCLIENTDRIVES, TRUE );
  193. pUser->fAutoClientLpts =
  194. (BOOLEAN) GetNumValue( Handle, WIN_AUTOCLIENTLPTS, TRUE );
  195. pUser->fForceClientLptDef =
  196. (BOOLEAN) GetNumValue( Handle, WIN_FORCECLIENTLPTDEF, TRUE );
  197. pUser->fDisableEncryption =
  198. (BOOLEAN) GetNumValue( Handle, WIN_DISABLEENCRYPTION, TRUE );
  199. pUser->fHomeDirectoryMapRoot =
  200. (BOOLEAN) GetNumValue( Handle, WIN_HOMEDIRECTORYMAPROOT, FALSE );
  201. pUser->fUseDefaultGina =
  202. (BOOLEAN) GetNumValue( Handle, WIN_USEDEFAULTGINA, FALSE );
  203. pUser->fDisableCpm =
  204. (BOOLEAN) GetNumValue( Handle, WIN_DISABLECPM, FALSE );
  205. pUser->fDisableCdm =
  206. (BOOLEAN) GetNumValue( Handle, WIN_DISABLECDM, FALSE );
  207. pUser->fDisableCcm =
  208. (BOOLEAN) GetNumValue( Handle, WIN_DISABLECCM, FALSE );
  209. pUser->fDisableLPT =
  210. (BOOLEAN) GetNumValue( Handle, WIN_DISABLELPT, FALSE );
  211. pUser->fDisableClip =
  212. (BOOLEAN) GetNumValue( Handle, WIN_DISABLECLIP, FALSE );
  213. pUser->fDisableExe =
  214. (BOOLEAN) GetNumValue( Handle, WIN_DISABLEEXE, FALSE );
  215. pUser->fDisableCam =
  216. (BOOLEAN) GetNumValue( Handle, WIN_DISABLECAM, FALSE );
  217. GetStringValue( Handle, WIN_USERNAME, NULL, pUser->UserName,
  218. USERNAME_LENGTH + 1 );
  219. GetStringValue( Handle, WIN_DOMAIN, NULL, pUser->Domain,
  220. DOMAIN_LENGTH + 1 );
  221. //
  222. // pull encrypted password out of LSA and decrypt it
  223. //
  224. // Build key name by appending the Winstation Name to the static KeyName
  225. // A WinStation Name must be passed in to store password
  226. if (pwszWinStationName != NULL)
  227. {
  228. // Build key name by appending the Winstation Name to the static KeyName
  229. dwKeyNameLength = wcslen(LSA_PSWD_KEYNAME) +
  230. wcslen(pwszWinStationName) + 1;
  231. // Allocate heap memory for the password KEY
  232. pwszPasswordKeyName = (LPWSTR)LocalAlloc(LPTR, dwKeyNameLength * sizeof(WCHAR));
  233. // if we failed to allocate memory just skip password querying
  234. if (pwszPasswordKeyName != NULL)
  235. {
  236. wcscpy(pwszPasswordKeyName, LSA_PSWD_KEYNAME);
  237. wcscat(pwszPasswordKeyName, pwszWinStationName);
  238. pwszPasswordKeyName[dwKeyNameLength - 1] = L'\0';
  239. // Get the password from LSA, if it failed, it's ok can mean key
  240. // isn't there and encPassword is set to NULL just continue
  241. GetStringFromLSA(pwszPasswordKeyName,
  242. encPassword,
  243. PASSWORD_LENGTH + 2);
  244. // Free up the password key we allocated above from the heap
  245. LocalFree(pwszPasswordKeyName);
  246. }
  247. }
  248. // check for password if there is one then decrypt it
  249. if ( wcslen( encPassword ) ) {
  250. // generate unicode string
  251. RtlInitUnicodeString( &UnicodePassword, &encPassword[1] );
  252. // decrypt password in place
  253. seed = (UCHAR) encPassword[0];
  254. RtlRunDecodeUnicodeString( seed, &UnicodePassword );
  255. // pull clear text password
  256. RtlMoveMemory( pUser->Password, &encPassword[1], sizeof(pUser->Password) );
  257. }
  258. else {
  259. // set to null
  260. pUser->Password[0] = (WCHAR) NULL;
  261. }
  262. GetStringValue( Handle, WIN_WORKDIRECTORY, NULL, pUser->WorkDirectory,
  263. DIRECTORY_LENGTH + 1 );
  264. GetStringValue( Handle, WIN_INITIALPROGRAM, NULL, pUser->InitialProgram,
  265. INITIALPROGRAM_LENGTH + 1 );
  266. GetStringValue( Handle, WIN_CALLBACKNUMBER, NULL, pUser->CallbackNumber,
  267. CALLBACK_LENGTH + 1 );
  268. pUser->Callback = GetNumValue( Handle, WIN_CALLBACK, Callback_Disable );
  269. pUser->Shadow = GetNumValue( Handle, WIN_SHADOW, Shadow_EnableInputNotify );
  270. pUser->MaxConnectionTime = GetNumValue( Handle, WIN_MAXCONNECTIONTIME, 0 );
  271. pUser->MaxDisconnectionTime = GetNumValue( Handle,
  272. WIN_MAXDISCONNECTIONTIME, 0 );
  273. pUser->MaxIdleTime = GetNumValue( Handle, WIN_MAXIDLETIME, 0 );
  274. pUser->KeyboardLayout = GetNumValue( Handle, WIN_KEYBOARDLAYOUT, 0 );
  275. pUser->MinEncryptionLevel = (BYTE) GetNumValue( Handle, WIN_MINENCRYPTIONLEVEL, 1 );
  276. pUser->fWallPaperDisabled = (BOOLEAN) IsWallPaperDisabled( Handle );
  277. pUser->fCursorBlinkDisabled = IsCursorBlinkDisabled( Handle );
  278. GetStringValue( Handle, WIN_NWLOGONSERVER, NULL, pUser->NWLogonServer,
  279. NASIFILESERVER_LENGTH + 1 );
  280. //These don't exist at this registry level. They are actually two levels
  281. //up at the machine policy level.
  282. //GetStringValue( Handle, WIN_WFPROFILEPATH, NULL, pUser->WFProfilePath,
  283. // DIRECTORY_LENGTH + 1 );
  284. //GetStringValue( Handle, WIN_WFHOMEDIR, NULL, pUser->WFHomeDir,
  285. // DIRECTORY_LENGTH + 1 );
  286. GetStringValue( Handle, WIN_WFHOMEDIRDRIVE, NULL, pUser->WFHomeDirDrive,
  287. 4 );
  288. pUser->ColorDepth = GetNumValue( Handle, POLICY_TS_COLOR_DEPTH, TS_8BPP_SUPPORT );
  289. }
  290. /*******************************************************************************
  291. *
  292. * QueryConfig
  293. *
  294. * query WINSTATIONCONFIG structure
  295. *
  296. * ENTRY:
  297. *
  298. * Handle (input)
  299. * registry handle
  300. * pConfig (output)
  301. * address to return WINSTATIONCONFIG structure
  302. * pWinStationName (input)
  303. * Name of winstation we are querying
  304. *
  305. * EXIT:
  306. * nothing
  307. *
  308. ******************************************************************************/
  309. VOID
  310. QueryConfig( HKEY Handle,
  311. PWINSTATIONCONFIG pConfig,
  312. PWINSTATIONNAMEW pWinStationName )
  313. {
  314. GetStringValue( Handle, WIN_COMMENT, NULL, pConfig->Comment,
  315. WINSTATIONCOMMENT_LENGTH + 1 );
  316. QueryUserConfig( Handle, &pConfig->User, pWinStationName);
  317. (void) RegQueryOEMId( pConfig->OEMId, sizeof(pConfig->OEMId) );
  318. }
  319. /*******************************************************************************
  320. *
  321. * QueryNetwork
  322. *
  323. * Query NETWORKCONFIG structure
  324. *
  325. * ENTRY:
  326. *
  327. * Handle (input)
  328. * registry handle
  329. * pNetwork (output)
  330. * address to return NETWORKCONFIG structure
  331. *
  332. * EXIT:
  333. * nothing
  334. *
  335. ******************************************************************************/
  336. VOID
  337. QueryNetwork( HKEY Handle,
  338. PNETWORKCONFIG pNetwork )
  339. {
  340. pNetwork->LanAdapter = GetNumValue( Handle, WIN_LANADAPTER, 0 );
  341. }
  342. /*******************************************************************************
  343. *
  344. * QueryNasi
  345. *
  346. * Query NASICONFIG structure
  347. *
  348. * ENTRY:
  349. *
  350. * Handle (input)
  351. * registry handle
  352. * pNasi (output)
  353. * address to return NASICONFIG structure
  354. *
  355. * EXIT:
  356. * nothing
  357. *
  358. ******************************************************************************/
  359. VOID
  360. QueryNasi( HKEY Handle,
  361. PNASICONFIG pNasi )
  362. {
  363. UCHAR seed;
  364. UNICODE_STRING UnicodePassword;
  365. WCHAR encPassword[ NASIPASSWORD_LENGTH + 2 ];
  366. // pull encrypted password out of registry
  367. GetStringValue( Handle, WIN_NASIPASSWORD, NULL, encPassword,
  368. NASIPASSWORD_LENGTH + 1 );
  369. // check for password if there is one then decrypt it
  370. if ( wcslen( encPassword ) ) {
  371. // generate unicode string
  372. RtlInitUnicodeString( &UnicodePassword, &encPassword[1] );
  373. // decrypt password in place
  374. seed = (UCHAR) encPassword[0];
  375. RtlRunDecodeUnicodeString( seed, &UnicodePassword );
  376. // pull clear text password
  377. RtlMoveMemory( pNasi->PassWord, &encPassword[1], sizeof(pNasi->PassWord) );
  378. }
  379. else {
  380. // set to null
  381. pNasi->PassWord[0] = (WCHAR) NULL;
  382. }
  383. GetStringValue( Handle, WIN_NASISPECIFICNAME, NULL, pNasi->SpecificName,
  384. NASISPECIFICNAME_LENGTH + 1 );
  385. GetStringValue( Handle, WIN_NASIUSERNAME, NULL, pNasi->UserName,
  386. NASIUSERNAME_LENGTH + 1 );
  387. GetStringValue( Handle, WIN_NASISESSIONNAME, NULL, pNasi->SessionName,
  388. NASISESSIONNAME_LENGTH + 1 );
  389. GetStringValue( Handle, WIN_NASIFILESERVER, NULL, pNasi->FileServer,
  390. NASIFILESERVER_LENGTH + 1 );
  391. pNasi->GlobalSession = (BOOLEAN)GetNumValue( Handle, WIN_NASIGLOBALSESSION, 0 );
  392. }
  393. /*******************************************************************************
  394. *
  395. * QueryAsync
  396. *
  397. * query ASYNCCONFIG structure
  398. *
  399. * ENTRY:
  400. *
  401. * Handle (input)
  402. * registry handle
  403. * pAsync (output)
  404. * address to return ASYNCCONFIG structure
  405. *
  406. * EXIT:
  407. * nothing
  408. *
  409. ******************************************************************************/
  410. VOID
  411. QueryAsync( HKEY Handle,
  412. PASYNCCONFIG pAsync )
  413. {
  414. GetStringValue( Handle, WIN_DEVICENAME, NULL, pAsync->DeviceName,
  415. DEVICENAME_LENGTH + 1 );
  416. GetStringValue( Handle, WIN_MODEMNAME, NULL, pAsync->ModemName,
  417. MODEMNAME_LENGTH + 1 );
  418. pAsync->BaudRate = GetNumValue( Handle, WIN_BAUDRATE, 9600 );
  419. pAsync->Parity = GetNumValue( Handle, WIN_PARITY, NOPARITY );
  420. pAsync->StopBits = GetNumValue( Handle, WIN_STOPBITS, ONESTOPBIT );
  421. pAsync->ByteSize = GetNumValue( Handle, WIN_BYTESIZE, 8 );
  422. pAsync->fEnableDsrSensitivity = (BOOLEAN) GetNumValue( Handle,
  423. WIN_ENABLEDSRSENSITIVITY,
  424. FALSE );
  425. pAsync->fConnectionDriver = (BOOLEAN) GetNumValue( Handle,
  426. WIN_CONNECTIONDRIVER,
  427. FALSE );
  428. QueryFlow( Handle, &pAsync->FlowControl );
  429. QueryConnect( Handle, &pAsync->Connect );
  430. }
  431. /*******************************************************************************
  432. *
  433. * QueryOemTd
  434. *
  435. * Query OEMTDCONFIG structure
  436. *
  437. * ENTRY:
  438. *
  439. * Handle (input)
  440. * registry handle
  441. * pOemTd (output)
  442. * address to return OEMTDCONFIG structure
  443. *
  444. * EXIT:
  445. * nothing
  446. *
  447. ******************************************************************************/
  448. VOID
  449. QueryOemTd( HKEY Handle,
  450. POEMTDCONFIG pOemTd )
  451. {
  452. pOemTd->Adapter = GetNumValue( Handle, WIN_OEMTDADAPTER, 0 );
  453. GetStringValue( Handle, WIN_OEMTDDEVICENAME, NULL, pOemTd->DeviceName,
  454. DEVICENAME_LENGTH + 1 );
  455. pOemTd->Flags = GetNumValue( Handle, WIN_OEMTDFLAGS, 0 );
  456. }
  457. /*******************************************************************************
  458. *
  459. * QueryFlow
  460. *
  461. * query FLOWCONTROLCONFIG structure
  462. *
  463. * ENTRY:
  464. *
  465. * Handle (input)
  466. * registry handle
  467. * pFlow (output)
  468. * address to return FLOWCONTROLCONFIG structure
  469. *
  470. * EXIT:
  471. * nothing
  472. *
  473. ******************************************************************************/
  474. VOID
  475. QueryFlow( HKEY Handle,
  476. PFLOWCONTROLCONFIG pFlow )
  477. {
  478. pFlow->fEnableSoftwareRx = (BOOLEAN) GetNumValue( Handle,
  479. WIN_FLOWSOFTWARERX,
  480. FALSE );
  481. pFlow->fEnableSoftwareTx = (BOOLEAN) GetNumValue( Handle,
  482. WIN_FLOWSOFTWARETX,
  483. TRUE );
  484. pFlow->fEnableDTR = (BOOLEAN) GetNumValue( Handle, WIN_ENABLEDTR, TRUE );
  485. pFlow->fEnableRTS = (BOOLEAN) GetNumValue( Handle, WIN_ENABLERTS, TRUE );
  486. pFlow->XonChar = (UCHAR) GetNumValue( Handle, WIN_XONCHAR, 0 );
  487. pFlow->XoffChar = (UCHAR) GetNumValue( Handle, WIN_XOFFCHAR, 0 );
  488. pFlow->Type = GetNumValue( Handle, WIN_FLOWTYPE, FlowControl_Hardware );
  489. pFlow->HardwareReceive = GetNumValue( Handle, WIN_FLOWHARDWARERX,
  490. ReceiveFlowControl_RTS );
  491. pFlow->HardwareTransmit = GetNumValue( Handle, WIN_FLOWHARDWARETX,
  492. TransmitFlowControl_CTS );
  493. }
  494. /*******************************************************************************
  495. *
  496. * QueryConnect
  497. *
  498. * query CONNECTCONFIG structure
  499. *
  500. * ENTRY:
  501. *
  502. * Handle (input)
  503. * registry handle
  504. * pConnect (output)
  505. * address to return CONNECTCONFIG structure
  506. *
  507. * EXIT:
  508. * nothing
  509. *
  510. ******************************************************************************/
  511. VOID
  512. QueryConnect( HKEY Handle,
  513. PCONNECTCONFIG pConnect )
  514. {
  515. pConnect->Type = GetNumValue( Handle, WIN_CONNECTTYPE, Connect_DSR );
  516. pConnect->fEnableBreakDisconnect = (BOOLEAN) GetNumValue( Handle,
  517. WIN_ENABLEBREAKDISCONNECT,
  518. FALSE );
  519. }
  520. /*******************************************************************************
  521. *
  522. * QueryCd
  523. *
  524. * query CDCONFIG structure
  525. *
  526. * ENTRY:
  527. *
  528. * Handle (input)
  529. * registry handle
  530. * pCdConfig (output)
  531. * address to return CDCONFIG structure
  532. *
  533. * EXIT:
  534. * nothing
  535. *
  536. ******************************************************************************/
  537. VOID
  538. QueryCd( HKEY Handle,
  539. PCDCONFIG pCdConfig )
  540. {
  541. pCdConfig->CdClass = GetNumValue( Handle, WIN_CDCLASS, CdNone );
  542. GetStringValue( Handle, WIN_CDNAME, NULL, pCdConfig->CdName,
  543. CDNAME_LENGTH + 1 );
  544. GetStringValue( Handle, WIN_CDDLL, L"", pCdConfig->CdDLL,
  545. DLLNAME_LENGTH + 1 );
  546. pCdConfig->CdFlag = GetNumValue( Handle, WIN_CDFLAG, 0 );
  547. }
  548. /*******************************************************************************
  549. *
  550. * QueryWd
  551. *
  552. * query WDCONFIG structure
  553. *
  554. * ENTRY:
  555. *
  556. * Handle (input)
  557. * registry handle
  558. * pWd (output)
  559. * address to return WDCONFIG structure
  560. *
  561. * EXIT:
  562. * nothing
  563. *
  564. ******************************************************************************/
  565. VOID
  566. QueryWd( HKEY Handle,
  567. PWDCONFIG pWd )
  568. {
  569. GetStringValue( Handle, WIN_WDNAME, NULL, pWd->WdName, WDNAME_LENGTH + 1 );
  570. GetStringValue( Handle, WIN_WDDLL, L"", pWd->WdDLL, DLLNAME_LENGTH + 1 );
  571. GetStringValue( Handle, WIN_WSXDLL, NULL, pWd->WsxDLL, DLLNAME_LENGTH + 1 );
  572. pWd->WdFlag = GetNumValue( Handle, WIN_WDFLAG, 0 );
  573. pWd->WdInputBufferLength = GetNumValue( Handle, WIN_INPUTBUFFERLENGTH, 2048 );
  574. GetStringValue( Handle, WIN_CFGDLL, NULL, pWd->CfgDLL, DLLNAME_LENGTH + 1 );
  575. GetStringValue( Handle, WIN_WDPREFIX, NULL, pWd->WdPrefix, WDPREFIX_LENGTH + 1 );
  576. }
  577. /*******************************************************************************
  578. *
  579. * QueryPdConfig
  580. *
  581. * query PDCONFIG structure
  582. *
  583. * ENTRY:
  584. *
  585. * Handle (input)
  586. * registry handle
  587. * pConfig (output)
  588. * address to return array of PDCONFIG structures
  589. * pCount (input/output)
  590. * pointer to number of PDCONFIG array elements
  591. *
  592. * EXIT:
  593. * nothing
  594. *
  595. ******************************************************************************/
  596. VOID
  597. QueryPdConfig( HKEY Handle,
  598. PPDCONFIG pConfig,
  599. PULONG pCount )
  600. {
  601. ULONG i;
  602. for ( i=0; i < *pCount; i++ ) {
  603. QueryPdConfig2( Handle, &pConfig[i].Create, i );
  604. QueryPdParams( Handle,
  605. pConfig[i].Create.SdClass,
  606. &pConfig[i].Params );
  607. }
  608. *pCount = MAX_PDCONFIG;
  609. }
  610. /*******************************************************************************
  611. *
  612. * QueryPdConfig2
  613. *
  614. * query PDCONFIG2 structure
  615. *
  616. * ENTRY:
  617. *
  618. * Handle (input)
  619. * registry handle
  620. * pPd2 (output)
  621. * address to return PDCONFIG2 structure
  622. * Index (input)
  623. * Index (array index)
  624. *
  625. * EXIT:
  626. * nothing
  627. *
  628. ******************************************************************************/
  629. VOID
  630. QueryPdConfig2( HKEY Handle,
  631. PPDCONFIG2 pPd2,
  632. ULONG Index )
  633. {
  634. GetStringValueEx( Handle, WIN_PDNAME, Index,
  635. NULL, pPd2->PdName, PDNAME_LENGTH + 1 );
  636. pPd2->SdClass = GetNumValueEx( Handle, WIN_PDCLASS, Index, Index==0 ? SdAsync : SdNone );
  637. GetStringValueEx( Handle, WIN_PDDLL, Index,
  638. NULL, pPd2->PdDLL, DLLNAME_LENGTH + 1 );
  639. pPd2->PdFlag = GetNumValueEx( Handle, WIN_PDFLAG, Index, 0 );
  640. /*
  641. * The following data is the same for all pds
  642. */
  643. pPd2->OutBufLength = GetNumValue( Handle, WIN_OUTBUFLENGTH, 530 );
  644. pPd2->OutBufCount = GetNumValue( Handle, WIN_OUTBUFCOUNT, 10 );
  645. pPd2->OutBufDelay = GetNumValue( Handle, WIN_OUTBUFDELAY, 100 );
  646. pPd2->InteractiveDelay = GetNumValue( Handle, WIN_INTERACTIVEDELAY, 10 );
  647. pPd2->KeepAliveTimeout = GetNumValue( Handle, WIN_KEEPALIVETIMEOUT, 0 );
  648. pPd2->PortNumber = GetNumValue( Handle, WIN_PORTNUMBER, 0 );
  649. }
  650. /*******************************************************************************
  651. *
  652. * QueryPdConfig3
  653. *
  654. * query PDCONFIG3 structure
  655. *
  656. * ENTRY:
  657. *
  658. * Handle (input)
  659. * registry handle
  660. * pPd (output)
  661. * address to return PDCONFIG3 structure
  662. * Index (input)
  663. * Index (array index)
  664. *
  665. * EXIT:
  666. * nothing
  667. *
  668. ******************************************************************************/
  669. VOID
  670. QueryPdConfig3( HKEY Handle,
  671. PPDCONFIG3 pPd3,
  672. ULONG Index )
  673. {
  674. int i;
  675. ULONG Length;
  676. LPWSTR tmp;
  677. WCHAR PdName[ MAX_PDCONFIG * ( PDNAME_LENGTH + 1 ) + 1 ];
  678. ULONG ValueType;
  679. QueryPdConfig2( Handle, &pPd3->Data, Index );
  680. GetStringValue( Handle, WIN_SERVICENAME, NULL,
  681. pPd3->ServiceName,
  682. PDNAME_LENGTH + 1 );
  683. GetStringValue( Handle, WIN_CONFIGDLL, NULL,
  684. pPd3->ConfigDLL,
  685. DLLNAME_LENGTH + 1 );
  686. Length = sizeof(PdName);
  687. pPd3->RequiredPdCount = 0;
  688. if ( RegQueryValueEx( Handle, WIN_REQUIREDPDS, NULL, &ValueType,
  689. (LPBYTE)PdName, &Length ) == ERROR_SUCCESS ) {
  690. tmp = PdName;
  691. i = 0;
  692. while ( *tmp != UNICODE_NULL ) {
  693. pPd3->RequiredPdCount++;
  694. wcscpy( pPd3->RequiredPds[i], tmp );
  695. i++;
  696. tmp += wcslen(tmp) + 1;
  697. }
  698. }
  699. }
  700. /*******************************************************************************
  701. *
  702. * QueryPdParams
  703. *
  704. * query PDPARAMS structure
  705. *
  706. * ENTRY:
  707. *
  708. * Handle (input)
  709. * registry handle
  710. * SdClass (input)
  711. * type of PD
  712. * pParams (output)
  713. * address to return PDPARAMS structure
  714. *
  715. * EXIT:
  716. * nothing
  717. *
  718. ******************************************************************************/
  719. VOID
  720. QueryPdParams( HKEY Handle,
  721. SDCLASS SdClass,
  722. PPDPARAMS pParams )
  723. {
  724. pParams->SdClass = SdClass;
  725. switch ( SdClass ) {
  726. case SdNetwork :
  727. QueryNetwork( Handle, &pParams->Network );
  728. break;
  729. case SdNasi :
  730. QueryNasi( Handle, &pParams->Nasi );
  731. break;
  732. case SdAsync :
  733. QueryAsync( Handle, &pParams->Async );
  734. break;
  735. case SdOemTransport :
  736. QueryOemTd( Handle, &pParams->OemTd );
  737. break;
  738. }
  739. }
  740. #define CONTROL_PANEL L"Control Panel"
  741. #define DESKTOP L"Desktop"
  742. #define WALLPAPER L"Wallpaper"
  743. #define STRNONE L"(None)"
  744. #define CURSORBLINK L"DisableCursorBlink"
  745. /*******************************************************************************
  746. *
  747. * IsWallPaperDisabled
  748. *
  749. * Is the wall paper disabled?
  750. *
  751. * ENTRY:
  752. * Handle (input)
  753. * registry handle
  754. * EXIT:
  755. * TRUE or FALSE (returns FALSE as default)
  756. *
  757. ******************************************************************************/
  758. BOOLEAN IsWallPaperDisabled( HKEY Handle )
  759. {
  760. HKEY Handle1;
  761. WCHAR KeyString[256];
  762. WCHAR KeyValue[256];
  763. DWORD KeyValueSize = sizeof(KeyValue);
  764. DWORD KeyValueType;
  765. DWORD Status;
  766. wcscpy( KeyString, WIN_USEROVERRIDE );
  767. wcscat( KeyString, L"\\" );
  768. wcscat( KeyString, CONTROL_PANEL );
  769. wcscat( KeyString, L"\\" );
  770. wcscat( KeyString, DESKTOP );
  771. if ( RegOpenKeyEx( Handle, KeyString, 0, KEY_READ,
  772. &Handle1 ) != ERROR_SUCCESS )
  773. return FALSE;
  774. //
  775. // TS setup/REGAPI set WALLPAPER to NULL value or STRNONE to indicate
  776. // wallpaper is disabled and non-existance WALLPAPER to indicate
  777. // wallpaper is enabled; however, GetStringValue() treat NULL value
  778. // same as non-existance reg. value so we can't use GetStringValue().
  779. //
  780. ZeroMemory( KeyValue, KeyValueSize );
  781. Status = RegQueryValueEx( Handle1, WALLPAPER, NULL, &KeyValueType,
  782. (LPBYTE) KeyValue, &KeyValueSize );
  783. RegCloseKey( Handle1 );
  784. if( ERROR_SUCCESS == Status && REG_SZ == KeyValueType ) {
  785. //
  786. // Valid value for WallPaper disable:
  787. // 1) TS setup sets WALLPAPER value to NULL value
  788. // 2) CreateUserConfig() sets WALLPAPER to STRNONE
  789. //
  790. if( KeyValueSize == sizeof(UNICODE_NULL) ||
  791. _wcsicmp( STRNONE, KeyValue ) == 0 ) {
  792. return TRUE;
  793. }
  794. }
  795. return FALSE;
  796. }
  797. /*******************************************************************************
  798. *
  799. * IsCursorBlinkDisabled
  800. *
  801. * Is the cursor blink disabled?
  802. *
  803. * ENTRY:
  804. * Handle (input)
  805. * registry handle
  806. * EXIT:
  807. * TRUE or FALSE (returns TRUE as default)
  808. *
  809. ******************************************************************************/
  810. BOOLEAN IsCursorBlinkDisabled( HKEY Handle )
  811. {
  812. HKEY Handle1;
  813. WCHAR KeyString[256];
  814. BOOLEAN ret;
  815. wcscpy( KeyString, WIN_USEROVERRIDE );
  816. wcscat( KeyString, L"\\" );
  817. wcscat( KeyString, CONTROL_PANEL );
  818. wcscat( KeyString, L"\\" );
  819. wcscat( KeyString, DESKTOP );
  820. if ( RegOpenKeyEx( Handle, KeyString, 0, KEY_READ,
  821. &Handle1 ) != ERROR_SUCCESS )
  822. return FALSE;
  823. ret = (BOOLEAN) GetNumValue( Handle1, CURSORBLINK, 0 );
  824. RegCloseKey( Handle1 );
  825. return ret;
  826. }
  827. /*****************************************************************************
  828. *
  829. * RegBuildNumberQuery
  830. *
  831. * Query the current build number from the registry.
  832. *
  833. * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\Current Version\
  834. * CurrentBuildNumber:REG_SZ:129
  835. *
  836. * ENTRY:
  837. * Param1 (input/output)
  838. * Comments
  839. *
  840. * EXIT:
  841. * STATUS_SUCCESS - no error
  842. *
  843. ****************************************************************************/
  844. BOOLEAN WINAPI
  845. RegBuildNumberQuery(
  846. PULONG pBuildNum
  847. )
  848. {
  849. ULONG Result, Value;
  850. HKEY hKey;
  851. WCHAR Buf[256];
  852. Result = RegOpenKeyEx(
  853. HKEY_LOCAL_MACHINE,
  854. BUILD_NUMBER_KEY,
  855. 0, // Reserved
  856. KEY_READ,
  857. &hKey
  858. );
  859. if( Result != ERROR_SUCCESS ) {
  860. #if DBG
  861. DbgPrint("RegBuildNumberQuery: Failed to open key %ws\n",BUILD_NUMBER_KEY);
  862. #endif
  863. return( FALSE );
  864. }
  865. Result = GetStringValue(
  866. hKey,
  867. BUILD_NUMBER_VALUE,
  868. L"0",
  869. Buf,
  870. sizeof(Buf)
  871. );
  872. if( Result != ERROR_SUCCESS ) {
  873. #if DBG
  874. DbgPrint("RegBuildNumberQuery: Failed to query value %ws\n",BUILD_NUMBER_VALUE);
  875. #endif
  876. RegCloseKey( hKey );
  877. return( FALSE );
  878. }
  879. RegCloseKey( hKey );
  880. //
  881. // Now must convert it into a number
  882. //
  883. Value = 0;
  884. swscanf( Buf, L"%d", &Value );
  885. *pBuildNum = Value;
  886. return( TRUE );
  887. }
  888. /*******************************************************************************
  889. *
  890. * RegQueryOEMId
  891. *
  892. * query oem id
  893. *
  894. * ENTRY:
  895. *
  896. * pOEMId (output)
  897. * pointer to buffer to return oem id
  898. * Length (input)
  899. * length of buffer
  900. *
  901. * EXIT:
  902. *
  903. * TRUE -- The operation succeeded.
  904. *
  905. * FALSE -- The operation failed. Extended error status is available
  906. * using GetLastError.
  907. *
  908. ******************************************************************************/
  909. BOOLEAN
  910. RegQueryOEMId( PBYTE pOEMId, ULONG Length )
  911. {
  912. HKEY Handle2;
  913. WCHAR OEMIdW[10];
  914. /*
  915. * Open registry (LOCAL_MACHINE\....\Terminal Server)
  916. */
  917. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0,
  918. KEY_READ, &Handle2 ) == ERROR_SUCCESS ) {
  919. GetStringValue( Handle2, REG_CITRIX_OEMID, NULL, OEMIdW, 10 );
  920. UnicodeToAnsi( pOEMId, Length, OEMIdW );
  921. pOEMId[3] = '\0';
  922. RegCloseKey( Handle2 );
  923. }
  924. return( TRUE );
  925. }
  926. /*******************************************************************************
  927. *
  928. * RegGetTServerVersion (UNICODE)
  929. *
  930. * Get the Terminal Server version number from the specified server.
  931. *
  932. * This version number is changed by Microsoft, and not OEM's.
  933. *
  934. * ENTRY:
  935. * pServerName (input)
  936. * Points to string of server to check.
  937. *
  938. * EXIT:
  939. * TRUE if Hydra Terminal Server; FALSE otherwise
  940. *
  941. ******************************************************************************/
  942. BOOLEAN WINAPI
  943. RegGetTServerVersion(
  944. WCHAR * pServerName,
  945. PULONG pVersionNumber
  946. )
  947. {
  948. LONG Error;
  949. HKEY ServerHandle, UserHandle;
  950. ULONG Value;
  951. /*
  952. * Connect to registry of specified server.
  953. */
  954. if ( (Error = RegConnectRegistry( pServerName,
  955. HKEY_LOCAL_MACHINE,
  956. &ServerHandle )) != ERROR_SUCCESS )
  957. return( FALSE );
  958. /*
  959. * Open the Terminal Server key and get the Version value.
  960. */
  961. if ( (Error = RegOpenKeyEx( ServerHandle, REG_CONTROL_TSERVER, 0,
  962. KEY_READ, &UserHandle )) != ERROR_SUCCESS ) {
  963. RegCloseKey( ServerHandle );
  964. return( FALSE );
  965. }
  966. Value = GetNumValue(
  967. UserHandle,
  968. REG_CITRIX_VERSION,
  969. 0 );
  970. /*
  971. * Close registry handles.
  972. */
  973. RegCloseKey( UserHandle );
  974. RegCloseKey( ServerHandle );
  975. *pVersionNumber = Value;
  976. return( TRUE );
  977. }
  978. /*******************************************************************************
  979. *
  980. * RegQueryUtilityCommandList (UNICODE)
  981. *
  982. * Allocate and build an array of PROGRAMCALL structures for the specified
  983. * MultiUser utility.
  984. *
  985. * ENTRY:
  986. * pUtilityKey (input)
  987. * Points to string containing the utility's command registry key.
  988. * ppProgramCall (output)
  989. * Points to a PPROGRAMCALL variable that will be set to the API-allocated
  990. * array of PROGRAMCALL structures, containing n elements, where n =
  991. * number of commands supported by the utility (as specified in the
  992. * registry). The pFirst item of array element 0 will point to the
  993. * first command (sorted alphabetically by command name). The pNext items
  994. * are then used to walk the list, till pNext is NULL.
  995. *
  996. * EXIT:
  997. * ERROR_SUCCESS if all goes well;
  998. * An error code is returned if failure.
  999. *
  1000. * If success, the caller must call RegFreeUtilityCommandList with the
  1001. * ppProgramCall variable to free the PROGRAMCALL structure array when
  1002. * finished using the array.
  1003. *
  1004. * The format of the REG_MULTI_SZ command item in the registry is as follows:
  1005. *
  1006. * string 1: "0" or "1" (required)
  1007. *
  1008. * 0 specifies that the command is a normal command which will
  1009. * be presented as an option by the utility USAGE help. 1
  1010. * indicates a command alias (hidden option), which won't
  1011. * appear in USAGE help.
  1012. *
  1013. * string 2: "number" (required)
  1014. *
  1015. * Specifies the minimum number of characters that must be
  1016. * typed for the command to be recognized (base 10).
  1017. *
  1018. * string 3: "command" (required)
  1019. *
  1020. * This is the actual command that will be recognized and
  1021. * displayed in the USAGE help (if not an aliased command).
  1022. *
  1023. * string 4: "program" (required)
  1024. *
  1025. * The file name of the program that will be executed. This
  1026. * should be a standard name.extension filename, and can
  1027. * include a full path, although this is not necessary since
  1028. * the utilities will normally reside in the standard SYSTEM32
  1029. * directory, which is a part of the standard PATH.
  1030. *
  1031. * string 5: "extra args" (optional)
  1032. *
  1033. * If specified, this string will be passed along to the
  1034. * utilsub.lib ExecProgram API to specify additional
  1035. * hard-coded arguments that will be used, in addition to any
  1036. * other arguments that were specified by the user on the
  1037. * command line.
  1038. *
  1039. * Note: If the command item is not a REG_MULTI_SZ value, or the command item
  1040. * is a REG_MULTI_SZ item but there is an error in its format, that
  1041. * command will be omitted from the command list. The return value
  1042. * from this function will still be ERROR_SUCCESS, but the command in
  1043. * error will be ignored by the utilities.
  1044. *
  1045. ******************************************************************************/
  1046. LONG WINAPI
  1047. RegQueryUtilityCommandList(
  1048. LPWSTR pUtilityKey,
  1049. PPROGRAMCALL * ppProgramCall
  1050. )
  1051. {
  1052. HKEY Handle = NULL;
  1053. LONG status = ERROR_SUCCESS;
  1054. DWORD iValue, cValues, ccValueName, cbValueData,
  1055. ccTmpValueName, cbTmpValueData, dwType;
  1056. LPWSTR pValueName = NULL, pValueData = NULL, pString;
  1057. PPROGRAMCALL pProg = NULL, pProgNext, pProgPrev;
  1058. ULONG ulCommandLen;
  1059. PWCHAR pEndptr;
  1060. int iCompare;
  1061. *ppProgramCall = NULL;
  1062. /*
  1063. * Open specified utility key and determine number of values and maximum
  1064. * value name and data length.
  1065. */
  1066. if ( status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1067. pUtilityKey,
  1068. 0,
  1069. KEY_READ,
  1070. &Handle ) != ERROR_SUCCESS ) {
  1071. #if DBG
  1072. DbgPrint("RegQueryUtilityCommandList: Can't open command list utility key %ws; error = %d\n", pUtilityKey, status);
  1073. #endif
  1074. goto error;
  1075. }
  1076. if ( status = RegQueryInfoKey( Handle,
  1077. NULL, // lpClass
  1078. NULL, // lpcbClass
  1079. NULL, // lpReserved
  1080. NULL, // lpcSubKeys
  1081. NULL, // lpcbMaxSubKeyLen
  1082. NULL, // lpcbMaxClassLen
  1083. &cValues, // lpcValues
  1084. &ccValueName, // lpcbMaxValueNameLen
  1085. &cbValueData, // lpcbMaxValueLen
  1086. NULL, // lpcbSecurityDescriptor
  1087. NULL // lpftLastWriteTime
  1088. ) != ERROR_SUCCESS ) {
  1089. #if DBG
  1090. DbgPrint("RegQueryUtilityCommandList: Can't query info for utility %ws; error = %d\n", pUtilityKey, status);
  1091. #endif
  1092. goto error;
  1093. }
  1094. /*
  1095. * Allocate space for #values + 1 PROGRAMCALL elements and value name and
  1096. * data buffers.
  1097. */
  1098. if ( ((*ppProgramCall = (PPROGRAMCALL)LocalAlloc( LPTR, (sizeof(PROGRAMCALL) * (cValues+1)) )) == NULL) ||
  1099. ((pValueName = (LPWSTR)LocalAlloc( LPTR, (int)(++ccValueName * sizeof(WCHAR)) )) == NULL) ||
  1100. ((pValueData = (LPWSTR)LocalAlloc( LPTR, (int)cbValueData )) == NULL) ) {
  1101. status = GetLastError();
  1102. #if DBG
  1103. DbgPrint("RegQueryUtilityCommandList: Can't allocate memory buffer(s) for utility %ws; error = %d\n", pUtilityKey, status);
  1104. #endif
  1105. goto error;
  1106. }
  1107. /*
  1108. * Enumerate and parse each value into the PROGRAMCALL components.
  1109. */
  1110. for ( iValue = 0, pProg = *ppProgramCall;
  1111. iValue < cValues;
  1112. iValue++, pProg++ ) {
  1113. ccTmpValueName = ccValueName;
  1114. cbTmpValueData = cbValueData;
  1115. if ( (status = RegEnumValue( Handle,
  1116. iValue,
  1117. pValueName,
  1118. &ccTmpValueName,
  1119. NULL,
  1120. &dwType,
  1121. (LPBYTE)pValueData,
  1122. &cbTmpValueData )) != ERROR_SUCCESS ) {
  1123. #if DBG
  1124. DbgPrint("RegQueryUtilityCommandList: Can't enumerate command (index = %d) for utility %ws; error = %d\n", iValue, pUtilityKey, status);
  1125. #endif
  1126. goto error;
  1127. }
  1128. /*
  1129. * If the data is not REG_MULTI_SZ, ignore it.
  1130. */
  1131. if ( dwType != REG_MULTI_SZ )
  1132. goto CommandInError;
  1133. /*
  1134. * Allocate data storage for this command, then parse and assign
  1135. * to the PROGRAMCALL structure items.
  1136. */
  1137. if ( (pProg->pRegistryMultiString = LocalAlloc(LPTR, cbTmpValueData)) == NULL ) {
  1138. status = GetLastError();
  1139. #if DBG
  1140. DbgPrint("RegQueryUtilityCommandList: Can't allocate memory buffer for utility %ws; error = %d\n", pUtilityKey, status);
  1141. #endif
  1142. goto error;
  1143. }
  1144. memcpy(pProg->pRegistryMultiString, pValueData, cbTmpValueData);
  1145. pString = pProg->pRegistryMultiString;
  1146. /*
  1147. * Parse alias flag.
  1148. */
  1149. if ( !wcscmp(pString, L"1") )
  1150. pProg->fAlias = TRUE;
  1151. else if ( !wcscmp(pString, L"0") )
  1152. pProg->fAlias = FALSE;
  1153. else
  1154. goto CommandInError;
  1155. pString += (wcslen(pString) + 1);
  1156. /*
  1157. * Parse command length.
  1158. */
  1159. if ( *pString == L'\0' )
  1160. goto CommandInError;
  1161. ulCommandLen = wcstoul(pString, &pEndptr, 10);
  1162. if ( *pEndptr != L'\0' )
  1163. goto CommandInError;
  1164. pProg->CommandLen = (USHORT)ulCommandLen;
  1165. pString += (wcslen(pString) + 1);
  1166. /*
  1167. * Parse command string.
  1168. */
  1169. if ( *pString == L'\0' )
  1170. goto CommandInError;
  1171. pProg->Command = pString;
  1172. pString += (wcslen(pString) + 1);
  1173. /*
  1174. * Parse program string.
  1175. */
  1176. if ( *pString == L'\0' )
  1177. goto CommandInError;
  1178. pProg->Program = pString;
  1179. pString += (wcslen(pString) + 1);
  1180. /*
  1181. * Parse (optional) Args string.
  1182. */
  1183. if ( *pString != L'\0' )
  1184. pProg->Args = pString;
  1185. /*
  1186. * Walk the command list to link this item in it's proper
  1187. * sorted place.
  1188. */
  1189. if ( pProg == *ppProgramCall ) {
  1190. pProg->pFirst = pProg; // first item in the list
  1191. } else for ( pProgPrev = pProgNext = (*ppProgramCall)->pFirst; ; ) {
  1192. if ( (iCompare = _wcsicmp(pProg->Command, pProgNext->Command)) < 0 ) {
  1193. pProg->pNext = pProgNext; // point to next
  1194. if ( pProgNext == (*ppProgramCall)->pFirst )
  1195. (*ppProgramCall)->pFirst = pProg; // first item
  1196. else
  1197. pProgPrev->pNext = pProg; // link after previous
  1198. break;
  1199. } else if ( iCompare == 0 ) {
  1200. goto CommandInError; // duplicate command - ignore
  1201. }
  1202. if ( pProgNext->pNext == NULL ) {
  1203. pProgNext->pNext = pProg; // link at end of list
  1204. break;
  1205. } else {
  1206. pProgPrev = pProgNext;
  1207. pProgNext = pProgNext->pNext;
  1208. }
  1209. }
  1210. continue;
  1211. CommandInError:
  1212. /*
  1213. * The command format is in error - ignore it.
  1214. */
  1215. if ( pProg->pRegistryMultiString )
  1216. LocalFree(pProg->pRegistryMultiString);
  1217. memset(pProg, 0, sizeof(PROGRAMCALL));
  1218. pProg--;
  1219. }
  1220. error:
  1221. if ( Handle != NULL )
  1222. RegCloseKey(Handle);
  1223. if ( pValueName )
  1224. LocalFree(pValueName);
  1225. if ( pValueData )
  1226. LocalFree(pValueData);
  1227. if ( status != ERROR_SUCCESS ) {
  1228. if ( *ppProgramCall ) {
  1229. RegFreeUtilityCommandList(*ppProgramCall);
  1230. *ppProgramCall = NULL;
  1231. }
  1232. }
  1233. return( status );
  1234. }
  1235. /*******************************************************************************
  1236. *
  1237. * RegFreeUtilityCommandList (UNICODE)
  1238. *
  1239. * Free the specified array of PROGRAMCALL structures.
  1240. *
  1241. * ENTRY:
  1242. * pProgramCall (input)
  1243. * Points PROGRAMCALL array to free.
  1244. *
  1245. * EXIT:
  1246. * ERROR_SUCCESS if all goes well; error code if failure
  1247. *
  1248. ******************************************************************************/
  1249. LONG WINAPI
  1250. RegFreeUtilityCommandList(
  1251. PPROGRAMCALL pProgramCall
  1252. )
  1253. {
  1254. PPROGRAMCALL pProg;
  1255. LONG status = ERROR_SUCCESS;
  1256. if ( pProgramCall ) {
  1257. for ( pProg = pProgramCall->pFirst; pProg != NULL; pProg = pProg->pNext ) {
  1258. if ( LocalFree( pProg->pRegistryMultiString ) != NULL ) {
  1259. status = GetLastError();
  1260. #if DBG
  1261. DbgPrint("RegFreeUtilityCommandList: Failed to free command list element for %ws; error = %d\n", pProg->Program, status);
  1262. #endif
  1263. }
  1264. }
  1265. if ( LocalFree( pProgramCall ) != NULL ) {
  1266. status = GetLastError();
  1267. #if DBG
  1268. DbgPrint("RegFreeUtilityCommandList: Failed to free command list array; error = %d\n", status);
  1269. #endif
  1270. }
  1271. }
  1272. return( status );
  1273. }