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.

1049 lines
28 KiB

  1. #include <stdafx.h>
  2. #include <adminpak.h>
  3. #include <objidl.h>
  4. #include "shlobj.h"
  5. // shortcut icons table ConditionType definition
  6. #define SHI_TYPE_NONE 0
  7. #define SHI_TYPE_SEARCH 1 // searches for existence of component's key file
  8. #define SHI_TYPE_INSTALLCOMPONENT 2 // checked for the component mentioned in the
  9. // Condition column at HKLM\SOFTWARE\Microsoft\CurrentVersion\Setup\OC Manager\Subcomponents
  10. #define SHI_TYPE_CONDITION 3 // evaluate the condition specified
  11. #define SAFE_EXECUTE_CS( statement ) \
  12. hr = statement; \
  13. if ( FAILED( hr ) ) \
  14. { \
  15. bResult = FALSE; \
  16. goto cleanup; \
  17. } \
  18. 1
  19. #define SAFE_RELEASE( pointer ) \
  20. if ( (pointer) != NULL ) \
  21. { \
  22. (pointer)->Release(); \
  23. (pointer) = NULL; \
  24. } \
  25. 1
  26. //
  27. // prototypes
  28. //
  29. BOOL IsComponentInstalled( LPCWSTR pwszComponent );
  30. BOOL LocateFile( LPCWSTR pwszFile, LPCWSTR pwszDirectory, PBOOL pbShortForm = NULL );
  31. BOOL CheckForComponents( HKEY hKey, LPCWSTR pwszComponents );
  32. BOOL CreateShortcut( LPCWSTR pwszShortcut,
  33. LPCWSTR pwszDescription, LPCWSTR pwszDirectory,
  34. LPCWSTR pwszFileName, LPCWSTR pwszArguments, LPCWSTR pwszWorkingDir,
  35. WORD wHotKey, INT nShowCmd, LPCWSTR pwszIconFile, DWORD dwIconIndex );
  36. //
  37. // implementation
  38. //
  39. BOOL PropertyGet_String( MSIHANDLE hInstall, LPCWSTR pwszProperty, CHString& strValue )
  40. {
  41. // local variables
  42. DWORD dwLength = 0;
  43. DWORD dwResult = 0;
  44. LPWSTR pwszValue = NULL;
  45. BOOL bSecondChance = FALSE;
  46. // check the input arguments
  47. if ( hInstall == NULL || pwszProperty == NULL )
  48. {
  49. return FALSE;
  50. }
  51. try
  52. {
  53. // mark this as first chance
  54. dwLength = 255;
  55. bSecondChance = FALSE;
  56. //
  57. // re-start point
  58. //
  59. retry_get:
  60. // get the pointer to the internal buffer
  61. pwszValue = strValue.GetBufferSetLength( dwLength + 1 );
  62. // get the value from the MSI record and check the result
  63. dwResult = MsiGetPropertyW( hInstall, pwszProperty, pwszValue, &dwLength );
  64. if ( dwResult == ERROR_MORE_DATA && bSecondChance == FALSE )
  65. {
  66. // now go back and try to the read the value again
  67. bSecondChance = TRUE;
  68. goto retry_get;
  69. }
  70. else if ( dwResult != ERROR_SUCCESS )
  71. {
  72. SetLastError( dwResult );
  73. strValue.ReleaseBuffer( 1 ); // simply pass some number
  74. return FALSE;
  75. }
  76. // release the buffer
  77. strValue.ReleaseBuffer( dwLength );
  78. // return the result
  79. return TRUE;
  80. }
  81. catch( ... )
  82. {
  83. return FALSE;
  84. }
  85. }
  86. BOOL GetFieldValueFromRecord_String( MSIHANDLE hRecord, DWORD dwColumn, CHString& strValue )
  87. {
  88. // local variables
  89. DWORD dwLength = 0;
  90. DWORD dwResult = 0;
  91. LPWSTR pwszValue = NULL;
  92. BOOL bSecondChance = FALSE;
  93. // check the input
  94. if ( hRecord == NULL )
  95. {
  96. return FALSE;
  97. }
  98. try
  99. {
  100. // mark this as first chance
  101. dwLength = 255;
  102. bSecondChance = FALSE;
  103. //
  104. // re-start point
  105. //
  106. retry_get:
  107. // get the pointer to the internal buffer
  108. pwszValue = strValue.GetBufferSetLength( dwLength + 1 );
  109. // get the value from the MSI record and check the result
  110. dwResult = MsiRecordGetStringW( hRecord, dwColumn, pwszValue, &dwLength );
  111. if ( dwResult == ERROR_MORE_DATA && bSecondChance == FALSE )
  112. {
  113. // now go back and try to the read the value again
  114. bSecondChance = TRUE;
  115. goto retry_get;
  116. }
  117. else if ( dwResult != ERROR_SUCCESS )
  118. {
  119. SetLastError( dwResult );
  120. return FALSE;
  121. }
  122. // release the buffer
  123. strValue.ReleaseBuffer( dwLength );
  124. // we successfully got the value from the record
  125. return TRUE;
  126. }
  127. catch( ... )
  128. {
  129. return FALSE;
  130. }
  131. }
  132. BOOL CreateShortcut( LPCWSTR pwszShortcut,
  133. LPCWSTR pwszDescription, LPCWSTR pwszDirectory,
  134. LPCWSTR pwszFileName, LPCWSTR pwszArguments, LPCWSTR pwszWorkingDir,
  135. WORD wHotKey, INT nShowCmd, LPCWSTR pwszIconFile, DWORD dwIconIndex )
  136. {
  137. // local variables
  138. CHString str;
  139. HRESULT hr = S_OK;
  140. HANDLE hFile = NULL;
  141. BOOL bResult = FALSE;
  142. IShellLinkW* pShellLink = NULL;
  143. IPersistFile* pPersistFile = NULL;
  144. // check the input parameters
  145. // we dont care about the input for pwszArguments parameter
  146. if ( pwszShortcut == NULL ||
  147. pwszDescription == NULL || pwszDirectory == NULL ||
  148. pwszFileName == NULL || pwszWorkingDir == NULL || pwszIconFile == NULL )
  149. {
  150. return FALSE;
  151. }
  152. try
  153. {
  154. //
  155. // check if shortcut is already existing at this location or not
  156. //
  157. // prepare the link name and save it
  158. str.Format( L"%s%s", pwszDirectory, pwszShortcut );
  159. if ( str.Mid( str.GetLength() - 4 ).CompareNoCase( L".lnk" ) != 0 )
  160. {
  161. str += ".lnk";
  162. }
  163. // try to open the file
  164. hFile = CreateFileW( str, GENERIC_READ,
  165. FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  166. if ( hFile != INVALID_HANDLE_VALUE )
  167. {
  168. // close the handle to the file
  169. CloseHandle( hFile );
  170. // shortcut is alreadt existing -- so, dont create it again
  171. bResult = TRUE;
  172. goto cleanup;
  173. }
  174. //
  175. // shortcut is not existing -- so we need to create it now
  176. //
  177. // get the pointer to the IShellLink interface
  178. SAFE_EXECUTE_CS( CoCreateInstance( CLSID_ShellLink, NULL,
  179. CLSCTX_INPROC_SERVER, IID_IShellLinkW, (LPVOID*) &pShellLink ) );
  180. // get the pointer to the IPersistFile interface
  181. SAFE_EXECUTE_CS( pShellLink->QueryInterface( IID_IPersistFile, (LPVOID*) &pPersistFile ) );
  182. // set the working directory for the shortcut.
  183. SAFE_EXECUTE_CS( pShellLink->SetWorkingDirectory( pwszWorkingDir ) );
  184. // prepare the shortcut name -- path (working dir) + file name -- finally set the path
  185. // NOTE: we assume path containded in pwszWorkingDir ends with "\"
  186. str.Format( L"%s%s", pwszWorkingDir, pwszFileName );
  187. SAFE_EXECUTE_CS( pShellLink->SetPath( str ) );
  188. // check if arguments needs to set
  189. if ( pwszArguments == NULL || lstrlenW( pwszArguments ) > 0 )
  190. {
  191. SAFE_EXECUTE_CS( pShellLink->SetArguments( pwszArguments ) );
  192. }
  193. // set the description
  194. SAFE_EXECUTE_CS( pShellLink->SetDescription( pwszDescription ) );
  195. // set icon location
  196. SAFE_EXECUTE_CS( pShellLink->SetIconLocation(
  197. pwszIconFile, ((dwIconIndex == MSI_NULL_INTEGER) ? 0 : dwIconIndex) ) );
  198. // set hotkey
  199. if ( wHotKey != MSI_NULL_INTEGER )
  200. {
  201. SAFE_EXECUTE_CS( pShellLink->SetHotkey( wHotKey ) );
  202. }
  203. // set showcmd
  204. if ( nShowCmd != MSI_NULL_INTEGER )
  205. {
  206. SAFE_EXECUTE_CS( pShellLink->SetShowCmd( nShowCmd ) );
  207. }
  208. // prepare the link name and save it
  209. str.Format( L"%s%s", pwszDirectory, pwszShortcut );
  210. if ( str.Mid( str.GetLength() - 4 ).CompareNoCase( L".lnk" ) != 0 )
  211. {
  212. str += ".lnk";
  213. }
  214. // ...
  215. SAFE_EXECUTE_CS( pPersistFile->Save( str, TRUE ) );
  216. // mark the result as success
  217. bResult = TRUE;
  218. }
  219. catch( ... )
  220. {
  221. bResult = FALSE;
  222. }
  223. // default clean up
  224. cleanup:
  225. // release the interfaces
  226. SAFE_RELEASE( pShellLink );
  227. SAFE_RELEASE( pPersistFile );
  228. // return
  229. return bResult;
  230. }
  231. extern "C" ADMINPAK_API int _stdcall fnReCreateShortcuts( MSIHANDLE hInstall )
  232. {
  233. // local variables
  234. CHString str;
  235. HRESULT hr = S_OK;
  236. BOOL bFileFound = FALSE;
  237. BOOL bCreateShortcut = FALSE;
  238. DWORD dwResult = ERROR_SUCCESS;
  239. // MSI handles
  240. PMSIHANDLE hView = NULL;
  241. PMSIHANDLE hRecord = NULL;
  242. PMSIHANDLE hDatabase = NULL;
  243. // query field variables
  244. WORD wHotKey = 0;
  245. INT nShowCmd = 0;
  246. CHString strShortcut;
  247. CHString strFileName;
  248. CHString strIconFile;
  249. CHString strDirectory;
  250. CHString strArguments;
  251. CHString strCondition;
  252. DWORD dwIconIndex = 0;
  253. CHString strWorkingDir;
  254. CHString strDescription;
  255. CHString strIconDirectory;
  256. DWORD dwConditionType = 0;
  257. // sql for retrieving the information from MSI table
  258. const WCHAR cwszSQL[] =
  259. L" SELECT DISTINCT"
  260. L" `Shortcut`.`Name`, `Shortcut`.`Description`, `Shortcut`.`Directory_`, `File`.`FileName`, "
  261. L" `Shortcut`.`Arguments`, `Component`.`Directory_`, `Shortcut`.`Hotkey`, `Shortcut`.`ShowCmd`, "
  262. L" `ShortcutIcons`.`IconDirectory_`, `ShortcutIcons`.`IconFile`, `ShortcutIcons`.`IconIndex`, "
  263. L" `ShortcutIcons`.`ConditionType`, `ShortcutIcons`.`Condition` "
  264. L" FROM `Shortcut`, `Component`, `File`, `ShortcutIcons` "
  265. L" WHERE `Shortcut`.`Component_` = `Component`.`Component` "
  266. L" AND `Component`.`KeyPath` = `File`.`File` "
  267. L" AND `ShortcutIcons`.`Shortcut_` = `Shortcut`.`Shortcut`";
  268. // column indices into the record
  269. enum {
  270. Shortcut = 1,
  271. Description, Directory, FileName, Arguments,
  272. WorkingDir, HotKey, ShowCmd, IconDirectory, IconFile, IconIndex, ConditionType, Condition
  273. };
  274. // initialize the COM library
  275. hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
  276. if ( FAILED( hr ) )
  277. {
  278. dwResult = ERROR_INVALID_HANDLE;
  279. goto cleanup;
  280. }
  281. // get a handle on the MSI database
  282. hDatabase = MsiGetActiveDatabase( hInstall );
  283. if ( hDatabase == NULL )
  284. {
  285. dwResult = ERROR_INVALID_HANDLE;
  286. goto cleanup;
  287. }
  288. // get a view of our table in the MSI
  289. dwResult = MsiDatabaseOpenViewW( hDatabase, cwszSQL, &hView );
  290. if ( dwResult != ERROR_SUCCESS )
  291. {
  292. dwResult = ERROR_INVALID_HANDLE;
  293. goto cleanup;
  294. }
  295. // if no errors, get our records
  296. dwResult = MsiViewExecute( hView, NULL );
  297. if( dwResult != ERROR_SUCCESS )
  298. {
  299. dwResult = ERROR_INVALID_HANDLE;
  300. goto cleanup;
  301. }
  302. // loop through the result records obtain via SQL
  303. hRecord = NULL;
  304. while( MsiViewFetch( hView, &hRecord ) == ERROR_SUCCESS )
  305. {
  306. // get the values from the record
  307. wHotKey = (WORD) MsiRecordGetInteger( hRecord, HotKey );
  308. nShowCmd = MsiRecordGetInteger( hRecord, ShowCmd );
  309. dwIconIndex = MsiRecordGetInteger( hRecord, IconIndex );
  310. dwConditionType = MsiRecordGetInteger( hRecord, ConditionType );
  311. GetFieldValueFromRecord_String( hRecord, Shortcut, strShortcut );
  312. GetFieldValueFromRecord_String( hRecord, FileName, strFileName );
  313. GetFieldValueFromRecord_String( hRecord, IconFile, strIconFile );
  314. GetFieldValueFromRecord_String( hRecord, Directory, strDirectory );
  315. GetFieldValueFromRecord_String( hRecord, Arguments, strArguments );
  316. GetFieldValueFromRecord_String( hRecord, Condition, strCondition );
  317. GetFieldValueFromRecord_String( hRecord, WorkingDir, strWorkingDir );
  318. GetFieldValueFromRecord_String( hRecord, Description, strDescription );
  319. GetFieldValueFromRecord_String( hRecord, IconDirectory, strIconDirectory );
  320. // shortcut name might contain '|' as seperator for 8.3 and long name formats -- suppress this
  321. if( strShortcut.Find( L'|' ) != -1 )
  322. {
  323. str = strShortcut.Mid( strShortcut.Find( L'|' ) + 1 );
  324. strShortcut = str; // store the result back
  325. }
  326. // transform the directory property references
  327. TransformDirectory( hInstall, strDirectory );
  328. TransformDirectory( hInstall, strWorkingDir );
  329. TransformDirectory( hInstall, strIconDirectory );
  330. // prepare the icon locatio
  331. str.Format( L"%s%s", strIconDirectory, strIconFile );
  332. strIconFile = str; // store the result back
  333. //
  334. // determine whether shortcut need to be created or not
  335. //
  336. // if the condition type is not specified, assume it "SEARCH"
  337. if ( dwConditionType == MSI_NULL_INTEGER )
  338. {
  339. dwConditionType = SHI_TYPE_SEARCH;
  340. }
  341. // no matter what the "ConditionType" -- since creation of the shortcut very much depends
  342. // on the existence of the file, we will try to locate for the file first -- this is necessary condition
  343. // so, do a simple file search for the component key file
  344. bFileFound = LocateFile( strFileName, strWorkingDir, NULL );
  345. // proceed with rest of the conditions only if necessary condition is satisfied
  346. if ( bFileFound == TRUE )
  347. {
  348. //
  349. // now do additional sufficient conditon(s) if needed
  350. //
  351. bCreateShortcut = FALSE;
  352. if ( dwConditionType == SHI_TYPE_SEARCH )
  353. {
  354. // search is already successful
  355. bCreateShortcut = TRUE;
  356. }
  357. else if ( dwConditionType == SHI_TYPE_INSTALLCOMPONENT )
  358. {
  359. // check whether the component specified in 'Condition' field is installed or not
  360. bCreateShortcut = IsComponentInstalled( strCondition );
  361. }
  362. else if ( dwConditionType == SHI_TYPE_CONDITION )
  363. {
  364. // evaluate the condition specified by the user
  365. if ( MsiEvaluateConditionW( hInstall, strCondition ) == MSICONDITION_TRUE )
  366. {
  367. bCreateShortcut = TRUE;
  368. }
  369. }
  370. // check the shortcut if needed
  371. if ( bCreateShortcut == TRUE )
  372. {
  373. CreateShortcut( strShortcut,
  374. strDescription, strDirectory, strFileName, strArguments,
  375. strWorkingDir, wHotKey, nShowCmd, strIconFile, dwIconIndex );
  376. }
  377. }
  378. // close the MSI handle to the current record object -- ignore the error
  379. MsiCloseHandle( hRecord );
  380. hRecord = NULL;
  381. }
  382. // mark the flag as success
  383. dwResult = ERROR_SUCCESS;
  384. //
  385. // cleanup
  386. //
  387. cleanup:
  388. // un-initialize the COM library
  389. CoUninitialize();
  390. // close the handle to the record
  391. if ( hRecord != NULL )
  392. {
  393. MsiCloseHandle( hRecord );
  394. hRecord = NULL;
  395. }
  396. // close View -- ignore the errors
  397. if ( hView != NULL )
  398. {
  399. MsiViewClose( hView );
  400. hView = NULL;
  401. }
  402. // close the database handle
  403. if ( hDatabase != NULL )
  404. {
  405. MsiCloseHandle( hDatabase );
  406. hDatabase = NULL;
  407. }
  408. // return
  409. return dwResult;
  410. }
  411. BOOL LocateFile( LPCWSTR pwszFile, LPCWSTR pwszDirectory, PBOOL pbShortForm )
  412. {
  413. // local variables
  414. INT nPosition = 0;
  415. HANDLE hFind = NULL;
  416. BOOL bFound = FALSE;
  417. CHString strPath;
  418. CHString strFileName;
  419. WIN32_FIND_DATAW findData;
  420. // check the optional parameter
  421. if ( pbShortForm != NULL )
  422. {
  423. *pbShortForm = FALSE;
  424. }
  425. // check the input
  426. if ( pwszFile == NULL || pwszDirectory == NULL )
  427. {
  428. return FALSE;
  429. }
  430. try
  431. {
  432. // init the variable with file name passed
  433. strFileName = pwszFile;
  434. // check whether user specified two formats for this file (8.3 and long format)
  435. nPosition = strFileName.Find( L'|' );
  436. if ( nPosition != -1 )
  437. {
  438. // extract the long file name first
  439. CHString strTemp;
  440. strTemp = strFileName.Mid( nPosition + 1 );
  441. strFileName = strTemp;
  442. // check the length of the file name
  443. if ( strFileName.GetLength() == 0 )
  444. {
  445. // invalid file name format
  446. return FALSE;
  447. }
  448. }
  449. // prepare the path
  450. strPath.Format( L"%s%s", pwszDirectory, strFileName );
  451. // search for this file
  452. bFound = FALSE;
  453. hFind = FindFirstFileW( strPath, &findData );
  454. if ( hFind == INVALID_HANDLE_VALUE )
  455. {
  456. // find failed -- may be file is not found -- confirm this
  457. bFound = FALSE;
  458. if ( GetLastError() == ERROR_FILE_NOT_FOUND )
  459. {
  460. // yes -- file is not found
  461. }
  462. }
  463. else
  464. {
  465. // file is located
  466. // take the actions needed
  467. // close the handle to the file search first
  468. FindClose( hFind );
  469. hFind = NULL;
  470. // set the flag
  471. bFound = TRUE;
  472. if ( pbShortForm != NULL )
  473. {
  474. *pbShortForm = FALSE;
  475. }
  476. }
  477. //
  478. // file is not found in long format
  479. // may be, it is existed in 8.3 format
  480. // so, check whether user supplied 8.3 file name for this file
  481. if ( nPosition != -1 && bFound == FALSE )
  482. {
  483. // extract the 8.3 format of the file name
  484. CHString strTemp;
  485. strTemp = pwszFile;
  486. strFileName = strTemp.Mid( 0, nPosition );
  487. // prepare the path
  488. strPath.Format( L"%s%s", pwszDirectory, strFileName );
  489. // search for this file
  490. bFound = FALSE;
  491. hFind = FindFirstFileW( strPath, &findData );
  492. if ( hFind == INVALID_HANDLE_VALUE )
  493. {
  494. // find failed -- may be file is not found -- confirm this
  495. if ( GetLastError() == ERROR_FILE_NOT_FOUND )
  496. {
  497. // yes -- file is not found
  498. }
  499. }
  500. else
  501. {
  502. // file is located
  503. // take the actions needed
  504. // close the handle to the file search first
  505. FindClose( hFind );
  506. hFind = NULL;
  507. // set the flag
  508. bFound = TRUE;
  509. if ( pbShortForm != NULL )
  510. {
  511. *pbShortForm = TRUE;
  512. }
  513. }
  514. }
  515. }
  516. catch( ... )
  517. {
  518. return FALSE;
  519. }
  520. // return the result of search
  521. return bFound;
  522. }
  523. BOOL IsComponentInstalled( LPCWSTR pwszComponent )
  524. {
  525. // local variables
  526. HKEY hKey = NULL;
  527. LONG lResult = 0;
  528. LONG lPosition = 0;
  529. CHString strTemp;
  530. CHString strComponent;
  531. CHString strComponents;
  532. BOOL bComponentInstalled = FALSE;
  533. const WCHAR cwszSubKey[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager\\Subcomponents";
  534. // open the registry path
  535. lResult = RegOpenKeyExW( HKEY_LOCAL_MACHINE, cwszSubKey, 0, KEY_READ, &hKey );
  536. if ( lResult != ERROR_SUCCESS )
  537. {
  538. SetLastError( lResult );
  539. return FALSE;
  540. }
  541. //
  542. // since components may be multiple -- we need to check for each and every component
  543. //
  544. try
  545. {
  546. // get the component -- ready for processing
  547. strComponents = pwszComponent;
  548. // loop until there are no more components
  549. bComponentInstalled = FALSE;
  550. while ( strComponents.GetLength() != 0 )
  551. {
  552. // extract the first component
  553. lPosition = strComponents.Find( L';' );
  554. if ( lPosition != -1 )
  555. {
  556. strComponent = strComponents.Mid( 0, lPosition );
  557. strTemp = strComponents.Mid( lPosition + 1 );
  558. strComponents = strTemp;
  559. }
  560. else
  561. {
  562. // there is only one component
  563. strComponent = strComponents;
  564. strComponents = L"";
  565. }
  566. // check for the components existence
  567. if ( CheckForComponents( hKey, strComponent ) == TRUE )
  568. {
  569. // since this is an OR condition checking -- if atleast one component in installed
  570. // then we will return from here itself as there wont be any meaning in checking for the
  571. // existence of other components -- the condition is satisfied
  572. bComponentInstalled = TRUE;
  573. break;
  574. }
  575. }
  576. }
  577. catch( ... )
  578. {
  579. // ignore the exception
  580. }
  581. // we are done with the opened registry key -- we can close it
  582. RegCloseKey( hKey );
  583. hKey = NULL;
  584. // return the result
  585. return bComponentInstalled;
  586. }
  587. BOOL CheckForComponents( HKEY hKey, LPCWSTR pwszComponents )
  588. {
  589. // local variables
  590. LONG lResult = 0;
  591. DWORD dwType = 0;
  592. DWORD dwSize = 0;
  593. DWORD dwValue = 0;
  594. CHString strTemp;
  595. CHString strComponent;
  596. CHString strComponents;
  597. LONG lPosition = 0;
  598. // check the input
  599. if ( hKey == NULL || pwszComponents == NULL )
  600. {
  601. return FALSE;
  602. }
  603. try
  604. {
  605. // ...
  606. strComponents = pwszComponents;
  607. if ( strComponents.GetLength() == 0 )
  608. {
  609. return FALSE;
  610. }
  611. // loop until all the components are checked
  612. while ( strComponents.GetLength() != 0 )
  613. {
  614. // extract the first component
  615. lPosition = strComponent.Find( L',' );
  616. if ( lPosition != -1 )
  617. {
  618. strComponent = strComponents.Mid( 0, lPosition );
  619. strTemp = strComponents.Mid( lPosition + 1 );
  620. strComponents = strTemp;
  621. }
  622. else
  623. {
  624. // there is only one component
  625. strComponent = strComponents;
  626. strComponents = L"";
  627. }
  628. // now check for this component in registry
  629. dwSize = sizeof( DWORD );
  630. lResult = RegQueryValueExW( hKey, strComponent, NULL, &dwType, (LPBYTE) &dwValue, &dwSize );
  631. // *) check result of the registry query operation
  632. // *) confirm the type of the value -- it should be REG_DWORD
  633. // *) also check the state of the component and return the accordingly
  634. // 1 Installed
  635. // 0 Not Installed
  636. strTemp.Format( L"%d", dwValue );
  637. if ( lResult != ERROR_SUCCESS || dwType != REG_DWORD || dwValue == 0 )
  638. {
  639. // no matter what is the reason -- we will treat this as
  640. // component is not installed at all
  641. //
  642. // and since this is an AND condition checking -- if atleast one component in not installed
  643. // then we will return from here itself as there wont be any meaning in checking for the
  644. // existence of other components
  645. return FALSE;
  646. }
  647. }
  648. }
  649. catch( ... )
  650. {
  651. return FALSE;
  652. }
  653. // if the control came to this point -- it is obvious that required components are installed
  654. return TRUE;
  655. }
  656. BOOL TransformDirectory( MSIHANDLE hInstall, CHString& strDirectory )
  657. {
  658. // local variables
  659. CHString strActualDirectory;
  660. // check the input parameters
  661. if ( hInstall == NULL )
  662. {
  663. return FALSE;
  664. }
  665. try
  666. {
  667. // get the property value
  668. PropertyGet_String( hInstall, strDirectory, strActualDirectory );
  669. // assign the property value to the input argument
  670. strDirectory = strActualDirectory;
  671. // return
  672. return TRUE;
  673. }
  674. catch( ... )
  675. {
  676. return FALSE;
  677. }
  678. }
  679. // remove the shortcuts that are created by W2K version of adminpak.msi (W2K -> .NET upgrade scenario)
  680. extern "C" ADMINPAK_API int _stdcall fnDeleteW2KShortcuts( MSIHANDLE hInstall )
  681. {
  682. // local variables
  683. CHString str;
  684. HRESULT hr = S_OK;
  685. BOOL bFileFound = FALSE;
  686. BOOL bShortForm = FALSE;
  687. BOOL bCreateShortcut = FALSE;
  688. DWORD nPosition = 0;
  689. DWORD dwResult = ERROR_SUCCESS;
  690. // MSI handles
  691. PMSIHANDLE hView = NULL;
  692. PMSIHANDLE hRecord = NULL;
  693. PMSIHANDLE hDatabase = NULL;
  694. // query field variables
  695. CHString strShortcut;
  696. CHString strNewShortcut;
  697. CHString strShortcutDirectory;
  698. CHString strRecreate;
  699. CHString strFileDirectory;
  700. CHString strFileName;
  701. CHString strArguments;
  702. CHString strDescription;
  703. CHString strIconDirectory;
  704. CHString strIconFile;
  705. DWORD dwIconIndex = 0;
  706. DWORD dwConditionType = 0;
  707. CHString strCondition;
  708. // sql for retrieving the information from MSI table
  709. const WCHAR cwszSQL[] = L"SELECT * FROM `W2KShortcutCleanup`";
  710. // column indices into the record
  711. enum {
  712. Shortcut = 2,
  713. ShortcutDirectory, Recreate, NewShortcut,
  714. FileDirectory, FileName, Arguments, Description,
  715. IconDirectory, IconFile, IconIndex, ConditionType, Condition
  716. };
  717. // initialize the COM library
  718. hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
  719. if ( FAILED( hr ) )
  720. {
  721. dwResult = ERROR_INVALID_HANDLE;
  722. goto cleanup;
  723. }
  724. // get a handle on the MSI database
  725. hDatabase = MsiGetActiveDatabase( hInstall );
  726. if ( hDatabase == NULL )
  727. {
  728. dwResult = ERROR_INVALID_HANDLE;
  729. goto cleanup;
  730. }
  731. // get a view of our table in the MSI
  732. dwResult = MsiDatabaseOpenViewW( hDatabase, cwszSQL, &hView );
  733. if ( dwResult != ERROR_SUCCESS )
  734. {
  735. dwResult = ERROR_INVALID_HANDLE;
  736. goto cleanup;
  737. }
  738. // if no errors, get our records
  739. dwResult = MsiViewExecute( hView, NULL );
  740. if( dwResult != ERROR_SUCCESS )
  741. {
  742. dwResult = ERROR_INVALID_HANDLE;
  743. goto cleanup;
  744. }
  745. try
  746. {
  747. // loop through the result records obtain via SQL
  748. hRecord = NULL;
  749. while( MsiViewFetch( hView, &hRecord ) == ERROR_SUCCESS )
  750. {
  751. // get the values from the record
  752. dwIconIndex = MsiRecordGetInteger( hRecord, IconIndex );
  753. dwConditionType = MsiRecordGetInteger( hRecord, ConditionType );
  754. GetFieldValueFromRecord_String( hRecord, Shortcut, strShortcut );
  755. GetFieldValueFromRecord_String( hRecord, NewShortcut, strNewShortcut );
  756. GetFieldValueFromRecord_String( hRecord, Recreate, strRecreate );
  757. GetFieldValueFromRecord_String( hRecord, FileName, strFileName );
  758. GetFieldValueFromRecord_String( hRecord, IconFile, strIconFile );
  759. GetFieldValueFromRecord_String( hRecord, Arguments, strArguments );
  760. GetFieldValueFromRecord_String( hRecord, Condition, strCondition );
  761. GetFieldValueFromRecord_String( hRecord, Description, strDescription );
  762. GetFieldValueFromRecord_String( hRecord, FileDirectory, strFileDirectory );
  763. GetFieldValueFromRecord_String( hRecord, IconDirectory, strIconDirectory );
  764. GetFieldValueFromRecord_String( hRecord, ShortcutDirectory, strShortcutDirectory );
  765. // transform the directory property references
  766. TransformDirectory( hInstall, strFileDirectory );
  767. TransformDirectory( hInstall, strIconDirectory );
  768. TransformDirectory( hInstall, strShortcutDirectory );
  769. // search for the existence of the shortcut
  770. if ( LocateFile( strShortcut, strShortcutDirectory ) == FALSE )
  771. {
  772. // file is not found
  773. goto loop_cleanup;
  774. }
  775. //
  776. // shortcut is found
  777. //
  778. // delete the shortcut
  779. //
  780. // file might be in short name or long name -- so attempt to delete the appropriate file only
  781. nPosition = strShortcut.Find( L'|' );
  782. if ( nPosition != -1 )
  783. {
  784. if ( bShortForm == TRUE )
  785. {
  786. str = strShortcut.Mid( 0, nPosition );
  787. }
  788. else
  789. {
  790. str = strShortcut.Mid( nPosition + 1 );
  791. }
  792. // ...
  793. strShortcut = str;
  794. }
  795. str.Format( L"%s%s", strShortcutDirectory, strShortcut );
  796. if ( DeleteFileW( str ) == FALSE )
  797. {
  798. // failed to delete the file
  799. goto loop_cleanup;
  800. }
  801. // check if the directory is empty or not --
  802. // if the directory is empty, delete the directory also
  803. if ( LocateFile( L"*.lnk", strShortcutDirectory ) == FALSE )
  804. {
  805. // directory is empty -- delete it
  806. // NOTE: we dont care about the suceess of the function call
  807. RemoveDirectoryW( strShortcutDirectory );
  808. }
  809. // check whether we need to recreate the shortcut or not
  810. if ( strRecreate == L"N" )
  811. {
  812. // no need to create the shortcut
  813. goto loop_cleanup;
  814. }
  815. //
  816. // we need to recreate the shortcut
  817. //
  818. // prepare the icon location
  819. str.Format( L"%s%s", strIconDirectory, strIconFile );
  820. strIconFile = str; // store the result back
  821. //
  822. // determine whether shortcut need to be created or not
  823. //
  824. // if the condition type is not specified, assume it "SEARCH"
  825. if ( dwConditionType == MSI_NULL_INTEGER )
  826. {
  827. dwConditionType = SHI_TYPE_SEARCH;
  828. }
  829. // no matter what the "ConditionType" -- since creation of the shortcut very much depends
  830. // on the existence of the file, we will try to locate for the file first -- this is necessary condition
  831. // so, do a simple file search for the component key file
  832. bFileFound = LocateFile( strFileName, strFileDirectory );
  833. // proceed with rest of the conditions only if necessary condition is satisfied
  834. if ( bFileFound == TRUE )
  835. {
  836. //
  837. // now do additional sufficient conditon(s) if needed
  838. //
  839. bCreateShortcut = FALSE;
  840. if ( dwConditionType == SHI_TYPE_SEARCH )
  841. {
  842. // search is already successful
  843. bCreateShortcut = TRUE;
  844. }
  845. else if ( dwConditionType == SHI_TYPE_INSTALLCOMPONENT )
  846. {
  847. // check whether the component specified in 'Condition' field is installed or not
  848. bCreateShortcut = IsComponentInstalled( strCondition );
  849. }
  850. else if ( dwConditionType == SHI_TYPE_CONDITION )
  851. {
  852. // evaluate the condition specified by the user
  853. if ( MsiEvaluateConditionW( hInstall, strCondition ) == MSICONDITION_TRUE )
  854. {
  855. bCreateShortcut = TRUE;
  856. }
  857. }
  858. // check the shortcut if needed
  859. if ( bCreateShortcut == TRUE )
  860. {
  861. CreateShortcut(
  862. ((strNewShortcut.GetLength() == 0) ? strShortcut : strNewShortcut), strDescription,
  863. strShortcutDirectory, strFileName, strArguments, strFileDirectory, 0, 0, strIconFile, dwIconIndex );
  864. }
  865. }
  866. loop_cleanup:
  867. // close the MSI handle to the current record object -- ignore the error
  868. MsiCloseHandle( hRecord );
  869. hRecord = NULL;
  870. }
  871. // mark the flag as success
  872. dwResult = ERROR_SUCCESS;
  873. }
  874. catch( ... )
  875. {
  876. // error
  877. dwResult = ERROR_INVALID_HANDLE;
  878. }
  879. //
  880. // cleanup
  881. //
  882. cleanup:
  883. // un-initialize the COM library
  884. CoUninitialize();
  885. // close the handle to the record
  886. if ( hRecord != NULL )
  887. {
  888. MsiCloseHandle( hRecord );
  889. hRecord = NULL;
  890. }
  891. // close View -- ignore the errors
  892. if ( hView != NULL )
  893. {
  894. MsiViewClose( hView );
  895. hView = NULL;
  896. }
  897. // close the database handle
  898. if ( hDatabase != NULL )
  899. {
  900. MsiCloseHandle( hDatabase );
  901. hDatabase = NULL;
  902. }
  903. // return
  904. return dwResult;
  905. }