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.

1010 lines
29 KiB

  1. //*************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation 1998-2000
  4. // All rights reserved
  5. //
  6. // apis.cxx
  7. //
  8. //*************************************************************
  9. #include "appmgmt.hxx"
  10. static CLoadMsi * gLoadMsi = 0;
  11. static WCHAR * gpwszWinsta = 0;
  12. static DWORD ReportInstallStatus(
  13. PINSTALLCONTEXT pInstallContext,
  14. DWORD InstallStatus,
  15. BOOL bUninstall,
  16. WCHAR * pwszDeploymentName,
  17. WCHAR * pwszGPOName,
  18. WCHAR * pwszDeploymentId
  19. );
  20. DWORD WINAPI
  21. InstallApplication(
  22. IN PINSTALLDATA pInstallData
  23. )
  24. {
  25. APPKEY AppKey;
  26. HINSTANCE hMsi;
  27. MSICONFIGUREPRODUCTEXW * pfnConfigureProduct;
  28. PINSTALLCONTEXT pInstallContext;
  29. APPLICATION_INFO InstallInfo;
  30. UNINSTALL_APPS UninstallApps;
  31. DWORD InstallUILevel;
  32. INSTALLUILEVEL OldUILevel;
  33. DWORD UninstallCount;
  34. DWORD n;
  35. DWORD ExtraStatus;
  36. DWORD Status;
  37. BOOL bStatus;
  38. boolean bInstall;
  39. Status = Bind();
  40. if ( Status != ERROR_SUCCESS )
  41. return Status;
  42. if ( DebugLevelOn(DM_VERBOSE) )
  43. {
  44. WCHAR * pwszCommandLine;
  45. WCHAR UserName[32];
  46. DWORD NameLength;
  47. NameLength = sizeof(UserName) / sizeof(WCHAR);
  48. UserName[0] = 0;
  49. GetUserName( UserName, &NameLength );
  50. pwszCommandLine = GetCommandLine();
  51. if ( ! pwszCommandLine )
  52. pwszCommandLine = L"";
  53. DebugMsg((DM_VERBOSE, IDS_INSTALL_REQUEST, pwszCommandLine, UserName));
  54. }
  55. AppKey.Type = pInstallData->Type;
  56. AppKey.ProcessorArchitecture = DEFAULT_ARCHITECTURE;
  57. switch ( pInstallData->Type )
  58. {
  59. case APPNAME :
  60. AppKey.uType.AppName.Name = pInstallData->Spec.AppName.Name;
  61. memcpy( &AppKey.uType.AppName.PolicyId, &pInstallData->Spec.AppName.GPOId, sizeof(GUID) );
  62. break;
  63. case FILEEXT :
  64. AppKey.uType.FileExt = pInstallData->Spec.FileExt;
  65. break;
  66. case PROGID :
  67. AppKey.uType.ProgId = pInstallData->Spec.ProgId;
  68. break;
  69. case COMCLASS :
  70. AppKey.uType.COMClass.Clsid = pInstallData->Spec.COMClass.Clsid;
  71. AppKey.uType.COMClass.ClsCtx = pInstallData->Spec.COMClass.ClsCtx;
  72. break;
  73. default :
  74. return ERROR_INVALID_PARAMETER;
  75. }
  76. pInstallContext = 0;
  77. memset( &InstallInfo, 0, sizeof(InstallInfo) );
  78. memset( &UninstallApps, 0, sizeof(UninstallApps) );
  79. Status = InstallBegin(
  80. ghRpc,
  81. &AppKey,
  82. &pInstallContext,
  83. &InstallInfo,
  84. &UninstallApps );
  85. if ( Status != ERROR_SUCCESS )
  86. return Status;
  87. CLoadMsi LoadMsi( Status );
  88. if ( Status != ERROR_SUCCESS )
  89. goto InstallApplicationExit;
  90. if ( InstallInfo.pwszSetupCommand )
  91. {
  92. HINSTANCE hShell32;
  93. SHELLEXECUTEEXW * pfnShellExecuteEx;
  94. SHELLEXECUTEINFO ShellExInfo;
  95. WCHAR * pwszCommand;
  96. WCHAR * pwszParams;
  97. WCHAR * pwszDirectory;
  98. pwszDirectory = NULL;
  99. pfnShellExecuteEx = 0;
  100. hShell32 = LoadLibrary( L"shell32.dll" );
  101. if ( hShell32 )
  102. pfnShellExecuteEx = (SHELLEXECUTEEXW *) GetProcAddress( hShell32, "ShellExecuteExW" );
  103. if ( ! pfnShellExecuteEx )
  104. Status = GetLastError();
  105. if ( ERROR_SUCCESS == Status )
  106. {
  107. pwszCommand = InstallInfo.pwszSetupCommand;
  108. if ( L'"' == pwszCommand[0] )
  109. {
  110. pwszParams = wcschr( &pwszCommand[1], L'"' );
  111. if ( pwszParams )
  112. pwszCommand++;
  113. }
  114. else
  115. {
  116. pwszParams = wcschr( pwszCommand, L' ' );
  117. }
  118. if ( pwszParams )
  119. {
  120. *pwszParams++ = 0;
  121. while ( L' ' == *pwszParams )
  122. pwszParams++;
  123. }
  124. }
  125. //
  126. // Need to set the current directory to that
  127. // containing the actual executable
  128. //
  129. if ( ERROR_SUCCESS == Status )
  130. {
  131. WCHAR* pwszDirectoryEnd;
  132. //
  133. // Find the last pathsep, which marks the
  134. // end of the containing directory -- if we
  135. // don't find it, the admin specified some strange
  136. // path and we'll just end up passing NULL for
  137. // the current directory
  138. //
  139. pwszDirectoryEnd = wcsrchr( pwszCommand, L'\\' );
  140. if ( pwszDirectoryEnd )
  141. {
  142. //
  143. // Get a copy of the full path that we can
  144. // truncate to the containing directory
  145. //
  146. pwszDirectory = StringDuplicate( pwszCommand );
  147. if ( pwszDirectory )
  148. {
  149. //
  150. // Truncate to the containing directory
  151. //
  152. pwszDirectory[ pwszDirectoryEnd - pwszCommand ] = L'\0';
  153. }
  154. else
  155. {
  156. Status = ERROR_OUTOFMEMORY;
  157. }
  158. }
  159. }
  160. if ( ERROR_SUCCESS == Status )
  161. {
  162. ShellExInfo.cbSize = sizeof( ShellExInfo );
  163. ShellExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
  164. ShellExInfo.hwnd = NULL;
  165. ShellExInfo.lpVerb = NULL;
  166. ShellExInfo.lpFile = pwszCommand;
  167. ShellExInfo.lpParameters = pwszParams;
  168. ShellExInfo.lpDirectory = pwszDirectory;
  169. ShellExInfo.nShow = SW_SHOWNORMAL;
  170. ShellExInfo.hProcess = 0;
  171. DebugMsg((DM_VERBOSE, IDS_LEGACY_INSTALL, pwszCommand));
  172. bStatus = (*pfnShellExecuteEx)( &ShellExInfo );
  173. if ( ! bStatus )
  174. Status = GetLastError();
  175. }
  176. delete [] pwszDirectory;
  177. if ( hShell32 )
  178. FreeLibrary( hShell32 );
  179. if ( (ERROR_SUCCESS == Status) && ShellExInfo.hProcess )
  180. {
  181. Status = WAIT_OBJECT_0;
  182. if ( LoadUser32Funcs() )
  183. {
  184. MSG msg;
  185. HANDLE Handles[2];
  186. Handles[0] = ShellExInfo.hProcess;
  187. for (;;)
  188. {
  189. Status = (*pfnMsgWaitForMultipleObjects)( 1, Handles, FALSE, INFINITE, QS_ALLINPUT );
  190. if ( (WAIT_OBJECT_0+1) == Status )
  191. {
  192. if ( (*pfnPeekMessageW)( &msg, NULL, 0, 0, PM_REMOVE) )
  193. {
  194. (*pfnTranslateMessage)( &msg );
  195. (*pfnDispatchMessageW)( &msg );
  196. }
  197. continue;
  198. }
  199. break;
  200. }
  201. }
  202. CloseHandle( ShellExInfo.hProcess );
  203. if ( WAIT_OBJECT_0 == Status )
  204. Status = ERROR_SUCCESS;
  205. else
  206. Status = GetLastError();
  207. }
  208. gpEvents->ZAPInstall(
  209. Status,
  210. InstallInfo.pwszDeploymentName,
  211. InstallInfo.pwszGPOName,
  212. pwszCommand );
  213. goto InstallApplicationExit;
  214. }
  215. OldUILevel = (*gpfnMsiSetInternalUI)( INSTALLUILEVEL_NOCHANGE, NULL );
  216. if ( UninstallApps.Products > 0 )
  217. (*gpfnMsiSetInternalUI)( INSTALLUILEVEL_BASIC, NULL );
  218. for ( UninstallCount = 0; UninstallCount < UninstallApps.Products; )
  219. {
  220. if ( UninstallApps.ApplicationInfo[UninstallCount].Flags & APPINFOFLAG_UNINSTALL )
  221. {
  222. DebugMsg((DM_VERBOSE, IDS_UNINSTALL, UninstallApps.ApplicationInfo[UninstallCount].pwszDeploymentName, UninstallApps.ApplicationInfo[UninstallCount].pwszGPOName));
  223. //
  224. // The MsiQueryProductState could fail due to out of memory -- it could
  225. // return INSTALL_STATE_UNKNOWN in out of memory situations, and we would incorrectly
  226. // unmanage the application -- so we use MsiGetProductInfo which returns a status
  227. // that allows us to distinguish these cases
  228. //
  229. Status = gpfnMsiGetProductInfo(
  230. UninstallApps.ApplicationInfo[UninstallCount].pwszProductCode,
  231. INSTALLPROPERTY_PACKAGECODE,
  232. NULL,
  233. NULL);
  234. //
  235. // If the product is installed, try to uninstall. If it exists but has
  236. // bad configuration data, attempt the uninstall anyway in the hope that
  237. // it will get removed
  238. //
  239. if ( ( ERROR_SUCCESS == Status ) ||
  240. ( ERROR_BAD_CONFIGURATION == Status ) )
  241. {
  242. //
  243. // ERROR_SUCCESS_REBOOT_INITIATED here will be treated as an error
  244. // since we don't want to attempt to do an install if the machine
  245. // is being rebooted.
  246. // The two REJECTED errors can be encountered when the application is
  247. // only advertised and is prevented from (un)installing by policy.
  248. //
  249. Status = (*gpfnMsiConfigureProductEx)( UninstallApps.ApplicationInfo[UninstallCount].pwszProductCode, INSTALLLEVEL_MAXIMUM, INSTALLSTATE_ABSENT, NULL );
  250. if ( ERROR_SUCCESS_REBOOT_REQUIRED == Status )
  251. {
  252. Status = ERROR_SUCCESS;
  253. }
  254. else if ( (ERROR_INSTALL_PACKAGE_REJECTED == Status) ||
  255. (ERROR_INSTALL_TRANSFORM_REJECTED == Status) )
  256. {
  257. Status = InstallUnmanageApp( pInstallContext, UninstallApps.ApplicationInfo[UninstallCount].pwszDeploymentId, TRUE );
  258. }
  259. }
  260. else if ( ERROR_UNKNOWN_PRODUCT == Status )
  261. {
  262. //
  263. // If we didn't find the product, treat this as a successful removal
  264. // since the desired state, absence of the app, is achieved.
  265. //
  266. Status = ERROR_SUCCESS;
  267. }
  268. ReportInstallStatus(
  269. pInstallContext,
  270. Status,
  271. TRUE,
  272. UninstallApps.ApplicationInfo[UninstallCount].pwszDeploymentName,
  273. UninstallApps.ApplicationInfo[UninstallCount].pwszGPOName,
  274. UninstallApps.ApplicationInfo[UninstallCount].pwszDeploymentId);
  275. }
  276. // Nothing to do here for an orphaned app.
  277. if ( ERROR_SUCCESS == Status )
  278. UninstallCount++;
  279. if ( Status != ERROR_SUCCESS )
  280. goto InstallApplicationRollback;
  281. }
  282. Status = InstallManageApp( pInstallContext, InstallInfo.pwszDeploymentId, ERROR_SUCCESS, &bInstall );
  283. if ( Status != ERROR_SUCCESS )
  284. goto InstallApplicationRollback;
  285. if ( InstallInfo.Flags & APPINFOFLAG_FULLUI )
  286. InstallUILevel = INSTALLUILEVEL_FULL;
  287. else // InstallInfo.Flags & APPINFOFLAG_BASICUI
  288. InstallUILevel = INSTALLUILEVEL_BASIC;
  289. if ( (APPNAME == pInstallData->Type) && (InstallInfo.Flags & APPINFOFLAG_BASICUI) )
  290. InstallUILevel |= INSTALLUILEVEL_ENDDIALOG;
  291. (void) (*gpfnMsiSetInternalUI)( (INSTALLUILEVEL) InstallUILevel, NULL );
  292. if ( InstallInfo.pwszDescriptor )
  293. {
  294. DebugMsg((DM_VERBOSE, IDS_INSTALL_DESC, InstallInfo.pwszDeploymentName, InstallInfo.pwszGPOName));
  295. Status = (*gpfnMsiProvideComponentFromDescriptor)( InstallInfo.pwszDescriptor, NULL, NULL, NULL );
  296. REMAP_DARWIN_STATUS( Status );
  297. ReportInstallStatus(
  298. pInstallContext,
  299. Status,
  300. FALSE,
  301. InstallInfo.pwszDeploymentName,
  302. InstallInfo.pwszGPOName,
  303. InstallInfo.pwszDeploymentId);
  304. }
  305. else
  306. {
  307. DebugMsg((DM_VERBOSE, IDS_INSTALL_PC, InstallInfo.pwszDeploymentName, InstallInfo.pwszGPOName));
  308. Status = (*gpfnMsiConfigureProductEx)( InstallInfo.pwszProductCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, NULL );
  309. REMAP_DARWIN_STATUS( Status );
  310. ReportInstallStatus(
  311. pInstallContext,
  312. Status,
  313. FALSE,
  314. InstallInfo.pwszDeploymentName,
  315. InstallInfo.pwszGPOName,
  316. InstallInfo.pwszDeploymentId);
  317. }
  318. (void) (*gpfnMsiSetInternalUI)( OldUILevel, NULL );
  319. //
  320. // If the added app was already managed, any error must be ignored, we don't want to
  321. // unmanage it in this case. Darwin rollback & repair should handle these cases.
  322. //
  323. if ( (Status != ERROR_SUCCESS) && (InstallInfo.Flags & APPINFOFLAG_ALREADYMANAGED) )
  324. goto InstallApplicationExit;
  325. if ( ERROR_SUCCESS == Status )
  326. {
  327. //
  328. // Now we can finally unmanage any upgraded apps.
  329. // If these fail, it will be fixed up in a subsequent run of policy.
  330. //
  331. for ( n = 0; n < UninstallCount; n++ )
  332. ExtraStatus = InstallUnmanageApp( pInstallContext, UninstallApps.ApplicationInfo[n].pwszDeploymentId, FALSE );
  333. goto InstallApplicationExit;
  334. }
  335. //
  336. // Failed to install the new app, unmanage it and fall through to our rollback.
  337. //
  338. ExtraStatus = InstallUnmanageApp( pInstallContext, InstallInfo.pwszDeploymentId, FALSE );
  339. InstallApplicationRollback:
  340. for ( n = 0; n < UninstallCount; n++ )
  341. {
  342. bInstall = FALSE;
  343. ExtraStatus = InstallManageApp( pInstallContext, UninstallApps.ApplicationInfo[n].pwszDeploymentId, Status, &bInstall );
  344. if ( (ERROR_SUCCESS == ExtraStatus) && bInstall )
  345. {
  346. (void) (*gpfnMsiConfigureProductEx)( UninstallApps.ApplicationInfo[n].pwszProductCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, NULL );
  347. gpEvents->Install( Status, UninstallApps.ApplicationInfo[n].pwszDeploymentName, UninstallApps.ApplicationInfo[n].pwszGPOName );
  348. }
  349. }
  350. InstallApplicationExit:
  351. if ( pInstallContext )
  352. InstallEnd( (Status == ERROR_SUCCESS), &pInstallContext );
  353. FreeApplicationInfo( &InstallInfo );
  354. while ( UninstallApps.Products )
  355. FreeApplicationInfo( &UninstallApps.ApplicationInfo[--UninstallApps.Products] );
  356. LocalFree( UninstallApps.ApplicationInfo );
  357. return Status;
  358. }
  359. DWORD WINAPI
  360. UninstallApplication(
  361. IN WCHAR * ProductCode,
  362. IN DWORD dwStatus
  363. )
  364. {
  365. DWORD Status;
  366. Status = Bind();
  367. if ( Status != ERROR_SUCCESS )
  368. return Status;
  369. return ARPRemoveApp( ghRpc, ProductCode, dwStatus );
  370. }
  371. DWORD WINAPI
  372. CommandLineFromMsiDescriptor(
  373. IN WCHAR * Descriptor,
  374. OUT WCHAR * CommandLine,
  375. IN OUT DWORD * CommandLineLength
  376. )
  377. {
  378. INSTALLUILEVEL NewUILevel;
  379. INSTALLUILEVEL OldUILevel;
  380. HKEY hkAppmgmt;
  381. WCHAR ProductCode[40];
  382. DWORD Size;
  383. DWORD ArgStart;
  384. DWORD Status;
  385. Status = ERROR_SUCCESS;
  386. //
  387. // For this api we can not affort to dynamically load/unload msi each time, it
  388. // is just called too frequently.
  389. // We'll store the load object in a global rather then a static in case we
  390. // add support for a call-in mechanism to free this.
  391. //
  392. if ( ! gLoadMsi )
  393. gLoadMsi = new CLoadMsi( Status );
  394. if ( gLoadMsi && (Status != ERROR_SUCCESS) )
  395. {
  396. delete gLoadMsi;
  397. gLoadMsi = 0;
  398. }
  399. if ( Status != ERROR_SUCCESS )
  400. return Status;
  401. if ( ! LoadUser32Funcs() )
  402. return ERROR_OUTOFMEMORY;
  403. //
  404. // We get the process window station in order to detect processes running
  405. // in non-interactive desktops where Darwin UI is not possible. Darwin
  406. // itself is not aware of these situations.
  407. //
  408. if ( ! gpwszWinsta )
  409. {
  410. HWINSTA hWinsta;
  411. BOOL bStatus;
  412. hWinsta = (*pfnGetProcessWindowStation)();
  413. if ( hWinsta )
  414. {
  415. Size = 0;
  416. (void) (*pfnGetUserObjectInformationW)( hWinsta, UOI_NAME, NULL, 0, &Size );
  417. gpwszWinsta = new WCHAR[Size/2];
  418. if ( gpwszWinsta )
  419. {
  420. bStatus = (*pfnGetUserObjectInformationW)( hWinsta, UOI_NAME, gpwszWinsta, Size, &Size );
  421. if ( ! bStatus )
  422. {
  423. Status = GetLastError();
  424. delete [] gpwszWinsta;
  425. gpwszWinsta = 0;
  426. }
  427. }
  428. else
  429. Status = ERROR_OUTOFMEMORY;
  430. (*pfnCloseWindowStation)( hWinsta );
  431. }
  432. //
  433. // Since this code was added very late (just before nt5 rc3) we don't
  434. // treat an error in getting the window station handle as a failure in
  435. // this API. Too many unknowns with the security configuration of
  436. // services. We'll treat this case as a non-winsta0 process.
  437. //
  438. }
  439. if ( Status != ERROR_SUCCESS )
  440. return Status;
  441. //
  442. // If we can't grab the winsta handle or can confirm that this is a
  443. // non-winsta0 process, we fix the ui level to none.
  444. //
  445. if ( (0 == gpwszWinsta) || (lstrcmp( L"WinSta0", gpwszWinsta ) != 0) )
  446. (*gpfnMsiSetInternalUI)( INSTALLUILEVEL_NONE, NULL );
  447. OldUILevel = (*gpfnMsiSetInternalUI)( INSTALLUILEVEL_NOCHANGE, NULL );
  448. //
  449. // Some processes, like the dcom service, may not be able to handle UI
  450. // of any kind. So if the UI level is currently set to none we never
  451. // change it.
  452. //
  453. if ( OldUILevel != INSTALLUILEVEL_NONE )
  454. {
  455. Status = (*gpfnMsiDecomposeDescriptor)(
  456. Descriptor,
  457. ProductCode,
  458. NULL,
  459. NULL,
  460. NULL );
  461. if ( Status != ERROR_SUCCESS )
  462. return Status;
  463. Status = RegOpenKeyEx(
  464. HKEY_CURRENT_USER,
  465. APPMGMTKEY,
  466. 0,
  467. KEY_READ,
  468. &hkAppmgmt );
  469. if ( ERROR_SUCCESS == Status )
  470. {
  471. Size = sizeof( NewUILevel );
  472. Status = RegQueryValueEx(
  473. hkAppmgmt,
  474. ProductCode,
  475. NULL,
  476. NULL,
  477. (PBYTE) &NewUILevel,
  478. &Size );
  479. RegCloseKey( hkAppmgmt );
  480. }
  481. if ( ERROR_SUCCESS == Status )
  482. (*gpfnMsiSetInternalUI)( NewUILevel, NULL );
  483. }
  484. //
  485. // Returns a quoted exe path with appended args. The forth parameter
  486. // is obsolete and returns no usefull value.
  487. //
  488. Status = (*gpfnMsiProvideComponentFromDescriptor)(
  489. Descriptor,
  490. CommandLine,
  491. CommandLineLength,
  492. &ArgStart );
  493. REMAP_DARWIN_STATUS( Status );
  494. if ( Status != ERROR_SUCCESS )
  495. DebugMsg((DM_VERBOSE, IDS_DESC_FAIL, Descriptor, Status));
  496. (*gpfnMsiSetInternalUI)( OldUILevel, NULL );
  497. return Status;
  498. }
  499. DWORD WINAPI
  500. GetLocalManagedApplications(
  501. IN BOOL bUserApps,
  502. OUT LPDWORD pdwApps,
  503. OUT PLOCALMANAGEDAPPLICATION * prgLocalApps
  504. )
  505. {
  506. PLOCALMANAGEDAPPLICATION pLocalApps;
  507. HKEY hkRoot;
  508. HKEY hkAppmgmt;
  509. HKEY hkApp;
  510. WCHAR wszDeploymentId[44];
  511. DWORD Size;
  512. DWORD Index;
  513. DWORD Apps;
  514. DWORD Status;
  515. *pdwApps = 0;
  516. *prgLocalApps = 0;
  517. Status = ERROR_SUCCESS;
  518. if ( bUserApps )
  519. Status = RegOpenCurrentUser( KEY_READ, &hkRoot );
  520. else
  521. hkRoot = HKEY_LOCAL_MACHINE;
  522. if ( Status != ERROR_SUCCESS )
  523. return Status;
  524. Status = RegOpenKeyEx(
  525. hkRoot,
  526. APPMGMTKEY,
  527. 0,
  528. KEY_READ,
  529. &hkAppmgmt );
  530. if ( Status != ERROR_SUCCESS )
  531. return Status;
  532. Status = RegQueryInfoKey (
  533. hkAppmgmt,
  534. NULL,
  535. NULL,
  536. NULL,
  537. &Apps,
  538. NULL,
  539. NULL,
  540. NULL,
  541. NULL,
  542. NULL,
  543. NULL,
  544. NULL );
  545. if ( ERROR_SUCCESS == Status )
  546. {
  547. pLocalApps = (PLOCALMANAGEDAPPLICATION) LocalAlloc( LMEM_ZEROINIT, Apps * sizeof(LOCALMANAGEDAPPLICATION) );
  548. if ( ! pLocalApps )
  549. Status = ERROR_OUTOFMEMORY;
  550. }
  551. if ( Status != ERROR_SUCCESS )
  552. {
  553. RegCloseKey( hkAppmgmt );
  554. if ( bUserApps )
  555. RegCloseKey( hkRoot );
  556. return ERROR_SUCCESS;
  557. }
  558. for ( Index = 0; Index < Apps; Index++ )
  559. {
  560. Status = RegEnumKey(
  561. hkAppmgmt,
  562. Index,
  563. wszDeploymentId,
  564. sizeof(wszDeploymentId) / sizeof(WCHAR) );
  565. if ( ERROR_SUCCESS == Status )
  566. {
  567. Status = RegOpenKeyEx(
  568. hkAppmgmt,
  569. wszDeploymentId,
  570. 0,
  571. KEY_READ,
  572. &hkApp );
  573. }
  574. if ( Status != ERROR_SUCCESS )
  575. break;
  576. Size = sizeof(DWORD);
  577. Status = RegQueryValueEx(
  578. hkApp,
  579. APPSTATEVALUE,
  580. 0,
  581. NULL,
  582. (LPBYTE) &pLocalApps[Index].dwState,
  583. &Size );
  584. if ( ERROR_SUCCESS == Status )
  585. Status = ReadStringValue( hkApp, DEPLOYMENTNAMEVALUE, &pLocalApps[Index].pszDeploymentName );
  586. if ( ERROR_SUCCESS == Status )
  587. Status = ReadStringValue( hkApp, GPONAMEVALUE, &pLocalApps[Index].pszPolicyName );
  588. if ( ERROR_SUCCESS == Status )
  589. Status = ReadStringValue( hkApp, PRODUCTIDVALUE, &pLocalApps[Index].pszProductId );
  590. RegCloseKey( hkApp );
  591. if ( Status != ERROR_SUCCESS )
  592. break;
  593. }
  594. if ( Status != ERROR_SUCCESS )
  595. {
  596. for ( Index = 0; Index < Apps; Index++ )
  597. {
  598. LocalFree( pLocalApps[Index].pszDeploymentName );
  599. LocalFree( pLocalApps[Index].pszPolicyName );
  600. LocalFree( pLocalApps[Index].pszProductId );
  601. }
  602. LocalFree( pLocalApps );
  603. }
  604. else
  605. {
  606. *prgLocalApps = pLocalApps;
  607. *pdwApps = Apps;
  608. }
  609. RegCloseKey( hkAppmgmt );
  610. if ( bUserApps )
  611. RegCloseKey( hkRoot );
  612. return Status;
  613. }
  614. void WINAPI
  615. GetLocalManagedApplicationData(
  616. WCHAR * ProductCode,
  617. LPWSTR * DisplayName,
  618. LPWSTR * SupportUrl
  619. )
  620. {
  621. HKEY hkRoot;
  622. HKEY hkAppmgmt;
  623. HKEY hkApp;
  624. WCHAR wszDeploymentId[44];
  625. WCHAR wszProductId[40];
  626. DWORD Index;
  627. DWORD Size;
  628. DWORD Status;
  629. BOOL bUser;
  630. *DisplayName = 0;
  631. *SupportUrl = 0;
  632. for ( int i = 0; i < 2; i++ )
  633. {
  634. Status = ERROR_SUCCESS;
  635. bUser = (0 == i);
  636. if ( bUser )
  637. Status = RegOpenCurrentUser( KEY_READ, &hkRoot );
  638. else
  639. hkRoot = HKEY_LOCAL_MACHINE;
  640. if ( Status != ERROR_SUCCESS )
  641. break;
  642. hkAppmgmt = 0;
  643. Status = RegOpenKeyEx(
  644. hkRoot,
  645. APPMGMTKEY,
  646. 0,
  647. KEY_READ,
  648. &hkAppmgmt );
  649. if ( bUser )
  650. RegCloseKey( hkRoot );
  651. if ( ERROR_SUCCESS == Status )
  652. {
  653. DWORD InstallUI;
  654. Size = sizeof(InstallUI);
  655. // This is the hint that we will use to determine if this product is managed.
  656. Status = RegQueryValueEx(
  657. hkAppmgmt,
  658. ProductCode,
  659. NULL,
  660. NULL,
  661. (LPBYTE) &InstallUI,
  662. &Size );
  663. }
  664. if ( Status != ERROR_SUCCESS )
  665. {
  666. if ( hkAppmgmt )
  667. RegCloseKey( hkAppmgmt );
  668. continue;
  669. }
  670. for ( Index = 0 ;; Index++ )
  671. {
  672. Status = RegEnumKey(
  673. hkAppmgmt,
  674. Index,
  675. wszDeploymentId,
  676. sizeof(wszDeploymentId) / sizeof(WCHAR) );
  677. if ( ERROR_SUCCESS == Status )
  678. {
  679. Status = RegOpenKeyEx(
  680. hkAppmgmt,
  681. wszDeploymentId,
  682. 0,
  683. KEY_READ,
  684. &hkApp );
  685. }
  686. if ( Status != ERROR_SUCCESS )
  687. break;
  688. Size = sizeof(wszProductId);
  689. wszProductId[0] = 0;
  690. (void) RegQueryValueEx( hkApp, PRODUCTIDVALUE, NULL, NULL, (LPBYTE) wszProductId, &Size );
  691. if ( lstrcmpi( ProductCode, wszProductId ) != 0 )
  692. {
  693. RegCloseKey( hkApp );
  694. continue;
  695. }
  696. (void) ReadStringValue( hkApp, DEPLOYMENTNAMEVALUE, DisplayName );
  697. (void) ReadStringValue( hkApp, SUPPORTURL, SupportUrl );
  698. RegCloseKey( hkApp );
  699. break;
  700. }
  701. RegCloseKey( hkAppmgmt );
  702. if ( *DisplayName || *SupportUrl )
  703. break;
  704. }
  705. }
  706. DWORD WINAPI
  707. GetManagedApplications(
  708. IN GUID* pCategory,
  709. IN DWORD dwQueryFlags,
  710. IN DWORD dwInfoLevel,
  711. OUT LPDWORD pdwApps,
  712. OUT PMANAGEDAPPLICATION* prgManagedApps)
  713. {
  714. LONG Status;
  715. MANAGED_APPLIST AppList;
  716. //
  717. // Initialize the out parameters
  718. //
  719. if (pdwApps) {
  720. *pdwApps = NULL;
  721. }
  722. if (prgManagedApps) {
  723. *prgManagedApps = NULL;
  724. }
  725. //
  726. // Validate caller parameters that aren't passed to the
  727. // rpc interface -- other parameters will be validated
  728. // by the server
  729. //
  730. if (!pdwApps || !prgManagedApps) {
  731. return ERROR_INVALID_PARAMETER;
  732. }
  733. Status = Bind();
  734. if ( Status != ERROR_SUCCESS )
  735. return Status;
  736. //
  737. // Initialize our stack variables
  738. //
  739. memset(&AppList, 0, sizeof(AppList));
  740. //
  741. // Call the method on the server.
  742. //
  743. Status = GetManagedApps( ghRpc, pCategory, dwQueryFlags, dwInfoLevel, &AppList);
  744. //
  745. // On success, set the caller's out parameters to refer
  746. // to the results returned by the server
  747. //
  748. if ( ERROR_SUCCESS == Status)
  749. {
  750. *pdwApps = AppList.Applications;
  751. *prgManagedApps = (PMANAGEDAPPLICATION) AppList.rgApps;
  752. }
  753. return Status;
  754. }
  755. static DWORD
  756. ReportInstallStatus(
  757. PINSTALLCONTEXT pInstallContext,
  758. DWORD InstallStatus,
  759. BOOL bUninstall,
  760. WCHAR * pwszDeploymentName,
  761. WCHAR * pwszGPOName,
  762. WCHAR * pwszDeploymentId
  763. )
  764. {
  765. DWORD Status;
  766. DWORD dwEventId;
  767. Status = ERROR_SUCCESS;
  768. //
  769. // First, report the correct event based on whether
  770. // this is an install or an uninstall
  771. //
  772. if ( ! bUninstall )
  773. {
  774. gpEvents->Install(
  775. InstallStatus,
  776. pwszDeploymentName,
  777. pwszGPOName
  778. );
  779. ( ERROR_SUCCESS == InstallStatus ) ?
  780. ( dwEventId = EVENT_APPMGMT_INSTALL ) : ( dwEventId = EVENT_APPMGMT_INSTALL_FAILED );
  781. }
  782. else
  783. {
  784. gpEvents->Uninstall(
  785. InstallStatus,
  786. pwszDeploymentName,
  787. pwszGPOName
  788. );
  789. ( ERROR_SUCCESS == InstallStatus ) ?
  790. ( dwEventId = EVENT_APPMGMT_UNINSTALL ) : ( dwEventId = EVENT_APPMGMT_UNINSTALL_FAILED );
  791. }
  792. //
  793. // If there was an error, log a failure status
  794. //
  795. if ( ERROR_SUCCESS != InstallStatus )
  796. {
  797. Status = RsopReportInstallFailure(
  798. pInstallContext,
  799. pwszDeploymentId,
  800. dwEventId);
  801. }
  802. return Status;
  803. }
  804. DWORD WINAPI
  805. GetManagedApplicationCategories(
  806. DWORD dwReserved,
  807. APPCATEGORYINFOLIST* pAppCategory
  808. )
  809. {
  810. DWORD Status;
  811. APPCATEGORYLIST CategoryList;
  812. if ( ( 0 != dwReserved ) ||
  813. ! pAppCategory )
  814. {
  815. return ERROR_INVALID_PARAMETER;
  816. }
  817. memset( &CategoryList, 0, sizeof( CategoryList ) );
  818. Status = Bind();
  819. if ( Status != ERROR_SUCCESS )
  820. return Status;
  821. Status = GetManagedAppCategories(
  822. ghRpc,
  823. &CategoryList);
  824. *pAppCategory = *( ( APPCATEGORYINFOLIST* ) &CategoryList );
  825. return Status;
  826. }