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

#include <stdafx.h>
#include <adminpak.h>
#include <objidl.h>
#include "shlobj.h"
// shortcut icons table ConditionType definition
#define SHI_TYPE_NONE 0
#define SHI_TYPE_SEARCH 1 // searches for existence of component's key file
#define SHI_TYPE_INSTALLCOMPONENT 2 // checked for the component mentioned in the
// Condition column at HKLM\SOFTWARE\Microsoft\CurrentVersion\Setup\OC Manager\Subcomponents
#define SHI_TYPE_CONDITION 3 // evaluate the condition specified
#define SAFE_EXECUTE_CS( statement ) \
hr = statement; \
if ( FAILED( hr ) ) \
{ \
bResult = FALSE; \
goto cleanup; \
} \
1
#define SAFE_RELEASE( pointer ) \
if ( (pointer) != NULL ) \
{ \
(pointer)->Release(); \
(pointer) = NULL; \
} \
1
//
// prototypes
//
BOOL IsComponentInstalled( LPCWSTR pwszComponent );
BOOL LocateFile( LPCWSTR pwszFile, LPCWSTR pwszDirectory, PBOOL pbShortForm = NULL );
BOOL CheckForComponents( HKEY hKey, LPCWSTR pwszComponents );
BOOL CreateShortcut( LPCWSTR pwszShortcut,
LPCWSTR pwszDescription, LPCWSTR pwszDirectory,
LPCWSTR pwszFileName, LPCWSTR pwszArguments, LPCWSTR pwszWorkingDir,
WORD wHotKey, INT nShowCmd, LPCWSTR pwszIconFile, DWORD dwIconIndex );
//
// implementation
//
BOOL PropertyGet_String( MSIHANDLE hInstall, LPCWSTR pwszProperty, CHString& strValue )
{
// local variables
DWORD dwLength = 0;
DWORD dwResult = 0;
LPWSTR pwszValue = NULL;
BOOL bSecondChance = FALSE;
// check the input arguments
if ( hInstall == NULL || pwszProperty == NULL )
{
return FALSE;
}
try
{
// mark this as first chance
dwLength = 255;
bSecondChance = FALSE;
//
// re-start point
//
retry_get:
// get the pointer to the internal buffer
pwszValue = strValue.GetBufferSetLength( dwLength + 1 );
// get the value from the MSI record and check the result
dwResult = MsiGetPropertyW( hInstall, pwszProperty, pwszValue, &dwLength );
if ( dwResult == ERROR_MORE_DATA && bSecondChance == FALSE )
{
// now go back and try to the read the value again
bSecondChance = TRUE;
goto retry_get;
}
else if ( dwResult != ERROR_SUCCESS )
{
SetLastError( dwResult );
strValue.ReleaseBuffer( 1 ); // simply pass some number
return FALSE;
}
// release the buffer
strValue.ReleaseBuffer( dwLength );
// return the result
return TRUE;
}
catch( ... )
{
return FALSE;
}
}
BOOL GetFieldValueFromRecord_String( MSIHANDLE hRecord, DWORD dwColumn, CHString& strValue )
{
// local variables
DWORD dwLength = 0;
DWORD dwResult = 0;
LPWSTR pwszValue = NULL;
BOOL bSecondChance = FALSE;
// check the input
if ( hRecord == NULL )
{
return FALSE;
}
try
{
// mark this as first chance
dwLength = 255;
bSecondChance = FALSE;
//
// re-start point
//
retry_get:
// get the pointer to the internal buffer
pwszValue = strValue.GetBufferSetLength( dwLength + 1 );
// get the value from the MSI record and check the result
dwResult = MsiRecordGetStringW( hRecord, dwColumn, pwszValue, &dwLength );
if ( dwResult == ERROR_MORE_DATA && bSecondChance == FALSE )
{
// now go back and try to the read the value again
bSecondChance = TRUE;
goto retry_get;
}
else if ( dwResult != ERROR_SUCCESS )
{
SetLastError( dwResult );
return FALSE;
}
// release the buffer
strValue.ReleaseBuffer( dwLength );
// we successfully got the value from the record
return TRUE;
}
catch( ... )
{
return FALSE;
}
}
BOOL CreateShortcut( LPCWSTR pwszShortcut,
LPCWSTR pwszDescription, LPCWSTR pwszDirectory,
LPCWSTR pwszFileName, LPCWSTR pwszArguments, LPCWSTR pwszWorkingDir,
WORD wHotKey, INT nShowCmd, LPCWSTR pwszIconFile, DWORD dwIconIndex )
{
// local variables
CHString str;
HRESULT hr = S_OK;
HANDLE hFile = NULL;
BOOL bResult = FALSE;
IShellLinkW* pShellLink = NULL;
IPersistFile* pPersistFile = NULL;
// check the input parameters
// we dont care about the input for pwszArguments parameter
if ( pwszShortcut == NULL ||
pwszDescription == NULL || pwszDirectory == NULL ||
pwszFileName == NULL || pwszWorkingDir == NULL || pwszIconFile == NULL )
{
return FALSE;
}
try
{
//
// check if shortcut is already existing at this location or not
//
// prepare the link name and save it
str.Format( L"%s%s", pwszDirectory, pwszShortcut );
if ( str.Mid( str.GetLength() - 4 ).CompareNoCase( L".lnk" ) != 0 )
{
str += ".lnk";
}
// try to open the file
hFile = CreateFileW( str, GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile != INVALID_HANDLE_VALUE )
{
// close the handle to the file
CloseHandle( hFile );
// shortcut is alreadt existing -- so, dont create it again
bResult = TRUE;
goto cleanup;
}
//
// shortcut is not existing -- so we need to create it now
//
// get the pointer to the IShellLink interface
SAFE_EXECUTE_CS( CoCreateInstance( CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER, IID_IShellLinkW, (LPVOID*) &pShellLink ) );
// get the pointer to the IPersistFile interface
SAFE_EXECUTE_CS( pShellLink->QueryInterface( IID_IPersistFile, (LPVOID*) &pPersistFile ) );
// set the working directory for the shortcut.
SAFE_EXECUTE_CS( pShellLink->SetWorkingDirectory( pwszWorkingDir ) );
// prepare the shortcut name -- path (working dir) + file name -- finally set the path
// NOTE: we assume path containded in pwszWorkingDir ends with "\"
str.Format( L"%s%s", pwszWorkingDir, pwszFileName );
SAFE_EXECUTE_CS( pShellLink->SetPath( str ) );
// check if arguments needs to set
if ( pwszArguments == NULL || lstrlenW( pwszArguments ) > 0 )
{
SAFE_EXECUTE_CS( pShellLink->SetArguments( pwszArguments ) );
}
// set the description
SAFE_EXECUTE_CS( pShellLink->SetDescription( pwszDescription ) );
// set icon location
SAFE_EXECUTE_CS( pShellLink->SetIconLocation(
pwszIconFile, ((dwIconIndex == MSI_NULL_INTEGER) ? 0 : dwIconIndex) ) );
// set hotkey
if ( wHotKey != MSI_NULL_INTEGER )
{
SAFE_EXECUTE_CS( pShellLink->SetHotkey( wHotKey ) );
}
// set showcmd
if ( nShowCmd != MSI_NULL_INTEGER )
{
SAFE_EXECUTE_CS( pShellLink->SetShowCmd( nShowCmd ) );
}
// prepare the link name and save it
str.Format( L"%s%s", pwszDirectory, pwszShortcut );
if ( str.Mid( str.GetLength() - 4 ).CompareNoCase( L".lnk" ) != 0 )
{
str += ".lnk";
}
// ...
SAFE_EXECUTE_CS( pPersistFile->Save( str, TRUE ) );
// mark the result as success
bResult = TRUE;
}
catch( ... )
{
bResult = FALSE;
}
// default clean up
cleanup:
// release the interfaces
SAFE_RELEASE( pShellLink );
SAFE_RELEASE( pPersistFile );
// return
return bResult;
}
extern "C" ADMINPAK_API int _stdcall fnReCreateShortcuts( MSIHANDLE hInstall )
{
// local variables
CHString str;
HRESULT hr = S_OK;
BOOL bFileFound = FALSE;
BOOL bCreateShortcut = FALSE;
DWORD dwResult = ERROR_SUCCESS;
// MSI handles
PMSIHANDLE hView = NULL;
PMSIHANDLE hRecord = NULL;
PMSIHANDLE hDatabase = NULL;
// query field variables
WORD wHotKey = 0;
INT nShowCmd = 0;
CHString strShortcut;
CHString strFileName;
CHString strIconFile;
CHString strDirectory;
CHString strArguments;
CHString strCondition;
DWORD dwIconIndex = 0;
CHString strWorkingDir;
CHString strDescription;
CHString strIconDirectory;
DWORD dwConditionType = 0;
// sql for retrieving the information from MSI table
const WCHAR cwszSQL[] =
L" SELECT DISTINCT"
L" `Shortcut`.`Name`, `Shortcut`.`Description`, `Shortcut`.`Directory_`, `File`.`FileName`, "
L" `Shortcut`.`Arguments`, `Component`.`Directory_`, `Shortcut`.`Hotkey`, `Shortcut`.`ShowCmd`, "
L" `ShortcutIcons`.`IconDirectory_`, `ShortcutIcons`.`IconFile`, `ShortcutIcons`.`IconIndex`, "
L" `ShortcutIcons`.`ConditionType`, `ShortcutIcons`.`Condition` "
L" FROM `Shortcut`, `Component`, `File`, `ShortcutIcons` "
L" WHERE `Shortcut`.`Component_` = `Component`.`Component` "
L" AND `Component`.`KeyPath` = `File`.`File` "
L" AND `ShortcutIcons`.`Shortcut_` = `Shortcut`.`Shortcut`";
// column indices into the record
enum {
Shortcut = 1,
Description, Directory, FileName, Arguments,
WorkingDir, HotKey, ShowCmd, IconDirectory, IconFile, IconIndex, ConditionType, Condition
};
// initialize the COM library
hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
if ( FAILED( hr ) )
{
dwResult = ERROR_INVALID_HANDLE;
goto cleanup;
}
// get a handle on the MSI database
hDatabase = MsiGetActiveDatabase( hInstall );
if ( hDatabase == NULL )
{
dwResult = ERROR_INVALID_HANDLE;
goto cleanup;
}
// get a view of our table in the MSI
dwResult = MsiDatabaseOpenViewW( hDatabase, cwszSQL, &hView );
if ( dwResult != ERROR_SUCCESS )
{
dwResult = ERROR_INVALID_HANDLE;
goto cleanup;
}
// if no errors, get our records
dwResult = MsiViewExecute( hView, NULL );
if( dwResult != ERROR_SUCCESS )
{
dwResult = ERROR_INVALID_HANDLE;
goto cleanup;
}
// loop through the result records obtain via SQL
hRecord = NULL;
while( MsiViewFetch( hView, &hRecord ) == ERROR_SUCCESS )
{
// get the values from the record
wHotKey = (WORD) MsiRecordGetInteger( hRecord, HotKey );
nShowCmd = MsiRecordGetInteger( hRecord, ShowCmd );
dwIconIndex = MsiRecordGetInteger( hRecord, IconIndex );
dwConditionType = MsiRecordGetInteger( hRecord, ConditionType );
GetFieldValueFromRecord_String( hRecord, Shortcut, strShortcut );
GetFieldValueFromRecord_String( hRecord, FileName, strFileName );
GetFieldValueFromRecord_String( hRecord, IconFile, strIconFile );
GetFieldValueFromRecord_String( hRecord, Directory, strDirectory );
GetFieldValueFromRecord_String( hRecord, Arguments, strArguments );
GetFieldValueFromRecord_String( hRecord, Condition, strCondition );
GetFieldValueFromRecord_String( hRecord, WorkingDir, strWorkingDir );
GetFieldValueFromRecord_String( hRecord, Description, strDescription );
GetFieldValueFromRecord_String( hRecord, IconDirectory, strIconDirectory );
// shortcut name might contain '|' as seperator for 8.3 and long name formats -- suppress this
if( strShortcut.Find( L'|' ) != -1 )
{
str = strShortcut.Mid( strShortcut.Find( L'|' ) + 1 );
strShortcut = str; // store the result back
}
// transform the directory property references
TransformDirectory( hInstall, strDirectory );
TransformDirectory( hInstall, strWorkingDir );
TransformDirectory( hInstall, strIconDirectory );
// prepare the icon locatio
str.Format( L"%s%s", strIconDirectory, strIconFile );
strIconFile = str; // store the result back
//
// determine whether shortcut need to be created or not
//
// if the condition type is not specified, assume it "SEARCH"
if ( dwConditionType == MSI_NULL_INTEGER )
{
dwConditionType = SHI_TYPE_SEARCH;
}
// no matter what the "ConditionType" -- since creation of the shortcut very much depends
// on the existence of the file, we will try to locate for the file first -- this is necessary condition
// so, do a simple file search for the component key file
bFileFound = LocateFile( strFileName, strWorkingDir, NULL );
// proceed with rest of the conditions only if necessary condition is satisfied
if ( bFileFound == TRUE )
{
//
// now do additional sufficient conditon(s) if needed
//
bCreateShortcut = FALSE;
if ( dwConditionType == SHI_TYPE_SEARCH )
{
// search is already successful
bCreateShortcut = TRUE;
}
else if ( dwConditionType == SHI_TYPE_INSTALLCOMPONENT )
{
// check whether the component specified in 'Condition' field is installed or not
bCreateShortcut = IsComponentInstalled( strCondition );
}
else if ( dwConditionType == SHI_TYPE_CONDITION )
{
// evaluate the condition specified by the user
if ( MsiEvaluateConditionW( hInstall, strCondition ) == MSICONDITION_TRUE )
{
bCreateShortcut = TRUE;
}
}
// check the shortcut if needed
if ( bCreateShortcut == TRUE )
{
CreateShortcut( strShortcut,
strDescription, strDirectory, strFileName, strArguments,
strWorkingDir, wHotKey, nShowCmd, strIconFile, dwIconIndex );
}
}
// close the MSI handle to the current record object -- ignore the error
MsiCloseHandle( hRecord );
hRecord = NULL;
}
// mark the flag as success
dwResult = ERROR_SUCCESS;
//
// cleanup
//
cleanup:
// un-initialize the COM library
CoUninitialize();
// close the handle to the record
if ( hRecord != NULL )
{
MsiCloseHandle( hRecord );
hRecord = NULL;
}
// close View -- ignore the errors
if ( hView != NULL )
{
MsiViewClose( hView );
hView = NULL;
}
// close the database handle
if ( hDatabase != NULL )
{
MsiCloseHandle( hDatabase );
hDatabase = NULL;
}
// return
return dwResult;
}
BOOL LocateFile( LPCWSTR pwszFile, LPCWSTR pwszDirectory, PBOOL pbShortForm )
{
// local variables
INT nPosition = 0;
HANDLE hFind = NULL;
BOOL bFound = FALSE;
CHString strPath;
CHString strFileName;
WIN32_FIND_DATAW findData;
// check the optional parameter
if ( pbShortForm != NULL )
{
*pbShortForm = FALSE;
}
// check the input
if ( pwszFile == NULL || pwszDirectory == NULL )
{
return FALSE;
}
try
{
// init the variable with file name passed
strFileName = pwszFile;
// check whether user specified two formats for this file (8.3 and long format)
nPosition = strFileName.Find( L'|' );
if ( nPosition != -1 )
{
// extract the long file name first
CHString strTemp;
strTemp = strFileName.Mid( nPosition + 1 );
strFileName = strTemp;
// check the length of the file name
if ( strFileName.GetLength() == 0 )
{
// invalid file name format
return FALSE;
}
}
// prepare the path
strPath.Format( L"%s%s", pwszDirectory, strFileName );
// search for this file
bFound = FALSE;
hFind = FindFirstFileW( strPath, &findData );
if ( hFind == INVALID_HANDLE_VALUE )
{
// find failed -- may be file is not found -- confirm this
bFound = FALSE;
if ( GetLastError() == ERROR_FILE_NOT_FOUND )
{
// yes -- file is not found
}
}
else
{
// file is located
// take the actions needed
// close the handle to the file search first
FindClose( hFind );
hFind = NULL;
// set the flag
bFound = TRUE;
if ( pbShortForm != NULL )
{
*pbShortForm = FALSE;
}
}
//
// file is not found in long format
// may be, it is existed in 8.3 format
// so, check whether user supplied 8.3 file name for this file
if ( nPosition != -1 && bFound == FALSE )
{
// extract the 8.3 format of the file name
CHString strTemp;
strTemp = pwszFile;
strFileName = strTemp.Mid( 0, nPosition );
// prepare the path
strPath.Format( L"%s%s", pwszDirectory, strFileName );
// search for this file
bFound = FALSE;
hFind = FindFirstFileW( strPath, &findData );
if ( hFind == INVALID_HANDLE_VALUE )
{
// find failed -- may be file is not found -- confirm this
if ( GetLastError() == ERROR_FILE_NOT_FOUND )
{
// yes -- file is not found
}
}
else
{
// file is located
// take the actions needed
// close the handle to the file search first
FindClose( hFind );
hFind = NULL;
// set the flag
bFound = TRUE;
if ( pbShortForm != NULL )
{
*pbShortForm = TRUE;
}
}
}
}
catch( ... )
{
return FALSE;
}
// return the result of search
return bFound;
}
BOOL IsComponentInstalled( LPCWSTR pwszComponent )
{
// local variables
HKEY hKey = NULL;
LONG lResult = 0;
LONG lPosition = 0;
CHString strTemp;
CHString strComponent;
CHString strComponents;
BOOL bComponentInstalled = FALSE;
const WCHAR cwszSubKey[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager\\Subcomponents";
// open the registry path
lResult = RegOpenKeyExW( HKEY_LOCAL_MACHINE, cwszSubKey, 0, KEY_READ, &hKey );
if ( lResult != ERROR_SUCCESS )
{
SetLastError( lResult );
return FALSE;
}
//
// since components may be multiple -- we need to check for each and every component
//
try
{
// get the component -- ready for processing
strComponents = pwszComponent;
// loop until there are no more components
bComponentInstalled = FALSE;
while ( strComponents.GetLength() != 0 )
{
// extract the first component
lPosition = strComponents.Find( L';' );
if ( lPosition != -1 )
{
strComponent = strComponents.Mid( 0, lPosition );
strTemp = strComponents.Mid( lPosition + 1 );
strComponents = strTemp;
}
else
{
// there is only one component
strComponent = strComponents;
strComponents = L"";
}
// check for the components existence
if ( CheckForComponents( hKey, strComponent ) == TRUE )
{
// since this is an OR condition checking -- if atleast one component in installed
// then we will return from here itself as there wont be any meaning in checking for the
// existence of other components -- the condition is satisfied
bComponentInstalled = TRUE;
break;
}
}
}
catch( ... )
{
// ignore the exception
}
// we are done with the opened registry key -- we can close it
RegCloseKey( hKey );
hKey = NULL;
// return the result
return bComponentInstalled;
}
BOOL CheckForComponents( HKEY hKey, LPCWSTR pwszComponents )
{
// local variables
LONG lResult = 0;
DWORD dwType = 0;
DWORD dwSize = 0;
DWORD dwValue = 0;
CHString strTemp;
CHString strComponent;
CHString strComponents;
LONG lPosition = 0;
// check the input
if ( hKey == NULL || pwszComponents == NULL )
{
return FALSE;
}
try
{
// ...
strComponents = pwszComponents;
if ( strComponents.GetLength() == 0 )
{
return FALSE;
}
// loop until all the components are checked
while ( strComponents.GetLength() != 0 )
{
// extract the first component
lPosition = strComponent.Find( L',' );
if ( lPosition != -1 )
{
strComponent = strComponents.Mid( 0, lPosition );
strTemp = strComponents.Mid( lPosition + 1 );
strComponents = strTemp;
}
else
{
// there is only one component
strComponent = strComponents;
strComponents = L"";
}
// now check for this component in registry
dwSize = sizeof( DWORD );
lResult = RegQueryValueExW( hKey, strComponent, NULL, &dwType, (LPBYTE) &dwValue, &dwSize );
// *) check result of the registry query operation
// *) confirm the type of the value -- it should be REG_DWORD
// *) also check the state of the component and return the accordingly
// 1 Installed
// 0 Not Installed
strTemp.Format( L"%d", dwValue );
if ( lResult != ERROR_SUCCESS || dwType != REG_DWORD || dwValue == 0 )
{
// no matter what is the reason -- we will treat this as
// component is not installed at all
//
// and since this is an AND condition checking -- if atleast one component in not installed
// then we will return from here itself as there wont be any meaning in checking for the
// existence of other components
return FALSE;
}
}
}
catch( ... )
{
return FALSE;
}
// if the control came to this point -- it is obvious that required components are installed
return TRUE;
}
BOOL TransformDirectory( MSIHANDLE hInstall, CHString& strDirectory )
{
// local variables
CHString strActualDirectory;
// check the input parameters
if ( hInstall == NULL )
{
return FALSE;
}
try
{
// get the property value
PropertyGet_String( hInstall, strDirectory, strActualDirectory );
// assign the property value to the input argument
strDirectory = strActualDirectory;
// return
return TRUE;
}
catch( ... )
{
return FALSE;
}
}
// remove the shortcuts that are created by W2K version of adminpak.msi (W2K -> .NET upgrade scenario)
extern "C" ADMINPAK_API int _stdcall fnDeleteW2KShortcuts( MSIHANDLE hInstall )
{
// local variables
CHString str;
HRESULT hr = S_OK;
BOOL bFileFound = FALSE;
BOOL bShortForm = FALSE;
BOOL bCreateShortcut = FALSE;
DWORD nPosition = 0;
DWORD dwResult = ERROR_SUCCESS;
// MSI handles
PMSIHANDLE hView = NULL;
PMSIHANDLE hRecord = NULL;
PMSIHANDLE hDatabase = NULL;
// query field variables
CHString strShortcut;
CHString strNewShortcut;
CHString strShortcutDirectory;
CHString strRecreate;
CHString strFileDirectory;
CHString strFileName;
CHString strArguments;
CHString strDescription;
CHString strIconDirectory;
CHString strIconFile;
DWORD dwIconIndex = 0;
DWORD dwConditionType = 0;
CHString strCondition;
// sql for retrieving the information from MSI table
const WCHAR cwszSQL[] = L"SELECT * FROM `W2KShortcutCleanup`";
// column indices into the record
enum {
Shortcut = 2,
ShortcutDirectory, Recreate, NewShortcut,
FileDirectory, FileName, Arguments, Description,
IconDirectory, IconFile, IconIndex, ConditionType, Condition
};
// initialize the COM library
hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
if ( FAILED( hr ) )
{
dwResult = ERROR_INVALID_HANDLE;
goto cleanup;
}
// get a handle on the MSI database
hDatabase = MsiGetActiveDatabase( hInstall );
if ( hDatabase == NULL )
{
dwResult = ERROR_INVALID_HANDLE;
goto cleanup;
}
// get a view of our table in the MSI
dwResult = MsiDatabaseOpenViewW( hDatabase, cwszSQL, &hView );
if ( dwResult != ERROR_SUCCESS )
{
dwResult = ERROR_INVALID_HANDLE;
goto cleanup;
}
// if no errors, get our records
dwResult = MsiViewExecute( hView, NULL );
if( dwResult != ERROR_SUCCESS )
{
dwResult = ERROR_INVALID_HANDLE;
goto cleanup;
}
try
{
// loop through the result records obtain via SQL
hRecord = NULL;
while( MsiViewFetch( hView, &hRecord ) == ERROR_SUCCESS )
{
// get the values from the record
dwIconIndex = MsiRecordGetInteger( hRecord, IconIndex );
dwConditionType = MsiRecordGetInteger( hRecord, ConditionType );
GetFieldValueFromRecord_String( hRecord, Shortcut, strShortcut );
GetFieldValueFromRecord_String( hRecord, NewShortcut, strNewShortcut );
GetFieldValueFromRecord_String( hRecord, Recreate, strRecreate );
GetFieldValueFromRecord_String( hRecord, FileName, strFileName );
GetFieldValueFromRecord_String( hRecord, IconFile, strIconFile );
GetFieldValueFromRecord_String( hRecord, Arguments, strArguments );
GetFieldValueFromRecord_String( hRecord, Condition, strCondition );
GetFieldValueFromRecord_String( hRecord, Description, strDescription );
GetFieldValueFromRecord_String( hRecord, FileDirectory, strFileDirectory );
GetFieldValueFromRecord_String( hRecord, IconDirectory, strIconDirectory );
GetFieldValueFromRecord_String( hRecord, ShortcutDirectory, strShortcutDirectory );
// transform the directory property references
TransformDirectory( hInstall, strFileDirectory );
TransformDirectory( hInstall, strIconDirectory );
TransformDirectory( hInstall, strShortcutDirectory );
// search for the existence of the shortcut
if ( LocateFile( strShortcut, strShortcutDirectory ) == FALSE )
{
// file is not found
goto loop_cleanup;
}
//
// shortcut is found
//
// delete the shortcut
//
// file might be in short name or long name -- so attempt to delete the appropriate file only
nPosition = strShortcut.Find( L'|' );
if ( nPosition != -1 )
{
if ( bShortForm == TRUE )
{
str = strShortcut.Mid( 0, nPosition );
}
else
{
str = strShortcut.Mid( nPosition + 1 );
}
// ...
strShortcut = str;
}
str.Format( L"%s%s", strShortcutDirectory, strShortcut );
if ( DeleteFileW( str ) == FALSE )
{
// failed to delete the file
goto loop_cleanup;
}
// check if the directory is empty or not --
// if the directory is empty, delete the directory also
if ( LocateFile( L"*.lnk", strShortcutDirectory ) == FALSE )
{
// directory is empty -- delete it
// NOTE: we dont care about the suceess of the function call
RemoveDirectoryW( strShortcutDirectory );
}
// check whether we need to recreate the shortcut or not
if ( strRecreate == L"N" )
{
// no need to create the shortcut
goto loop_cleanup;
}
//
// we need to recreate the shortcut
//
// prepare the icon location
str.Format( L"%s%s", strIconDirectory, strIconFile );
strIconFile = str; // store the result back
//
// determine whether shortcut need to be created or not
//
// if the condition type is not specified, assume it "SEARCH"
if ( dwConditionType == MSI_NULL_INTEGER )
{
dwConditionType = SHI_TYPE_SEARCH;
}
// no matter what the "ConditionType" -- since creation of the shortcut very much depends
// on the existence of the file, we will try to locate for the file first -- this is necessary condition
// so, do a simple file search for the component key file
bFileFound = LocateFile( strFileName, strFileDirectory );
// proceed with rest of the conditions only if necessary condition is satisfied
if ( bFileFound == TRUE )
{
//
// now do additional sufficient conditon(s) if needed
//
bCreateShortcut = FALSE;
if ( dwConditionType == SHI_TYPE_SEARCH )
{
// search is already successful
bCreateShortcut = TRUE;
}
else if ( dwConditionType == SHI_TYPE_INSTALLCOMPONENT )
{
// check whether the component specified in 'Condition' field is installed or not
bCreateShortcut = IsComponentInstalled( strCondition );
}
else if ( dwConditionType == SHI_TYPE_CONDITION )
{
// evaluate the condition specified by the user
if ( MsiEvaluateConditionW( hInstall, strCondition ) == MSICONDITION_TRUE )
{
bCreateShortcut = TRUE;
}
}
// check the shortcut if needed
if ( bCreateShortcut == TRUE )
{
CreateShortcut(
((strNewShortcut.GetLength() == 0) ? strShortcut : strNewShortcut), strDescription,
strShortcutDirectory, strFileName, strArguments, strFileDirectory, 0, 0, strIconFile, dwIconIndex );
}
}
loop_cleanup:
// close the MSI handle to the current record object -- ignore the error
MsiCloseHandle( hRecord );
hRecord = NULL;
}
// mark the flag as success
dwResult = ERROR_SUCCESS;
}
catch( ... )
{
// error
dwResult = ERROR_INVALID_HANDLE;
}
//
// cleanup
//
cleanup:
// un-initialize the COM library
CoUninitialize();
// close the handle to the record
if ( hRecord != NULL )
{
MsiCloseHandle( hRecord );
hRecord = NULL;
}
// close View -- ignore the errors
if ( hView != NULL )
{
MsiViewClose( hView );
hView = NULL;
}
// close the database handle
if ( hDatabase != NULL )
{
MsiCloseHandle( hDatabase );
hDatabase = NULL;
}
// return
return dwResult;
}