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.

1623 lines
43 KiB

  1. /*
  2. * Copyright (c) 1996 Microsoft Corporation
  3. *
  4. * Module Name:
  5. *
  6. * ocgen.cpp
  7. *
  8. * Abstract:
  9. *
  10. * This file handles all messages passed by the OC Manager
  11. *
  12. * Author:
  13. *
  14. * Pat Styles (patst) Jan-20-1998
  15. *
  16. * Environment:
  17. *
  18. * User Mode
  19. */
  20. #define _OCGEN_CPP_
  21. #define UNICODE
  22. #define _UNICODE
  23. #include <stdlib.h>
  24. #include <assert.h>
  25. #include <tchar.h>
  26. #include <objbase.h>
  27. #include <shlwapi.h>
  28. #include <lm.h>
  29. #include "ocgen.h"
  30. #include <strsafe.h>
  31. #pragma hdrstop
  32. // also referred to in ocgen.h // forward reference
  33. DWORD OnPreinitialize();
  34. DWORD OnInitComponent(LPCTSTR ComponentId, PSETUP_INIT_COMPONENT psc);
  35. DWORD OnSetLanguage();
  36. DWORD_PTR OnQueryImage();
  37. DWORD OnSetupRequestPages(UINT type, PVOID srp);
  38. DWORD OnQuerySelStateChange(LPCTSTR ComponentId, LPCTSTR SubcomponentId, UINT state, UINT flags);
  39. DWORD OnCalcDiskSpace(LPCTSTR ComponentId, LPCTSTR SubcomponentId, DWORD addComponent, HDSKSPC dspace);
  40. DWORD OnQueueFileOps(LPCTSTR ComponentId, LPCTSTR SubcomponentId, HSPFILEQ queue);
  41. DWORD OnNotificationFromQueue();
  42. DWORD OnQueryStepCount();
  43. DWORD OnCompleteInstallation(LPCTSTR ComponentId, LPCTSTR SubcomponentId);
  44. DWORD OnCleanup();
  45. DWORD OnQueryState(LPCTSTR ComponentId, LPCTSTR SubcomponentId, UINT state);
  46. DWORD OnNeedMedia();
  47. DWORD OnAboutToCommitQueue(LPCTSTR ComponentId, LPCTSTR SubcomponentId);
  48. DWORD OnQuerySkipPage();
  49. DWORD OnWizardCreated();
  50. DWORD OnExtraRoutines(LPCTSTR ComponentId, PEXTRA_ROUTINES per);
  51. PPER_COMPONENT_DATA AddNewComponent(LPCTSTR ComponentId);
  52. PPER_COMPONENT_DATA LocateComponent(LPCTSTR ComponentId);
  53. VOID RemoveComponent(LPCTSTR ComponentId);
  54. BOOL StateInfo(PPER_COMPONENT_DATA cd, LPCTSTR SubcomponentId, BOOL *state);
  55. DWORD RegisterServers(HINF hinf, LPCTSTR component, DWORD state);
  56. DWORD EnumSections(HINF hinf, const TCHAR *component, const TCHAR *key, DWORD index, INFCONTEXT *pic, TCHAR *name);
  57. DWORD RegisterServices(PPER_COMPONENT_DATA cd, LPCTSTR component, DWORD state);
  58. DWORD CleanupNetShares(PPER_COMPONENT_DATA cd, LPCTSTR component, DWORD state);
  59. DWORD RunExternalProgram(PPER_COMPONENT_DATA cd, LPCTSTR component, DWORD state);
  60. // for determining prior install status of WMI components
  61. bool IsMSIProviderPresent();
  62. // for registering dlls
  63. typedef HRESULT (__stdcall *pfn)(void);
  64. #define KEYWORD_REGSVR TEXT("RegSvr")
  65. #define KEYWORD_UNREGSVR TEXT("UnregSvr")
  66. #define KEYWORD_UNINSTALL TEXT("Uninstall")
  67. #define KEYWORD_SOURCEPATH TEXT("SourcePath")
  68. #define KEYWORD_DELSHARE TEXT("DelShare")
  69. #define KEYWORD_ADDSERVICE TEXT("AddService")
  70. #define KEYWORD_DELSERVICE TEXT("DelService")
  71. #define KEYWORD_SHARENAME TEXT("Share")
  72. #define KEYWORD_RUN TEXT("Run")
  73. #define KEYVAL_SYSTEMSRC TEXT("SystemSrc")
  74. #define KEYWORD_COMMANDLINE TEXT("CommandLine")
  75. #define KEYWORD_TICKCOUNT TEXT("TickCount")
  76. // Services keywords/options
  77. #define KEYWORD_SERVICENAME TEXT("ServiceName")
  78. #define KEYWORD_DISPLAYNAME TEXT("DisplayName")
  79. #define KEYWORD_SERVICETYPE TEXT("ServiceType")
  80. #define KEYWORD_STARTTYPE TEXT("StartType")
  81. #define KEYWORD_ERRORCONTROL TEXT("ErrorControl")
  82. #define KEYWORD_IMAGEPATH TEXT("BinaryPathName")
  83. #define KEYWORD_LOADORDER TEXT("LoadOrderGroup")
  84. #define KEYWORD_DEPENDENCIES TEXT("Dependencies")
  85. #define KEYWORD_STARTNAME TEXT("ServiceStartName")
  86. #define KEYWORD_PASSWORD TEXT("Password")
  87. #define KEYVAL_ON TEXT("on")
  88. #define KEYVAL_OFF TEXT("off")
  89. #define KEYVAL_DEFAULT TEXT("default")
  90. const char gszRegisterSvrRoutine[] = "DllRegisterServer";
  91. const char gszUnregisterSvrRoutine[] = "DllUnregisterServer";
  92. BOOL g_fRebootNeed = FALSE;
  93. PPER_COMPONENT_DATA _cd;
  94. void av()
  95. {
  96. _cd = NULL;
  97. _cd->hinf = NULL;
  98. }
  99. /*
  100. * called by CRT when _DllMainCRTStartup is the DLL entry point
  101. */
  102. /*
  103. Not needed now as Wbemupgd.dll already has a DllMain.
  104. BOOL
  105. WINAPI
  106. DllMain(
  107. IN HINSTANCE hinstance,
  108. IN DWORD reason,
  109. IN LPVOID reserved
  110. )
  111. {
  112. BOOL b;
  113. UNREFERENCED_PARAMETER(reserved);
  114. b = true;
  115. switch(reason)
  116. {
  117. case DLL_PROCESS_ATTACH:
  118. ghinst = hinstance;
  119. loginit();
  120. // Fall through to process first thread
  121. case DLL_THREAD_ATTACH:
  122. b = true;
  123. break;
  124. case DLL_PROCESS_DETACH:
  125. break;
  126. case DLL_THREAD_DETACH:
  127. break;
  128. }
  129. return(b);
  130. }
  131. */
  132. DWORD_PTR
  133. OcEntry(
  134. IN LPCTSTR ComponentId,
  135. IN LPCTSTR SubcomponentId,
  136. IN UINT Function,
  137. IN UINT Param1,
  138. IN OUT PVOID Param2
  139. )
  140. {
  141. DWORD_PTR rc;
  142. DebugTraceOCNotification(Function, ComponentId);
  143. logOCNotification(Function, ComponentId);
  144. switch(Function)
  145. {
  146. case OC_PREINITIALIZE:
  147. rc = OnPreinitialize();
  148. break;
  149. case OC_INIT_COMPONENT:
  150. rc = OnInitComponent(ComponentId, (PSETUP_INIT_COMPONENT)Param2);
  151. break;
  152. case OC_EXTRA_ROUTINES:
  153. rc = OnExtraRoutines(ComponentId, (PEXTRA_ROUTINES)Param2);
  154. break;
  155. case OC_SET_LANGUAGE:
  156. rc = OnSetLanguage();
  157. break;
  158. case OC_QUERY_IMAGE:
  159. rc = OnQueryImage();
  160. break;
  161. case OC_REQUEST_PAGES:
  162. rc = OnSetupRequestPages(Param1, Param2);
  163. break;
  164. case OC_QUERY_CHANGE_SEL_STATE:
  165. rc = OnQuerySelStateChange(ComponentId, SubcomponentId, Param1, (UINT)((UINT_PTR)Param2));
  166. break;
  167. case OC_CALC_DISK_SPACE:
  168. rc = OnCalcDiskSpace(ComponentId, SubcomponentId, Param1, Param2);
  169. break;
  170. case OC_QUEUE_FILE_OPS:
  171. rc = OnQueueFileOps(ComponentId, SubcomponentId, (HSPFILEQ)Param2);
  172. break;
  173. case OC_NOTIFICATION_FROM_QUEUE:
  174. rc = OnNotificationFromQueue();
  175. break;
  176. case OC_QUERY_STEP_COUNT:
  177. rc = OnQueryStepCount();
  178. break;
  179. case OC_COMPLETE_INSTALLATION:
  180. rc = OnCompleteInstallation(ComponentId, SubcomponentId);
  181. break;
  182. case OC_CLEANUP:
  183. rc = OnCleanup();
  184. break;
  185. case OC_QUERY_STATE:
  186. rc = OnQueryState(ComponentId, SubcomponentId, Param1);
  187. break;
  188. case OC_NEED_MEDIA:
  189. rc = OnNeedMedia();
  190. break;
  191. case OC_ABOUT_TO_COMMIT_QUEUE:
  192. rc = OnAboutToCommitQueue(ComponentId,SubcomponentId);
  193. break;
  194. case OC_QUERY_SKIP_PAGE:
  195. rc = OnQuerySkipPage();
  196. break;
  197. case OC_WIZARD_CREATED:
  198. rc = OnWizardCreated();
  199. break;
  200. default:
  201. rc = NO_ERROR;
  202. break;
  203. }
  204. DebugTrace(1, TEXT("processing completed"));
  205. logOCNotificationCompletion();
  206. return rc;
  207. }
  208. /*-------------------------------------------------------*/
  209. /*
  210. * OC Manager message handlers
  211. *
  212. *-------------------------------------------------------*/
  213. /* OnPreinitialize()
  214. *
  215. * handler for OC_PREINITIALIZE
  216. */
  217. DWORD
  218. OnPreinitialize(
  219. VOID
  220. )
  221. {
  222. #ifdef ANSI
  223. return OCFLAG_ANSI;
  224. #else
  225. return OCFLAG_UNICODE;
  226. #endif
  227. }
  228. /*
  229. * OnInitComponent()
  230. *
  231. * handler for OC_INIT_COMPONENT
  232. */
  233. DWORD OnInitComponent(LPCTSTR ComponentId, PSETUP_INIT_COMPONENT psc)
  234. {
  235. PPER_COMPONENT_DATA cd;
  236. INFCONTEXT context;
  237. TCHAR buf[256];
  238. HINF hinf;
  239. BOOL rc;
  240. // assert(0);
  241. // av();
  242. // add component to linked list
  243. if (!(cd = AddNewComponent(ComponentId)))
  244. return ERROR_NOT_ENOUGH_MEMORY;
  245. // store component inf handle
  246. cd->hinf = (psc->ComponentInfHandle == INVALID_HANDLE_VALUE)
  247. ? NULL
  248. : psc->ComponentInfHandle;
  249. // open the inf
  250. if (cd->hinf)
  251. SetupOpenAppendInfFile(NULL, cd->hinf,NULL);
  252. // copy helper routines and flags
  253. cd->HelperRoutines = psc->HelperRoutines;
  254. cd->Flags = psc->SetupData.OperationFlags;
  255. cd->SourcePath = NULL;
  256. #if 0
  257. // Setup the SourcePath. Read inf and see if we should use the NT setup source.
  258. // If so, set to null and setupapi will take care of this for us. If there is
  259. // something specified in the inf, use it, otherwise use what is passed to us.
  260. *buf = 0;
  261. rc = SetupFindFirstLine(cd->hinf,
  262. ComponentId,
  263. KEYWORD_SOURCEPATH,
  264. &context);
  265. if (rc) {
  266. rc = SetupGetStringField(&context,
  267. 1,
  268. buf,
  269. sizeof(buf) / sizeof(TCHAR),
  270. NULL);
  271. }
  272. if (!_tcsicmp(buf, KEYVAL_SYSTEMSRC)) {
  273. cd->SourcePath = NULL;
  274. } else {
  275. cd->SourcePath = (TCHAR *)LocalAlloc(LMEM_FIXED, SBUF_SIZE);
  276. if (!cd->SourcePath)
  277. return ERROR_CANCELLED;
  278. if (!*buf)
  279. _tcscpy(cd->SourcePath, psc->SetupData.SourcePath);
  280. else
  281. ExpandEnvironmentStrings(buf, cd->SourcePath, S_SIZE);
  282. }
  283. #endif
  284. // play
  285. srand(GetTickCount());
  286. return NO_ERROR;
  287. }
  288. /*
  289. * OnExtraRoutines()
  290. *
  291. * handler for OC_EXTRA_ROUTINES
  292. */
  293. DWORD OnExtraRoutines(LPCTSTR ComponentId, PEXTRA_ROUTINES per)
  294. {
  295. PPER_COMPONENT_DATA cd;
  296. if (!(cd = LocateComponent(ComponentId)))
  297. return NO_ERROR;
  298. memcpy(&cd->ExtraRoutines, per, per->size);
  299. return NO_ERROR;
  300. }
  301. /*
  302. * OnSetLanguage()
  303. *
  304. * handler for OC_SET_LANGUAGE
  305. */
  306. DWORD OnSetLanguage()
  307. {
  308. return false;
  309. }
  310. /*
  311. * OnSetLanguage()
  312. *
  313. * handler for OC_SET_LANGUAGE
  314. */
  315. DWORD_PTR OnQueryImage()
  316. {
  317. return (DWORD_PTR)LoadBitmap(NULL,MAKEINTRESOURCE(32754)); // OBM_CLOSE
  318. }
  319. /*
  320. * OnSetupRequestPages
  321. *
  322. * Prepares wizard pages and returns them to the OC Manager
  323. */
  324. DWORD OnSetupRequestPages(UINT type, PVOID srp)
  325. {
  326. return 0;
  327. }
  328. /*
  329. * OnWizardCreated()
  330. */
  331. DWORD OnWizardCreated()
  332. {
  333. return NO_ERROR;
  334. }
  335. /*
  336. * OnQuerySkipPage()
  337. *
  338. * don't let the user deselect the sam component
  339. */
  340. DWORD OnQuerySkipPage()
  341. {
  342. return false;
  343. }
  344. /*
  345. * OnQuerySelStateChange()
  346. *
  347. * don't let the user deselect the sam component
  348. */
  349. DWORD OnQuerySelStateChange(LPCTSTR ComponentId,
  350. LPCTSTR SubcomponentId,
  351. UINT state,
  352. UINT flags)
  353. {
  354. DWORD rc = true;
  355. #if 0
  356. // if (!(flags & OCQ_ACTUAL_SELECTION)) {
  357. if (!_tcsicmp(SubcomponentId, TEXT("three"))) {
  358. if (!state) {
  359. return false;
  360. }
  361. }
  362. if (!_tcsicmp(ComponentId, TEXT("three"))) {
  363. if (!state) {
  364. return false;
  365. }
  366. }
  367. if (!_tcsicmp(SubcomponentId, TEXT("gs7"))) {
  368. if (state) {
  369. return false;
  370. }
  371. }
  372. if (!_tcsicmp(ComponentId, TEXT("gs7"))) {
  373. if (state) {
  374. return false;
  375. }
  376. }
  377. // }
  378. #endif
  379. if (!rc && (flags & OCQ_ACTUAL_SELECTION))
  380. MessageBeep(MB_ICONEXCLAMATION);
  381. return rc;
  382. }
  383. /*
  384. * OnCalcDiskSpace()
  385. *
  386. * handler for OC_ON_CALC_DISK_SPACE
  387. */
  388. DWORD OnCalcDiskSpace(LPCTSTR ComponentId,
  389. LPCTSTR SubcomponentId,
  390. DWORD addComponent,
  391. HDSKSPC dspace)
  392. {
  393. DWORD rc = NO_ERROR;
  394. TCHAR section[S_SIZE];
  395. PPER_COMPONENT_DATA cd;
  396. //
  397. // Param1 = 0 if for removing component or non-0 if for adding component
  398. // Param2 = HDSKSPC to operate on
  399. //
  400. // Return value is Win32 error code indicating outcome.
  401. //
  402. // In our case the private section for this component/subcomponent pair
  403. // is a simple standard inf install section, so we can use the high-level
  404. // disk space list api to do what we want.
  405. //
  406. if (!(cd = LocateComponent(ComponentId)))
  407. return NO_ERROR;
  408. StringCchCopy(section, S_SIZE, SubcomponentId);
  409. if (addComponent)
  410. {
  411. rc = SetupAddInstallSectionToDiskSpaceList(dspace,
  412. cd->hinf,
  413. NULL,
  414. section,
  415. 0,
  416. 0);
  417. }
  418. else
  419. {
  420. rc = SetupRemoveInstallSectionFromDiskSpaceList(dspace,
  421. cd->hinf,
  422. NULL,
  423. section,
  424. 0,
  425. 0);
  426. }
  427. if (!rc)
  428. rc = GetLastError();
  429. else
  430. rc = NO_ERROR;
  431. return rc;
  432. }
  433. /*
  434. * OnQueueFileOps()
  435. *
  436. * handler for OC_QUEUE_FILE_OPS
  437. */
  438. DWORD OnQueueFileOps(LPCTSTR ComponentId, LPCTSTR SubcomponentId, HSPFILEQ queue)
  439. {
  440. PPER_COMPONENT_DATA cd;
  441. BOOL state;
  442. BOOL rc;
  443. INFCONTEXT context;
  444. TCHAR section[256];
  445. TCHAR srcpathbuf[256];
  446. TCHAR *srcpath;
  447. if (!(cd = LocateComponent(ComponentId)))
  448. return NO_ERROR;
  449. if (!SubcomponentId || !*SubcomponentId)
  450. return NO_ERROR;
  451. cd->queue = queue;
  452. if (!StateInfo(cd, SubcomponentId, &state))
  453. return NO_ERROR;
  454. StringCchPrintf(section, 256, SubcomponentId);
  455. rc = TRUE;
  456. if (!state) {
  457. // being uninstalled. Fetch uninstall section name.
  458. rc = SetupFindFirstLine(cd->hinf,
  459. SubcomponentId,
  460. KEYWORD_UNINSTALL,
  461. &context);
  462. if (rc) {
  463. rc = SetupGetStringField(&context,
  464. 1,
  465. section,
  466. sizeof(section) / sizeof(TCHAR),
  467. NULL);
  468. }
  469. // also, unregister the dlls and kill services before deletion
  470. SetupInstallServicesFromInfSection(cd->hinf, section, 0);
  471. SetupInstallFromInfSection(NULL,cd->hinf,section,SPINST_UNREGSVR,NULL,NULL,0,NULL,NULL,NULL,NULL);
  472. }
  473. if (rc) {
  474. // if uninstalling, don't use version checks
  475. rc = SetupInstallFilesFromInfSection(cd->hinf,
  476. NULL,
  477. queue,
  478. section,
  479. cd->SourcePath,
  480. state ? SP_COPY_NEWER : 0);
  481. }
  482. if (!rc)
  483. return GetLastError();
  484. return NO_ERROR;
  485. }
  486. /*
  487. * OnNotificationFromQueue()
  488. *
  489. * handler for OC_NOTIFICATION_FROM_QUEUE
  490. *
  491. * NOTE: although this notification is defined,
  492. * it is currently unimplemented in oc manager
  493. */
  494. DWORD OnNotificationFromQueue()
  495. {
  496. return NO_ERROR;
  497. }
  498. /*
  499. * OnQueryStepCount
  500. *
  501. * handler forOC_QUERY_STEP_COUNT
  502. */
  503. DWORD OnQueryStepCount()
  504. {
  505. return 2;
  506. }
  507. /*
  508. * OnCompleteInstallation
  509. *
  510. * handler for OC_COMPLETE_INSTALLATION
  511. */
  512. DWORD OnCompleteInstallation(LPCTSTR ComponentId, LPCTSTR SubcomponentId)
  513. {
  514. PPER_COMPONENT_DATA cd;
  515. INFCONTEXT context;
  516. TCHAR section[256];
  517. BOOL state;
  518. BOOL rc;
  519. DWORD Error = NO_ERROR;
  520. // Do post-installation processing in the cleanup section.
  521. // This way we know all compoents queued for installation
  522. // have beein installed before we do our stuff.
  523. if (!(cd = LocateComponent(ComponentId)))
  524. return NO_ERROR;
  525. if (!SubcomponentId || !*SubcomponentId)
  526. return NO_ERROR;
  527. if (!StateInfo(cd, SubcomponentId, &state))
  528. return NO_ERROR;
  529. StringCchPrintf(section, 256, SubcomponentId);
  530. rc = TRUE;
  531. if (!state) {
  532. // being uninstalled. Fetch uninstall section name.
  533. rc = SetupFindFirstLine(cd->hinf,
  534. SubcomponentId,
  535. KEYWORD_UNINSTALL,
  536. &context);
  537. if (rc) {
  538. rc = SetupGetStringField(&context,
  539. 1,
  540. section,
  541. sizeof(section) / sizeof(TCHAR),
  542. NULL);
  543. }
  544. }
  545. if (state) {
  546. //
  547. // installation
  548. //
  549. if (rc) {
  550. // process the inf file
  551. rc = SetupInstallFromInfSection(NULL, // hwndOwner
  552. cd->hinf, // inf handle
  553. section, // name of component
  554. SPINST_ALL & ~SPINST_FILES,
  555. NULL, // relative key root
  556. NULL, // source root path
  557. 0, // copy flags
  558. NULL, // callback routine
  559. NULL, // callback routine context
  560. NULL, // device info set
  561. NULL); // device info struct
  562. if (rc) {
  563. rc = SetupInstallServicesFromInfSection(cd->hinf, section, 0);
  564. Error = GetLastError();
  565. if (!rc && Error == ERROR_SECTION_NOT_FOUND) {
  566. rc = TRUE;
  567. Error = NO_ERROR;
  568. }
  569. if (rc) {
  570. if (Error == ERROR_SUCCESS_REBOOT_REQUIRED) {
  571. cd->HelperRoutines.SetReboot(cd->HelperRoutines.OcManagerContext,TRUE);
  572. }
  573. Error = NO_ERROR;
  574. rc = RunExternalProgram(cd, section, state);
  575. }
  576. }
  577. }
  578. } else {
  579. //
  580. // uninstallation
  581. //
  582. if (rc)
  583. {
  584. rc = RunExternalProgram(cd, section, state);
  585. }
  586. if (rc) {
  587. rc = CleanupNetShares(cd, section, state);
  588. }
  589. }
  590. if (!rc && (Error == NO_ERROR) ) {
  591. Error = GetLastError( );
  592. }
  593. return Error;
  594. }
  595. /*
  596. * OnCleanup()
  597. *
  598. * handler for OC_CLEANUP
  599. */
  600. DWORD OnCleanup()
  601. {
  602. return NO_ERROR;
  603. }
  604. /*
  605. * OnQueryState()
  606. *
  607. * handler for OC_QUERY_STATE
  608. */
  609. DWORD OnQueryState(LPCTSTR ComponentId,
  610. LPCTSTR SubcomponentId,
  611. UINT state)
  612. {
  613. //
  614. // Override default state if MSI provider is already
  615. // present on the system and this is GUI-mode setup
  616. //
  617. PPER_COMPONENT_DATA cd;
  618. if (cd = LocateComponent(ComponentId))
  619. {
  620. if (!(cd->Flags & SETUPOP_STANDALONE))
  621. {
  622. if (state == OCSELSTATETYPE_CURRENT)
  623. {
  624. if (!_wcsicmp(ComponentId, L"wbemmsi") && !_wcsicmp(SubcomponentId, L"wbemmsi"))
  625. {
  626. if (IsMSIProviderPresent())
  627. {
  628. return SubcompOn;
  629. }
  630. }
  631. }
  632. }
  633. }
  634. return SubcompUseOcManagerDefault;
  635. }
  636. /*
  637. * OnNeedMedia()
  638. *
  639. * handler for OC_NEED_MEDIA
  640. */
  641. DWORD OnNeedMedia()
  642. {
  643. return false;
  644. }
  645. /*
  646. * OnAboutToCommitQueue()
  647. *
  648. * handler for OC_ABOUT_TO_COMMIT_QUEUE
  649. */
  650. DWORD OnAboutToCommitQueue(LPCTSTR ComponentId, LPCTSTR SubcomponentId)
  651. {
  652. PPER_COMPONENT_DATA cd;
  653. BOOL state;
  654. BOOL rc;
  655. INFCONTEXT context;
  656. TCHAR section[256];
  657. TCHAR srcpathbuf[256];
  658. TCHAR *srcpath;
  659. if (!(cd = LocateComponent(ComponentId)))
  660. return NO_ERROR;
  661. if (!SubcomponentId || !*SubcomponentId)
  662. return NO_ERROR;
  663. if (!StateInfo(cd, SubcomponentId, &state))
  664. return NO_ERROR;
  665. //
  666. // only do stuff on uninstall
  667. //
  668. if (state) {
  669. return NO_ERROR;
  670. }
  671. // Fetch uninstall section name.
  672. rc = SetupFindFirstLine(
  673. cd->hinf,
  674. SubcomponentId,
  675. KEYWORD_UNINSTALL,
  676. &context);
  677. if (rc) {
  678. rc = SetupGetStringField(
  679. &context,
  680. 1,
  681. section,
  682. sizeof(section) / sizeof(TCHAR),
  683. NULL);
  684. }
  685. if (rc)
  686. rc = SetupInstallServicesFromInfSection(cd->hinf, section, 0);
  687. if (rc) {
  688. rc = SetupInstallFromInfSection(
  689. NULL,
  690. cd->hinf,
  691. section,
  692. SPINST_ALL & ~SPINST_FILES,
  693. NULL,
  694. NULL,
  695. 0,
  696. NULL,
  697. NULL,
  698. NULL,
  699. NULL);
  700. }
  701. if (rc) {
  702. SetLastError(NO_ERROR);
  703. }
  704. return GetLastError();
  705. }
  706. /*
  707. * AddNewComponent()
  708. *
  709. * add new compononent to the top of the component list
  710. */
  711. PPER_COMPONENT_DATA AddNewComponent(LPCTSTR ComponentId)
  712. {
  713. PPER_COMPONENT_DATA data;
  714. data = (PPER_COMPONENT_DATA)LocalAlloc(LPTR,sizeof(PER_COMPONENT_DATA));
  715. if (!data)
  716. return data;
  717. data->ComponentId = (TCHAR *)LocalAlloc(LMEM_FIXED,
  718. (_tcslen(ComponentId) + 1) * sizeof(TCHAR));
  719. if(data->ComponentId)
  720. {
  721. StringCchCopy((TCHAR *)data->ComponentId, (_tcslen(ComponentId) + 1) * sizeof(TCHAR), ComponentId);
  722. // Stick at head of list
  723. data->Next = gcd;
  724. gcd = data;
  725. }
  726. else
  727. {
  728. LocalFree((HLOCAL)data);
  729. data = NULL;
  730. }
  731. return(data);
  732. }
  733. /*
  734. * LocateComponent()
  735. *
  736. * returns a compoent struct that matches the
  737. * passed component id.
  738. */
  739. PPER_COMPONENT_DATA LocateComponent(LPCTSTR ComponentId)
  740. {
  741. PPER_COMPONENT_DATA p;
  742. for (p = gcd; p; p=p->Next)
  743. {
  744. if (!_tcsicmp(p->ComponentId, ComponentId))
  745. return p;
  746. }
  747. return NULL;
  748. }
  749. /*
  750. * RemoveComponent()
  751. *
  752. * yanks a component from our linked list of components
  753. */
  754. VOID RemoveComponent(LPCTSTR ComponentId)
  755. {
  756. PPER_COMPONENT_DATA p, prev;
  757. for (prev = NULL, p = gcd; p; prev = p, p = p->Next)
  758. {
  759. if (!_tcsicmp(p->ComponentId, ComponentId))
  760. {
  761. LocalFree((HLOCAL)p->ComponentId);
  762. if (p->SourcePath)
  763. LocalFree((HLOCAL)p->SourcePath);
  764. if (prev)
  765. prev->Next = p->Next;
  766. else
  767. gcd = p->Next;
  768. LocalFree((HLOCAL)p);
  769. return;
  770. }
  771. }
  772. }
  773. // loads current selection state info into "state" and
  774. // returns whether the selection state was changed
  775. BOOL
  776. StateInfo(
  777. PPER_COMPONENT_DATA cd,
  778. LPCTSTR SubcomponentId,
  779. BOOL *state
  780. )
  781. {
  782. BOOL rc = TRUE;
  783. assert(state);
  784. // otherwise, check for a change in installation state
  785. *state = cd->HelperRoutines.QuerySelectionState(cd->HelperRoutines.OcManagerContext,
  786. SubcomponentId,
  787. OCSELSTATETYPE_CURRENT);
  788. if (*state == cd->HelperRoutines.QuerySelectionState(cd->HelperRoutines.OcManagerContext,
  789. SubcomponentId,
  790. OCSELSTATETYPE_ORIGINAL))
  791. {
  792. // no change
  793. rc = FALSE;
  794. }
  795. // if this is gui mode setup, presume the state has changed to force
  796. // an installation (or uninstallation)
  797. if (!(cd->Flags & SETUPOP_STANDALONE) && *state)
  798. rc = TRUE;
  799. return rc;
  800. }
  801. #if 0
  802. //
  803. // Andrewr -- get rid of RegisterServices and RegisterServers and have the oc gen component use setupapi instead.
  804. // this reduces the amount of redundant code
  805. //
  806. DWORD RegisterServices(
  807. PPER_COMPONENT_DATA cd,
  808. LPCTSTR component,
  809. DWORD state)
  810. {
  811. INFCONTEXT ic;
  812. TCHAR buf[MAX_PATH];
  813. TCHAR path[MAX_PATH];
  814. TCHAR sname[S_SIZE];
  815. TCHAR file[MAX_PATH];
  816. DWORD section;
  817. ULONG size;
  818. pfn pfreg;
  819. HINSTANCE hinst;
  820. HRESULT hr;
  821. TCHAR *keyword;
  822. SC_HANDLE schSystem;
  823. schSystem = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  824. if ( !schSystem ) {
  825. DWORD dwError = GetLastError( );
  826. if( !IsNT() && ( ERROR_CALL_NOT_IMPLEMENTED == dwError ) )
  827. {
  828. return( NO_ERROR );
  829. }
  830. else
  831. {
  832. return( dwError );
  833. }
  834. }
  835. if (state) {
  836. keyword = KEYWORD_ADDSERVICE;
  837. } else {
  838. keyword = KEYWORD_DELSERVICE;
  839. }
  840. for (section = 1;
  841. EnumSections(cd->hinf, component, keyword, section, &ic, sname);
  842. section++)
  843. {
  844. INFCONTEXT sic;
  845. SC_HANDLE schService;
  846. CHAR Temp[SBUF_SIZE];
  847. TCHAR ServiceName[ SBUF_SIZE ];
  848. TCHAR DisplayName[ SBUF_SIZE ];
  849. DWORD ServiceType;
  850. DWORD StartType;
  851. DWORD ErrorControl;
  852. TCHAR ImagePath[ SBUF_SIZE ];
  853. TCHAR LoadOrder[ SBUF_SIZE ];
  854. TCHAR Dependencies[ SBUF_SIZE ];
  855. TCHAR StartName[ SBUF_SIZE ];
  856. TCHAR Password[ SBUF_SIZE ];
  857. BOOL fDisplayName = FALSE;
  858. BOOL fServiceType = FALSE;
  859. BOOL fStartType = FALSE;
  860. BOOL fErrorControl = FALSE;
  861. BOOL fLoadOrder = FALSE;
  862. BOOL fDependencies = FALSE;
  863. BOOL fStartName = FALSE;
  864. BOOL fPassword = FALSE;
  865. BOOL fDontReboot = FALSE;
  866. //
  867. // Must have ServiceName
  868. //
  869. if (!SetupFindFirstLine(cd->hinf, sname, KEYWORD_SERVICENAME, &sic))
  870. {
  871. log( TEXT("OCGEN: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_SERVICENAME );
  872. continue;
  873. }
  874. if (!SetupGetStringField(&sic, 1, ServiceName, SBUF_SIZE, NULL))
  875. {
  876. log( TEXT("OCGEN: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_SERVICENAME );
  877. continue;
  878. }
  879. if (SetupFindFirstLine(cd->hinf, sname, KEYWORD_STARTTYPE, &sic))
  880. {
  881. if (SetupGetStringFieldA(&sic, 1, Temp, SBUF_SIZE, NULL))
  882. {
  883. StartType = atoi( Temp );
  884. fStartType = TRUE;
  885. }
  886. }
  887. if ( state )
  888. {
  889. if (SetupFindFirstLine(cd->hinf, sname, KEYWORD_DISPLAYNAME, &sic))
  890. {
  891. if (SetupGetStringField(&sic, 1, DisplayName, SBUF_SIZE, NULL))
  892. {
  893. fDisplayName = TRUE;
  894. }
  895. }
  896. if (SetupFindFirstLine(cd->hinf, sname, KEYWORD_SERVICETYPE, &sic))
  897. {
  898. if (SetupGetStringFieldA(&sic, 1, Temp, SBUF_SIZE, NULL))
  899. {
  900. ServiceType = atoi( Temp );
  901. fServiceType = TRUE;
  902. }
  903. }
  904. if (SetupFindFirstLine(cd->hinf, sname, KEYWORD_ERRORCONTROL, &sic))
  905. {
  906. if (SetupGetStringFieldA(&sic, 1, Temp, SBUF_SIZE, NULL))
  907. {
  908. ErrorControl = atoi( Temp );
  909. fErrorControl = TRUE;
  910. }
  911. }
  912. //
  913. // Must have ImagePath
  914. //
  915. if (!SetupFindFirstLine(cd->hinf, sname, KEYWORD_IMAGEPATH, &sic))
  916. {
  917. log( TEXT("OCGEN: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_IMAGEPATH );
  918. continue;
  919. }
  920. if (!SetupGetStringField(&sic, 1, ImagePath, SBUF_SIZE, NULL))
  921. {
  922. log( TEXT("OCGEN: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_IMAGEPATH );
  923. continue;
  924. }
  925. if (SetupFindFirstLine(cd->hinf, sname, KEYWORD_LOADORDER, &sic))
  926. {
  927. if (SetupGetStringField(&sic, 1, LoadOrder, SBUF_SIZE, NULL))
  928. {
  929. fLoadOrder = TRUE;
  930. }
  931. }
  932. if (SetupFindFirstLine(cd->hinf, sname, KEYWORD_DEPENDENCIES, &sic))
  933. {
  934. if (SetupGetStringField(&sic, 1, Dependencies, SBUF_SIZE-1, NULL))
  935. {
  936. LPTSTR psz = Dependencies;
  937. // needs to be a double-null terminated string
  938. Dependencies[ lstrlen(Dependencies) + 1] = TEXT('\0');
  939. // change commas into NULL characters
  940. while ( *psz )
  941. {
  942. if ( *psz == TEXT(',') )
  943. {
  944. *psz = TEXT('\0');
  945. }
  946. psz++;
  947. }
  948. fDependencies = TRUE;
  949. }
  950. }
  951. if (SetupFindFirstLine(cd->hinf, sname, KEYWORD_STARTNAME, &sic))
  952. {
  953. if (SetupGetStringField(&sic, 1, StartName, SBUF_SIZE, NULL))
  954. {
  955. fStartName = TRUE;
  956. }
  957. }
  958. if (SetupFindFirstLine(cd->hinf, sname, KEYWORD_PASSWORD, &sic))
  959. {
  960. if (SetupGetStringField(&sic, 1, Password, SBUF_SIZE, NULL))
  961. {
  962. fPassword = TRUE;
  963. }
  964. }
  965. schService = CreateService(
  966. schSystem,
  967. ServiceName,
  968. ( fDisplayName == TRUE ? DisplayName : ServiceName ),
  969. STANDARD_RIGHTS_REQUIRED | SERVICE_START,
  970. ( fServiceType == TRUE ? ServiceType : SERVICE_WIN32_OWN_PROCESS),
  971. ( fStartType == TRUE ? StartType : SERVICE_AUTO_START),
  972. ( fErrorControl == TRUE ? ErrorControl : SERVICE_ERROR_NORMAL),
  973. ImagePath,
  974. (fLoadOrder == TRUE ? LoadOrder : NULL),
  975. NULL, // tag id
  976. ( fDependencies == TRUE ? Dependencies : NULL ),
  977. ( fStartName == TRUE ? StartName : NULL),
  978. ( fPassword == TRUE ? Password : NULL ));
  979. if ( !schService )
  980. {
  981. DWORD Error = GetLastError( );
  982. log( TEXT("OCGEN: CreateService() error 0x%08x\r\n"), Error );
  983. return Error;
  984. }
  985. if ( (!fStartType)
  986. || ( fStartType && StartType == SERVICE_AUTO_START ))
  987. {
  988. if( !StartService( schService, 0, NULL ) )
  989. {
  990. DWORD Error = GetLastError( );
  991. switch ( Error )
  992. {
  993. case ERROR_SERVICE_EXISTS:
  994. {
  995. log( TEXT("OCGEN: %s was already exists.\r\n"), ServiceName );
  996. if ( fStartType && StartType == SERVICE_BOOT_START )
  997. {
  998. fDontReboot = TRUE;
  999. }
  1000. }
  1001. break;
  1002. case ERROR_SERVICE_ALREADY_RUNNING:
  1003. {
  1004. log( TEXT("OCGEN: %s was already started.\r\n"), ServiceName );
  1005. if ( fStartType && StartType == SERVICE_BOOT_START )
  1006. {
  1007. fDontReboot = TRUE;
  1008. }
  1009. }
  1010. break;
  1011. default:
  1012. log( TEXT("OCGEN: StartService() error 0x%08x\r\n"), Error );
  1013. return Error;
  1014. }
  1015. }
  1016. }
  1017. }
  1018. else
  1019. {
  1020. schService = OpenService( schSystem,
  1021. ServiceName,
  1022. STANDARD_RIGHTS_REQUIRED | DELETE );
  1023. if ( schService )
  1024. {
  1025. SERVICE_STATUS ss;
  1026. DeleteService( schService );
  1027. ControlService( schService, SERVICE_CONTROL_STOP, &ss );
  1028. }
  1029. }
  1030. //
  1031. // BOOT drivers require a reboot unless they were already started.
  1032. //
  1033. if ( schService
  1034. && fStartType && StartType == SERVICE_BOOT_START
  1035. && fDontReboot == FALSE)
  1036. {
  1037. cd->HelperRoutines.SetReboot(cd->HelperRoutines.OcManagerContext, NULL);
  1038. }
  1039. if ( schService )
  1040. {
  1041. CloseServiceHandle( schService );
  1042. }
  1043. }
  1044. return NO_ERROR;
  1045. }
  1046. #endif
  1047. #if 0
  1048. DWORD
  1049. RegisterServers(
  1050. HINF hinf,
  1051. LPCTSTR component,
  1052. DWORD state
  1053. )
  1054. {
  1055. INFCONTEXT ic;
  1056. TCHAR buf[MAX_PATH];
  1057. TCHAR path[MAX_PATH];
  1058. TCHAR sname[S_SIZE];
  1059. TCHAR file[MAX_PATH];
  1060. DWORD section;
  1061. ULONG size;
  1062. pfn pfreg;
  1063. HINSTANCE hinst;
  1064. HRESULT hr;
  1065. TCHAR *keyword;
  1066. LPCSTR routine;
  1067. CoInitialize(NULL);
  1068. if (state) {
  1069. keyword = KEYWORD_REGSVR;
  1070. routine = (LPCSTR)gszRegisterSvrRoutine;
  1071. } else {
  1072. keyword = KEYWORD_UNREGSVR;
  1073. routine = (LPCSTR)gszUnregisterSvrRoutine;
  1074. }
  1075. for (section = 1;
  1076. EnumSections(hinf, component, keyword, section, &ic, sname);
  1077. section++)
  1078. {
  1079. if (!SetupGetTargetPath(hinf, NULL, sname, path, sizeof(path), &size))
  1080. continue;
  1081. PathAddBackslash(path);
  1082. do {
  1083. // get fully qualified path to dll to register
  1084. if (!SetupGetStringField(&ic, 0, buf, sizeof(buf)/sizeof(buf[0]), NULL))
  1085. continue;
  1086. _tcscpy(file, path);
  1087. _tcscat(file, buf);
  1088. // call the dll's RegisterServer routine
  1089. if (!(hinst = LoadLibrary(file)))
  1090. continue;
  1091. if (!(pfreg = (pfn)GetProcAddress(hinst, routine)))
  1092. continue;
  1093. hr = pfreg();
  1094. assert(hr == NO_ERROR);
  1095. FreeLibrary(hinst);
  1096. // on to the next
  1097. } while (SetupFindNextLine(&ic, &ic));
  1098. }
  1099. CoUninitialize();
  1100. return TRUE;
  1101. }
  1102. #endif
  1103. /*
  1104. * EnumSections()
  1105. *
  1106. * finds the name of a section for a specified keyword
  1107. */
  1108. DWORD
  1109. EnumSections(
  1110. HINF hinf,
  1111. const TCHAR *component,
  1112. const TCHAR *key,
  1113. DWORD index,
  1114. INFCONTEXT *pic,
  1115. TCHAR *name
  1116. )
  1117. {
  1118. TCHAR section[S_SIZE];
  1119. if (!SetupFindFirstLine(hinf, component, NULL, pic))
  1120. return 0;
  1121. if (!SetupFindNextMatchLine(pic, key, pic))
  1122. return 0;
  1123. if (index > SetupGetFieldCount(pic))
  1124. return 0;
  1125. if (!SetupGetStringField(pic, index, section, sizeof(section)/sizeof(section[0]), NULL))
  1126. return 0;
  1127. if (name)
  1128. StringCchCopy(name, S_SIZE, section); // "name" buffer was allocated elsewhere and is S_SIZE characters in size
  1129. return SetupFindFirstLine(hinf, section, NULL, pic);
  1130. }
  1131. DWORD
  1132. OcLog(
  1133. LPCTSTR ComponentId,
  1134. UINT level,
  1135. LPCTSTR sz
  1136. )
  1137. {
  1138. TCHAR fmt[5000];
  1139. PPER_COMPONENT_DATA cd;
  1140. if (!(cd = LocateComponent(ComponentId)))
  1141. return NO_ERROR;
  1142. assert(cd->ExtraRoutines.LogError);
  1143. assert(level);
  1144. assert(sz);
  1145. StringCchCopy(fmt, 5000, TEXT("%s: %s"));
  1146. return cd->ExtraRoutines.LogError(cd->HelperRoutines.OcManagerContext,
  1147. level,
  1148. fmt,
  1149. ComponentId,
  1150. sz);
  1151. }
  1152. DWORD
  1153. CleanupNetShares(
  1154. PPER_COMPONENT_DATA cd,
  1155. LPCTSTR component,
  1156. DWORD state)
  1157. {
  1158. INFCONTEXT ic;
  1159. TCHAR sname[S_SIZE];
  1160. DWORD section;
  1161. TCHAR *keyword;
  1162. if (state) {
  1163. return NO_ERROR;
  1164. } else {
  1165. keyword = KEYWORD_DELSHARE;
  1166. }
  1167. for (section = 1;
  1168. EnumSections(cd->hinf, component, keyword, section, &ic, sname);
  1169. section++)
  1170. {
  1171. INFCONTEXT sic;
  1172. NET_API_STATUS netStat;
  1173. CHAR Temp[SBUF_SIZE];
  1174. TCHAR ShareName[ SBUF_SIZE ];
  1175. if (!SetupFindFirstLine(cd->hinf, sname, KEYWORD_SHARENAME, &sic))
  1176. {
  1177. log( TEXT("OCGEN: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_SHARENAME );
  1178. continue;
  1179. }
  1180. if (!SetupGetStringField(&sic, 1, ShareName, SBUF_SIZE, NULL))
  1181. {
  1182. log( TEXT("OCGEN: %s INF error - incorrect %s line\r\n"), keyword, KEYWORD_SHARENAME );
  1183. continue;
  1184. }
  1185. #ifdef UNICODE
  1186. netStat = NetShareDel( NULL, ShareName, 0 );
  1187. #else // UNICODE
  1188. WCHAR ShareNameW[ SBUF_SIZE ];
  1189. mbstowcs( ShareNameW, ShareName, lstrlen(ShareName));
  1190. netStat = NetShareDel( NULL, ShareNameW, 0 );
  1191. #endif // UNICODE
  1192. if ( netStat != NERR_Success )
  1193. {
  1194. log( TEXT("OCGEN: Failed to remove %s share. Error 0x%08x\r\n"), ShareName, netStat );
  1195. continue;
  1196. }
  1197. log( TEXT("OCGEN: %s share removed successfully.\r\n"), ShareName );
  1198. }
  1199. return TRUE;
  1200. }
  1201. DWORD
  1202. RunExternalProgram(
  1203. PPER_COMPONENT_DATA cd,
  1204. LPCTSTR component,
  1205. DWORD state)
  1206. {
  1207. INFCONTEXT ic;
  1208. TCHAR sname[S_SIZE];
  1209. DWORD section;
  1210. TCHAR *keyword;
  1211. keyword = KEYWORD_RUN;
  1212. for (section = 1;
  1213. EnumSections(cd->hinf, component, keyword, section, &ic, sname);
  1214. section++)
  1215. {
  1216. INFCONTEXT sic;
  1217. TCHAR CommandLine[ SBUF_SIZE ];
  1218. CHAR szTickCount[ SBUF_SIZE ];
  1219. ULONG TickCount;
  1220. BOOL b;
  1221. STARTUPINFO startupinfo;
  1222. PROCESS_INFORMATION process_information;
  1223. DWORD dwErr;
  1224. if (!SetupFindFirstLine(cd->hinf, sname, KEYWORD_COMMANDLINE , &sic))
  1225. {
  1226. log( TEXT("OCGEN: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_COMMANDLINE );
  1227. continue;
  1228. }
  1229. if (!SetupGetStringField(&sic, 1, CommandLine, SBUF_SIZE, NULL))
  1230. {
  1231. log( TEXT("OCGEN: %s INF error - incorrect %s line\r\n"), keyword, KEYWORD_COMMANDLINE );
  1232. continue;
  1233. }
  1234. if (!SetupFindFirstLine(cd->hinf, sname, KEYWORD_TICKCOUNT, &sic))
  1235. {
  1236. log( TEXT("OCGEN: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_TICKCOUNT );
  1237. continue;
  1238. }
  1239. if (!SetupGetStringFieldA(&sic, 1, szTickCount, SBUF_SIZE, NULL))
  1240. {
  1241. log( TEXT("OCGEN: %s INF error - incorrect %s line\r\n"), keyword, KEYWORD_TICKCOUNT );
  1242. continue;
  1243. }
  1244. TickCount = atoi( szTickCount );
  1245. ZeroMemory( &startupinfo, sizeof(startupinfo) );
  1246. startupinfo.cb = sizeof(startupinfo);
  1247. startupinfo.dwFlags = STARTF_USESHOWWINDOW;
  1248. startupinfo.wShowWindow = SW_HIDE | SW_SHOWMINNOACTIVE;
  1249. b = CreateProcess( NULL,
  1250. CommandLine,
  1251. NULL,
  1252. NULL,
  1253. FALSE,
  1254. CREATE_DEFAULT_ERROR_MODE,
  1255. NULL,
  1256. NULL,
  1257. &startupinfo,
  1258. &process_information );
  1259. if ( !b )
  1260. {
  1261. log( TEXT("OCGEN: failed to spawn %s process.\r\n"), CommandLine );
  1262. continue;
  1263. }
  1264. dwErr = WaitForSingleObject( process_information.hProcess, TickCount * 1000 );
  1265. if ( dwErr != NO_ERROR )
  1266. {
  1267. log( TEXT("OCGEN: WaitForSingleObject() failed. Error 0x%08x\r\n"), dwErr );
  1268. TerminateProcess( process_information.hProcess, -1 );
  1269. CloseHandle( process_information.hProcess );
  1270. CloseHandle( process_information.hThread );
  1271. continue;
  1272. }
  1273. CloseHandle( process_information.hProcess );
  1274. CloseHandle( process_information.hThread );
  1275. log( TEXT("OCGEN: %s successfully completed within %u seconds.\r\n"), CommandLine, TickCount );
  1276. }
  1277. return TRUE;
  1278. }
  1279. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1280. //
  1281. // Determine prior install status of WMI components
  1282. //
  1283. #define WBEM_REG_KEY L"SOFTWARE\\Microsoft\\WBEM"
  1284. #define INSTALL_DIR L"Installation Directory"
  1285. #define MSI_PROVIDER L"msiprov.dll"
  1286. #define CLSID_KEY L"Software\\classes\\CLSID"
  1287. #define CLSID_MSIPROV L"{BE0A9830-2B8B-11D1-A949-0060181EBBAD}"
  1288. bool IsMSIProviderPresent()
  1289. {
  1290. bool bRet = false;
  1291. //
  1292. // First check for the present of the provider dll
  1293. //
  1294. HKEY hKey;
  1295. long lRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WBEM_REG_KEY, 0, KEY_READ, &hKey);
  1296. if(ERROR_SUCCESS == lRes)
  1297. {
  1298. WCHAR wszTmp[MAX_PATH + 1];
  1299. DWORD dwLen = (MAX_PATH + 1)*sizeof(WCHAR);
  1300. lRes = RegQueryValueEx(hKey, INSTALL_DIR, NULL, NULL, (LPBYTE)wszTmp, &dwLen);
  1301. RegCloseKey(hKey);
  1302. if(ERROR_SUCCESS == lRes)
  1303. {
  1304. WCHAR wszPath[MAX_PATH + 1];
  1305. if (ExpandEnvironmentStrings(wszTmp, wszPath, MAX_PATH + 1))
  1306. {
  1307. StringCchCat(wszPath, MAX_PATH + 1, L"\\" MSI_PROVIDER);
  1308. DWORD dwAttribs = GetFileAttributes(wszPath);
  1309. if (dwAttribs != 0xFFFFFFFF)
  1310. {
  1311. //
  1312. // The file exists, now check for its CLSID in the registry
  1313. //
  1314. WCHAR wszCLSIDKey[62]; // entire key is 61 characters long
  1315. StringCchCopy(wszCLSIDKey, 62, CLSID_KEY L"\\");
  1316. StringCchCat(wszCLSIDKey, 62, CLSID_MSIPROV);
  1317. lRes = RegOpenKey(HKEY_LOCAL_MACHINE, wszCLSIDKey, &hKey);
  1318. if(ERROR_SUCCESS == lRes)
  1319. {
  1320. RegCloseKey(hKey);
  1321. //
  1322. // Both the file and the CLSID exist, so the provider is installed
  1323. //
  1324. bRet = true;
  1325. }
  1326. }
  1327. }
  1328. }
  1329. }
  1330. return bRet;
  1331. }