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.

975 lines
31 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996.
  5. //
  6. // File: P R O V I D E R . C P P
  7. //
  8. // Contents: Net component installer functions for Net providers.
  9. //
  10. // Notes:
  11. //
  12. // Author: billbe 22 Mar 1997
  13. //
  14. //---------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "ncreg.h"
  18. #include "ncsetup.h"
  19. #include "ncsvc.h"
  20. #include "provider.h"
  21. #include "winspool.h"
  22. #include "ncmisc.h"
  23. // constants
  24. //
  25. extern const WCHAR c_szDevice[];
  26. extern const WCHAR c_szProviderOrder[];
  27. extern const WCHAR c_szRegKeyCtlNPOrder[];
  28. extern const WCHAR c_szRegKeyServices[];
  29. const WCHAR c_chComma = L',';
  30. const WCHAR c_szDeviceName[] = L"DeviceName";
  31. const WCHAR c_szDisplayName[] = L"DisplayName";
  32. const WCHAR c_szInfKeyPrintProviderDll[] = L"PrintProviderDll";
  33. const WCHAR c_szInfSubKeyPrintProvider[] = L"PrintProvider";
  34. const WCHAR c_szNetworkProvider[] = L"NetworkProvider";
  35. const WCHAR c_szPrintProviderName[] = L"PrintProviderName";
  36. const WCHAR c_szRegKeyPrintProviders[] = L"System\\CurrentControlSet\\Control\\Print\\Providers";
  37. const WCHAR c_szRegKeyShortName[] = L"System\\CurrentControlSet\\Control\\NetworkProvider\\ShortName";
  38. const WCHAR c_szRegValueName[] = L"Name";
  39. const WCHAR c_szRegValueOrder[] = L"Order";
  40. const WCHAR c_szShortName[] = L"ShortName";
  41. // Functions
  42. //
  43. HRESULT
  44. HrCiCreateShortNameValueIfNeeded(HINF hinf, HKEY hkeyNetworkProvider,
  45. const tstring& strSection,
  46. tstring* pstrShortName);
  47. HRESULT
  48. HrCiSetDeviceName(HINF hinf, HKEY hkeyNetworkProvider,
  49. const tstring& strSection, const tstring& strServiceName);
  50. HRESULT
  51. HrCiWritePrintProviderInfoIfNeeded(HINF hinfFile, const tstring& strSection,
  52. HKEY hkeyInstance, DWORD dwPrintPosition);
  53. HRESULT
  54. HrCiAddPrintProvider(const tstring& strName, const tstring& strDllName,
  55. const tstring& strDisplayName, DWORD dwPrintPosition);
  56. HRESULT
  57. HrCiDeletePrintProviderIfNeeded(HKEY hkeyInstance, DWORD* pdwProviderPosition);
  58. //+--------------------------------------------------------------------------
  59. //
  60. // Function: HrCiAddNetProviderInfo
  61. //
  62. // Purpose: Adds the current component to the list of network
  63. // providers and also adds it as a print provider if
  64. // necessary.
  65. //
  66. // Arguments:
  67. // hinf [in] Handle to component's inf file
  68. // strSection [in] Main inf section
  69. // hkeyInstance [in] Component's instance key
  70. // fPreviouslyInstalled [in] TRUE if this component is being
  71. // reinstalled, FALSE otherwise
  72. //
  73. // Returns: HRESULT. S_OK if successful, an error code otherwise
  74. //
  75. // Author: billbe 22 Mar 1997
  76. // updated 7 Oct 1997
  77. //
  78. // Notes:
  79. //
  80. HRESULT
  81. HrCiAddNetProviderInfo(HINF hinf, PCWSTR pszSection,
  82. HKEY hkeyInstance, BOOL fPreviouslyInstalled)
  83. {
  84. Assert(IsValidHandle(hinf));
  85. Assert(pszSection);
  86. Assert(hkeyInstance);
  87. //tstring strServiceName;
  88. DWORD dwNetworkPosition = 0; // default position is the front.
  89. DWORD dwPrintPosition = 0; // default position is the front.
  90. if (fPreviouslyInstalled)
  91. {
  92. // Because the inf may contain modifications to the print provider.
  93. // e.g. Display name change, dll name change, etc. We delete it
  94. // then readd. We would like to just update the information
  95. // but the print provider api doesn't support it yet. Until
  96. // then, we need to delete and readd to pick up changes.
  97. //
  98. (void) HrCiDeleteNetProviderInfo(hkeyInstance, &dwNetworkPosition,
  99. &dwPrintPosition);
  100. TraceTag(ttidClassInst, "Upgrading provider info. Net Prov Pos %d "
  101. "Print Prov Pos %d", dwNetworkPosition, dwPrintPosition);
  102. }
  103. // Get the service name for this component
  104. WCHAR szServiceName[MAX_SERVICE_NAME_LEN];
  105. DWORD cbServiceName = MAX_SERVICE_NAME_LEN * sizeof(WCHAR);
  106. HKEY hkeyNdi;
  107. HRESULT hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi", KEY_READ, &hkeyNdi);
  108. if (S_OK == hr)
  109. {
  110. hr = HrRegQuerySzBuffer (
  111. hkeyNdi,
  112. L"Service",
  113. szServiceName,
  114. &cbServiceName);
  115. RegCloseKey (hkeyNdi);
  116. }
  117. if (S_OK == hr)
  118. {
  119. // If this is Webclient we need to make sure it is after
  120. // lanmanworkstation in the ordering. This should be temporary
  121. // until mpr.dll is updated to return the union of provider
  122. // information. Right now a server can source smb shares and
  123. // webclient shares but only one set can be retrieved via the mpr.
  124. // Since smb shares are more common, lanmanworkstation needs to be
  125. // before webclient. When mpr.dll changes, both sets will be returned
  126. // and ordering shouldn't matter (expect for performance).
  127. //
  128. if (0 == lstrcmpiW(szServiceName, L"WebClient"))
  129. {
  130. HKEY hkeyNP;
  131. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyCtlNPOrder,
  132. KEY_READ, &hkeyNP);
  133. if (S_OK == hr)
  134. {
  135. PWSTR Order;
  136. hr = HrRegQuerySzWithAlloc(hkeyNP, c_szProviderOrder, &Order);
  137. if (S_OK == hr)
  138. {
  139. DWORD dwPosition;
  140. if (FFindStringInCommaSeparatedList(L"LanmanWorkstation",
  141. Order, NC_IGNORE, &dwPosition))
  142. {
  143. dwNetworkPosition = dwPosition + 1;
  144. }
  145. delete [] Order;
  146. }
  147. RegCloseKey(hkeyNP);
  148. }
  149. }
  150. TraceTag(ttidClassInst, "Adding %S to the network provider "
  151. "order at position %d\n", szServiceName, dwNetworkPosition);
  152. // Add it to the list of network providers
  153. hr = HrRegAddStringToSz(szServiceName, HKEY_LOCAL_MACHINE,
  154. c_szRegKeyCtlNPOrder, c_szProviderOrder,
  155. c_chComma, STRING_FLAG_ENSURE_AT_INDEX, dwNetworkPosition);
  156. if (S_OK == hr)
  157. {
  158. tstring strNetworkProvider = c_szRegKeyServices;
  159. strNetworkProvider.append(L"\\");
  160. strNetworkProvider.append(szServiceName);
  161. strNetworkProvider.append(L"\\");
  162. strNetworkProvider.append(c_szNetworkProvider);
  163. // Open the NetworkProvider key under the component's
  164. // service key
  165. //
  166. HKEY hkey;
  167. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
  168. strNetworkProvider.c_str(), KEY_SET_VALUE | KEY_READ,
  169. &hkey);
  170. if (S_OK == hr)
  171. {
  172. // Check if shortname is needed.
  173. // by looking for it in the option
  174. // <main install section>.NetworkProvider section
  175. //
  176. tstring strNetworkSection(pszSection);
  177. strNetworkSection += L'.';
  178. strNetworkSection += c_szNetworkProvider;
  179. tstring strShortName;
  180. HRESULT hr = HrCiCreateShortNameValueIfNeeded(hinf,
  181. hkey, strNetworkSection, &strShortName);
  182. if (S_OK == hr)
  183. {
  184. // If shortname was created then we need to
  185. // also store it under the instance
  186. // key so we can remove it when the component
  187. // is removed
  188. (void) HrRegSetString(hkeyInstance,
  189. c_szShortName, strShortName);
  190. }
  191. // Set the device name in the NetworkProvider key
  192. // under the componet's service key
  193. //
  194. if (SUCCEEDED(hr))
  195. {
  196. hr = HrCiSetDeviceName(hinf, hkey, strNetworkSection,
  197. szServiceName);
  198. }
  199. RegCloseKey(hkey);
  200. }
  201. }
  202. }
  203. // Write out any print provider information if the inf file specifies it
  204. //
  205. if (S_OK == hr)
  206. {
  207. hr = HrCiWritePrintProviderInfoIfNeeded(hinf, pszSection,
  208. hkeyInstance, dwPrintPosition);
  209. }
  210. TraceHr (ttidError, FAL, hr, FALSE, "HrCiAddNetProviderInfo");
  211. return hr;
  212. }
  213. //+--------------------------------------------------------------------------
  214. //
  215. // Function: HrCiDeleteNetProviderInfo
  216. //
  217. // Purpose: Deletes the current component from the list of network
  218. // providers and also deletes it as a print provider if
  219. // necessary.
  220. //
  221. // Arguments:
  222. // hkeyInstance [in] The handle to the component's isntance key.
  223. // pdwNetworkPosition [out] Optional. The positon pf this component in
  224. // the network provider order before removal.
  225. // pdwPrintPosition [out] Optional. The positon of this component in
  226. // the print provider order before removal.
  227. //
  228. // Returns: HRESULT. S_OK if successful, an error code otherwise
  229. //
  230. // Author: billbe 22 Mar 1997
  231. // updated 7 Oct 1997
  232. //
  233. // Notes:
  234. //
  235. HRESULT
  236. HrCiDeleteNetProviderInfo(HKEY hkeyInstance, DWORD* pdwNetworkPosition,
  237. DWORD* pdwPrintPosition)
  238. {
  239. Assert(hkeyInstance);
  240. // Initialize out param.
  241. if (pdwNetworkPosition)
  242. {
  243. *pdwNetworkPosition = 0;
  244. }
  245. // Initialize out param.
  246. if (pdwPrintPosition)
  247. {
  248. *pdwPrintPosition = 0;
  249. }
  250. WCHAR szServiceName[MAX_SERVICE_NAME_LEN];
  251. DWORD cbServiceName = MAX_SERVICE_NAME_LEN * sizeof(WCHAR);
  252. // Get the service name for this component.
  253. HKEY hkeyNdi;
  254. HRESULT hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi", KEY_READ, &hkeyNdi);
  255. if (S_OK == hr)
  256. {
  257. hr = HrRegQuerySzBuffer (
  258. hkeyNdi,
  259. L"Service",
  260. szServiceName,
  261. &cbServiceName);
  262. RegCloseKey(hkeyNdi);
  263. }
  264. if (S_OK == hr)
  265. {
  266. // Open the network provider key.
  267. //
  268. HKEY hkeyNetProvider;
  269. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyCtlNPOrder,
  270. KEY_READ_WRITE, &hkeyNetProvider);
  271. if (S_OK == hr)
  272. {
  273. PWSTR pszOrder = NULL;
  274. PWSTR pszNewOrder;
  275. DWORD dwNetPos;
  276. // Get the current list of providers.
  277. //
  278. hr = HrRegQuerySzWithAlloc(hkeyNetProvider,
  279. c_szProviderOrder, &pszOrder);
  280. // If we managed to get the list and the provider we are
  281. // removing is in the list...
  282. //
  283. if ((S_OK == hr) && FFindStringInCommaSeparatedList(
  284. szServiceName, pszOrder,
  285. NC_IGNORE, &dwNetPos))
  286. {
  287. // Remove the provider from the list.
  288. hr = HrRemoveStringFromDelimitedSz(szServiceName,
  289. pszOrder, c_chComma, STRING_FLAG_REMOVE_ALL,
  290. &pszNewOrder);
  291. if (S_OK == hr)
  292. {
  293. // Set the new provider list back in the registry.
  294. (void) HrRegSetSz(hkeyNetProvider, c_szProviderOrder,
  295. pszNewOrder);
  296. MemFree (pszNewOrder);
  297. }
  298. // If the out param was specified, set the position.
  299. //
  300. if (pdwNetworkPosition)
  301. {
  302. *pdwNetworkPosition = dwNetPos;
  303. }
  304. }
  305. MemFree(pszOrder);
  306. RegCloseKey(hkeyNetProvider);
  307. }
  308. if (S_OK == hr)
  309. {
  310. // If short name was used, we need to remove it
  311. //
  312. tstring strShortName;
  313. hr = HrRegQueryString(hkeyInstance, c_szShortName, &strShortName);
  314. if (S_OK == hr)
  315. {
  316. // ShortName was used so remove it
  317. //
  318. HKEY hkey;
  319. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyShortName,
  320. KEY_SET_VALUE, &hkey);
  321. if (S_OK == hr)
  322. {
  323. hr = HrRegDeleteValue(hkey, strShortName.c_str());
  324. // delete from our instance key as well
  325. // Note: we do this because if this component is being
  326. // reinstalled, the new inf might not have shortname so
  327. // we don't want the old value lying around
  328. (void) HrRegDeleteValue(hkeyInstance, c_szShortName);
  329. RegCloseKey(hkey);
  330. }
  331. }
  332. // If the value wasn't there (in the driver key or the ShortName key,
  333. // then there is nothing to delete and everything is okay
  334. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  335. {
  336. hr = S_OK;
  337. }
  338. }
  339. }
  340. // Delete this component as a print provider if necessary
  341. //
  342. if (S_OK == hr)
  343. {
  344. hr = HrCiDeletePrintProviderIfNeeded(hkeyInstance, pdwPrintPosition);
  345. }
  346. TraceHr (ttidError, FAL, hr, FALSE, "HrCiDeleteNetProviderInfo");
  347. return hr;
  348. }
  349. //+--------------------------------------------------------------------------
  350. //
  351. // Function: HrCiCreateShortNameValueIfNeeded
  352. //
  353. // Purpose: Creates the short name value for the component under
  354. // the c_szRegKeyShortName registry key if short name is
  355. // present in the inf. The short name value is set to the
  356. // display name as found in the NetworkProvider key under
  357. // the component's service key
  358. //
  359. // Arguments:
  360. // hinf [in] Handle to the component's inf
  361. // hkeyNetworkProvider [in] The hkey to the NetworkProvider
  362. // key under the component's service
  363. // key
  364. // strSection [in] The section name where ShortName
  365. // would be located
  366. // pstrShortName [out] The short name found in the inf
  367. //
  368. // Returns: HRESULT. S_OK if shortname found, S_FALSE if no shortname was
  369. // found, or error code otherwise.
  370. //
  371. // Author: billbe 7 Oct 1997
  372. //
  373. // Notes:
  374. //
  375. HRESULT
  376. HrCiCreateShortNameValueIfNeeded(HINF hinf, HKEY hkeyNetworkProvider,
  377. const tstring& strSection,
  378. tstring* pstrShortName)
  379. {
  380. Assert(IsValidHandle(hinf));
  381. Assert(hkeyNetworkProvider);
  382. Assert(!strSection.empty());
  383. Assert(pstrShortName);
  384. INFCONTEXT ctx;
  385. // Look for optional shortname
  386. HRESULT hr = HrSetupFindFirstLine(hinf, strSection.c_str(),
  387. c_szShortName, &ctx);
  388. if (SUCCEEDED(hr))
  389. {
  390. // Get the shortname value
  391. hr = HrSetupGetStringField(ctx, 1, pstrShortName);
  392. if (SUCCEEDED(hr))
  393. {
  394. HKEY hkey;
  395. // Create the ShortName key
  396. hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE,
  397. c_szRegKeyShortName, REG_OPTION_NON_VOLATILE,
  398. KEY_SET_VALUE, NULL, &hkey, NULL);
  399. if (SUCCEEDED(hr))
  400. {
  401. // Get the provider name to set the short name value
  402. //
  403. tstring strProviderName;
  404. hr = HrRegQueryString(hkeyNetworkProvider, c_szRegValueName,
  405. &strProviderName);
  406. if (SUCCEEDED(hr))
  407. {
  408. // create the component's short name value under
  409. // the ShortName key and set it to the component's
  410. // display name
  411. hr = HrRegSetString(hkey, pstrShortName->c_str(),
  412. strProviderName);
  413. }
  414. RegCloseKey(hkey);
  415. }
  416. }
  417. }
  418. // The line and section were optional so if it didn't exists return S_FALSE
  419. if ((SPAPI_E_LINE_NOT_FOUND == hr) ||
  420. (SPAPI_E_BAD_SECTION_NAME_LINE == hr))
  421. {
  422. hr = S_FALSE;
  423. }
  424. // On failure, initialize the out param
  425. if (FAILED(hr))
  426. {
  427. pstrShortName->erase();
  428. }
  429. TraceHr (ttidError, FAL, hr, S_FALSE == hr,
  430. "HrCiCreateShortNameValueIfNeeded");
  431. return hr;
  432. }
  433. //+--------------------------------------------------------------------------
  434. //
  435. // Function: HrCiSetDeviceName
  436. //
  437. // Purpose: Creates the device name value for the component under
  438. // the NetworkProvider key located in the component's
  439. // service key. The device name by default is
  440. // \Device\<component's service name> unless the inf
  441. // specifies a new device name.
  442. //
  443. // Arguments:
  444. // hinf [in] Handle to the component's inf
  445. // hkeyNetworkProvider [in] The hkey to the NetworkProvider
  446. // key under the component's service
  447. // key
  448. // strSection [in] The section name where ShortName
  449. // would be located
  450. // strServiceName [in] The component's service name
  451. //
  452. // Returns: HRESULT. S_OK if successful, or error code otherwise.
  453. //
  454. // Author: billbe 7 Oct 1997
  455. //
  456. // Notes:
  457. //
  458. HRESULT
  459. HrCiSetDeviceName(HINF hinf, HKEY hkeyNetworkProvider,
  460. const tstring& strSection, const tstring& strServiceName)
  461. {
  462. Assert(IsValidHandle(hinf));
  463. Assert(hkeyNetworkProvider);
  464. INFCONTEXT ctx;
  465. tstring strDeviceName = c_szDevice;
  466. // Look for optional DeviceName
  467. HRESULT hr = HrSetupFindFirstLine(hinf, strSection.c_str(),
  468. c_szDeviceName, &ctx);
  469. if (SUCCEEDED(hr))
  470. {
  471. tstring strName;
  472. // Get the DeviceName value
  473. hr = HrSetupGetStringField(ctx, 1, &strName);
  474. if (SUCCEEDED(hr))
  475. {
  476. // append it to the current value
  477. strDeviceName.append(strName);
  478. }
  479. }
  480. // If the device name line was not found in the inf (or the
  481. // section name wasn't found), use the service name
  482. //
  483. if ((SPAPI_E_LINE_NOT_FOUND == hr) ||
  484. (SPAPI_E_BAD_SECTION_NAME_LINE == hr))
  485. {
  486. strDeviceName.append(strServiceName);
  487. hr = S_OK;
  488. }
  489. if (SUCCEEDED(hr))
  490. {
  491. // Now set the device name value in the service's networkprovider key
  492. hr = HrRegSetString(hkeyNetworkProvider, c_szDeviceName,
  493. strDeviceName);
  494. }
  495. TraceHr (ttidError, FAL, hr, FALSE, "HrCiSetDeviceName");
  496. return hr;
  497. }
  498. //+--------------------------------------------------------------------------
  499. //
  500. // Function: HrCiGetPrintProviderInfoFromInf
  501. //
  502. // Purpose: This function gets the display name and dll name from
  503. // the print provider section strSection.
  504. //
  505. // Arguments:
  506. // hinf [in] handle to inf file. See SetupApi for more info
  507. // strSection [in] The print provider section name
  508. // pstrName [out] The print provider name found in the inf
  509. // pstrDll [out] The dll name found in the inf
  510. // pstrDisplayName [out] The localized display name found in the inf
  511. //
  512. // Returns: HRESULT. S_OK if successful, error code otherwise
  513. //
  514. // Author: billbe 24 Oct 1997
  515. //
  516. // Notes:
  517. HRESULT
  518. HrCiGetPrintProviderInfoFromInf(HINF hinf, tstring strSection, tstring* pstrName,
  519. tstring* pstrDll, tstring* pstrDisplayName)
  520. {
  521. Assert(!strSection.empty());
  522. Assert(pstrName);
  523. Assert(pstrDll);
  524. Assert(pstrDisplayName);
  525. INFCONTEXT ctx;
  526. // find the line containing non-localized ProviderName
  527. HRESULT hr = HrSetupFindFirstLine(hinf, strSection.c_str(),
  528. c_szPrintProviderName, &ctx);
  529. if (S_OK == hr)
  530. {
  531. // Get the ProviderName
  532. hr = HrSetupGetStringField(ctx, 1, pstrName);
  533. if (S_OK == hr)
  534. {
  535. // Now find and get the PrintProviderDll value
  536. //
  537. hr = HrSetupFindFirstLine(hinf, strSection.c_str(),
  538. c_szInfKeyPrintProviderDll, &ctx);
  539. if (S_OK == hr)
  540. {
  541. hr = HrSetupGetStringField(ctx, 1, pstrDll);
  542. if (S_OK == hr)
  543. {
  544. // find the line containing DisplayName
  545. hr = HrSetupFindFirstLine(hinf, strSection.c_str(),
  546. c_szDisplayName, &ctx);
  547. if (S_OK == hr)
  548. {
  549. // Get the DisplayName
  550. hr = HrSetupGetStringField(ctx, 1, pstrDisplayName);
  551. }
  552. }
  553. }
  554. }
  555. }
  556. TraceHr (ttidError, FAL, hr, FALSE, "HrCiGetPrintProviderInfoFromInf");
  557. return hr;
  558. }
  559. //+--------------------------------------------------------------------------
  560. //
  561. // Function: HrCiWritePrintProviderInfoIfNeeded
  562. //
  563. // Purpose: This function updates necessary registry entries for
  564. // NETCLIENT class components that are print providers.
  565. //
  566. // Arguments:
  567. // hinf [in] handle to inf file. See SetupApi for more info.
  568. // strSection [in] The main section name.
  569. // hkeyInstance [in] The hkey to the component's instance key.
  570. // dwPrintPosition [in] The position to place the print provider when
  571. // it is added to the list.
  572. //
  573. // Returns: HRESULT. S_OK if successful, error code otherwise
  574. //
  575. // Author: billbe 22 Mar 1997
  576. // updated 7 Oct 1997
  577. //
  578. // Notes:
  579. HRESULT
  580. HrCiWritePrintProviderInfoIfNeeded(HINF hinf, const tstring& strSection,
  581. HKEY hkeyInstance, DWORD dwPrintPosition)
  582. {
  583. Assert(IsValidHandle(hinf));
  584. Assert(!strSection.empty());
  585. Assert(hkeyInstance);
  586. HRESULT hr = S_OK;
  587. INFCONTEXT ctx;
  588. tstring strDisplayName;
  589. tstring strName;
  590. tstring strPrintProviderDll;
  591. tstring strPrintSection(strSection);
  592. strPrintSection.append(L".");
  593. strPrintSection.append(c_szInfSubKeyPrintProvider);
  594. // First we check for the PrintProvider inf section
  595. hr = HrSetupFindFirstLine(hinf, strPrintSection.c_str(), NULL,
  596. &ctx);
  597. if (S_OK == hr)
  598. {
  599. // Get the print provider information from the inf
  600. hr = HrCiGetPrintProviderInfoFromInf(hinf, strPrintSection,
  601. &strName, &strPrintProviderDll, &strDisplayName);
  602. if (S_OK == hr)
  603. {
  604. // Add the component as a print provider
  605. hr = HrCiAddPrintProvider(strName, strPrintProviderDll,
  606. strDisplayName, dwPrintPosition);
  607. // Now write the Provider name under our instance key
  608. // so we can remove this provider when asked
  609. if (S_OK == hr)
  610. {
  611. (void) HrRegSetString(hkeyInstance,
  612. c_szPrintProviderName, strName);
  613. }
  614. }
  615. }
  616. else
  617. {
  618. // The section is optional so this is not an error
  619. if (SPAPI_E_LINE_NOT_FOUND == hr)
  620. {
  621. hr = S_OK;
  622. }
  623. }
  624. TraceHr (ttidError, FAL, hr, FALSE, "HrCiWritePrintProviderInfoIfNeeded");
  625. return hr;
  626. }
  627. //+--------------------------------------------------------------------------
  628. //
  629. // Function: MoveProviderToIndex
  630. //
  631. // Purpose: This function moves the pszProviderName to the position
  632. // specified.
  633. //
  634. // Arguments:
  635. // pszProviderName [in] Name of the print provider (used in call to
  636. // AddPrintProvidor.
  637. // dwPrintPosition [in] The index to place this provider in the
  638. // provider order.
  639. //
  640. // Returns: nothing
  641. //
  642. // Author: billbe 6 Oct 1998
  643. //
  644. // Notes:
  645. //
  646. VOID
  647. MoveProviderToIndex (
  648. IN PCWSTR pszProviderName,
  649. IN DWORD dwPrintPosition)
  650. {
  651. PROVIDOR_INFO_2 p2info;
  652. // Open the print provider key
  653. //
  654. HKEY hkey;
  655. HRESULT hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyPrintProviders,
  656. KEY_READ, &hkey);
  657. if (S_OK == hr)
  658. {
  659. // Retrieve the current order
  660. //
  661. PWSTR pmszOrder;
  662. hr = HrRegQueryMultiSzWithAlloc(hkey, c_szRegValueOrder, &pmszOrder);
  663. if (S_OK == hr)
  664. {
  665. PWSTR pmszNewOrder;
  666. BOOL fChanged;
  667. // Move the provider to the front
  668. //
  669. hr = HrAddSzToMultiSz(pszProviderName, pmszOrder,
  670. STRING_FLAG_ENSURE_AT_INDEX, dwPrintPosition,
  671. &pmszNewOrder, &fChanged);
  672. if ((S_OK == hr) && fChanged)
  673. {
  674. // Notify Spooler that we want to change the order
  675. //
  676. p2info.pOrder = pmszNewOrder;
  677. if (!AddPrintProvidor(NULL, 2, (LPBYTE)&p2info))
  678. {
  679. hr = HrFromLastWin32Error();
  680. // If we removed duplicates, the last call to
  681. // AddPrintProvidor may have failed with
  682. // ERROR_INVALID_PARAMETER. Trying again will correct
  683. // the problem.
  684. //
  685. if (HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) == hr)
  686. {
  687. AddPrintProvidor(NULL, 2,
  688. reinterpret_cast<LPBYTE>(&p2info));
  689. }
  690. TraceHr (ttidError, FAL, hr, FALSE,
  691. "AddPrintProvider(class 2) returned an error");
  692. }
  693. MemFree(pmszNewOrder);
  694. }
  695. MemFree(pmszOrder);
  696. }
  697. TraceHr (ttidError, FAL, hr, FALSE, "MoveProviderToIndex");
  698. RegCloseKey(hkey);
  699. }
  700. }
  701. //+--------------------------------------------------------------------------
  702. //
  703. // Function: HrCiAddPrintProvider
  704. //
  705. // Purpose: This function calls the AddPrintProvidor [sic] function
  706. // to add the current component as a provider.
  707. //
  708. // Arguments:
  709. // strName [in] Name of the print provider (used in call to
  710. // AddPrintProvidor.
  711. // strDllName [in] Dll name of the print provider.
  712. // strDisplayName [in] Localized Display Name.
  713. // dwPrintPosition [in] The position to place this provider when it
  714. // is added to the list.
  715. //
  716. // Returns: HRESULT. S_OK if successful, error code otherwise.
  717. //
  718. // Author: billbe 22 Mar 1997
  719. // updated 7 Oct 1997
  720. //
  721. // Notes: See AddPrintProvidor Win32 fcn for more info
  722. HRESULT
  723. HrCiAddPrintProvider(
  724. const tstring& strName,
  725. const tstring& strDllName,
  726. const tstring& strDisplayName,
  727. DWORD dwPrintPosition)
  728. {
  729. Assert(!strName.empty());
  730. Assert(!strDllName.empty());
  731. PROVIDOR_INFO_1 pi1;
  732. HRESULT hr=S_OK;
  733. // Fill the structure with the relevant info
  734. //
  735. pi1.pEnvironment = NULL;
  736. pi1.pDLLName = (PWSTR)strDllName.c_str();
  737. pi1.pName = (PWSTR)strName.c_str();
  738. hr = HrEnableAndStartSpooler();
  739. if (S_OK == hr)
  740. {
  741. if (!AddPrintProvidor(NULL, 1, reinterpret_cast<LPBYTE>(&pi1)))
  742. {
  743. // convert the error
  744. hr = HrFromLastWin32Error();
  745. }
  746. }
  747. if (S_OK == hr)
  748. {
  749. // AddPrintProvidor adds the print provider to the end of list.
  750. // 99% of the time, the goal is to have the provider be somewhere
  751. // else. We will attempt to move it to the position given to us. This
  752. // is either the beginning of the list or the previous position of
  753. // this provider (i.e. if we are reinstalling) If it fails we can
  754. // still go on.
  755. (void) MoveProviderToIndex(pi1.pName, dwPrintPosition);
  756. tstring strPrintProvider = c_szRegKeyPrintProviders;
  757. strPrintProvider.append(L"\\");
  758. strPrintProvider.append(strName);
  759. HKEY hkey;
  760. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
  761. strPrintProvider.c_str(),
  762. KEY_SET_VALUE, &hkey);
  763. if (S_OK == hr)
  764. {
  765. // Write DisplayName in the new key created by the
  766. // AddPrintProvidor [sic] call.
  767. // Not sure who the consumer of this value is but
  768. // the NT4 code did this
  769. hr = HrRegSetString(hkey, c_szDisplayName, strDisplayName);
  770. RegCloseKey(hkey);
  771. }
  772. }
  773. TraceHr (ttidError, FAL, hr, FALSE, "HrCiAddPrintProvider");
  774. return hr;
  775. }
  776. //+--------------------------------------------------------------------------
  777. //
  778. // Function: HrCiDeletePrintProviderIfNeeded
  779. //
  780. // Purpose: This function calls the DeletePrintProvidor [sic] function
  781. // if this component was a print provider
  782. //
  783. // Arguments:
  784. // hkeyInstance [in] The hkey for the component's instance key.
  785. // pdwProviderPosition [out] Optional. The position of the print
  786. // provider in the order list before it was
  787. // deleted.
  788. //
  789. // Returns: HRESULT. S_OK if successful, error code otherwise
  790. //
  791. // Author: billbe 22 Mar 1997
  792. // updated 7 Oct 1997
  793. //
  794. // Notes: See DeletePrintProvidor Win32 fcn for more info
  795. //
  796. HRESULT
  797. HrCiDeletePrintProviderIfNeeded(HKEY hkeyInstance, DWORD* pdwProviderPosition)
  798. {
  799. // Check if this component is a print provider
  800. //
  801. tstring strName;
  802. HRESULT hr = HrRegQueryString(hkeyInstance, c_szPrintProviderName,
  803. &strName);
  804. if (SUCCEEDED(hr))
  805. {
  806. // If the out param was specified, we may need to get the current position of this print provider
  807. // in the list of providers
  808. if (pdwProviderPosition)
  809. {
  810. *pdwProviderPosition = 0;
  811. // Open the print key
  812. //
  813. HKEY hkeyPrint;
  814. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyPrintProviders,
  815. KEY_READ, &hkeyPrint);
  816. if (SUCCEEDED(hr))
  817. {
  818. // Get the current order of providers
  819. //
  820. PWSTR pmszOrder;
  821. hr = HrRegQueryMultiSzWithAlloc(hkeyPrint,
  822. c_szRegValueOrder, &pmszOrder);
  823. if (S_OK == hr)
  824. {
  825. // Get this provider's current position
  826. (void) FGetSzPositionInMultiSzSafe(
  827. strName.c_str(), pmszOrder, pdwProviderPosition,
  828. NULL, NULL);
  829. MemFree(pmszOrder);
  830. }
  831. RegCloseKey(hkeyPrint);
  832. }
  833. }
  834. // The component was a print provider so we need to delete it as such
  835. //
  836. DeletePrintProvidor(NULL, NULL, (PWSTR)strName.c_str());
  837. // delete from our instance key as well
  838. // Note: we do this because if this component is being
  839. // reinstalled, the new inf might not have a providername so
  840. // we don't want the old value lying around
  841. (void) HrRegDeleteValue(hkeyInstance, c_szPrintProviderName);
  842. }
  843. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  844. {
  845. // This component was not a print provider so there
  846. // is nothing to remove
  847. hr = S_OK;
  848. }
  849. TraceHr (ttidError, FAL, hr, FALSE, "HrCiDeletePrintProviderIfNeeded");
  850. return hr;
  851. }