|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
lnkmig.c
Abstract:
<abstract>
Author:
Calin Negreanu (calinn) 08 Mar 2000
Revision History:
<alias> <date> <comments>
--*/
//
// Includes
//
#include "pch.h"
#include "logmsg.h"
#include "lnkmig.h"
#define DBG_LINKS "Links"
//
// Strings
//
// None
//
// Constants
//
// None
//
// Macros
//
// None
//
// Types
//
// None
//
// Globals
//
PMHANDLE g_LinksPool = NULL; MIG_ATTRIBUTEID g_LnkMigAttr_Shortcut = 0; MIG_ATTRIBUTEID g_CopyIfRelevantAttr; MIG_ATTRIBUTEID g_OsFileAttribute;
MIG_PROPERTYID g_LnkMigProp_Target = 0; MIG_PROPERTYID g_LnkMigProp_Params = 0; MIG_PROPERTYID g_LnkMigProp_WorkDir = 0; MIG_PROPERTYID g_LnkMigProp_RawWorkDir = 0; MIG_PROPERTYID g_LnkMigProp_IconPath = 0; MIG_PROPERTYID g_LnkMigProp_IconNumber = 0; MIG_PROPERTYID g_LnkMigProp_IconData = 0; MIG_PROPERTYID g_LnkMigProp_HotKey = 0; MIG_PROPERTYID g_LnkMigProp_DosApp = 0; MIG_PROPERTYID g_LnkMigProp_MsDosMode = 0; MIG_PROPERTYID g_LnkMigProp_ExtraData = 0;
MIG_OPERATIONID g_LnkMigOp_FixContent;
IShellLink *g_ShellLink = NULL; IPersistFile *g_PersistFile = NULL;
BOOL g_VcmMode = FALSE;
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
// None
//
// Macro expansion definition
//
// None
//
// Private prototypes
//
MIG_OBJECTENUMCALLBACK LinksCallback; MIG_PREENUMCALLBACK LnkMigPreEnumeration; MIG_POSTENUMCALLBACK LnkMigPostEnumeration; OPMAPPLYCALLBACK DoLnkContentFix; MIG_RESTORECALLBACK LinkRestoreCallback;
BOOL LinkDoesContentMatch ( IN BOOL AlreadyProcessed, IN MIG_OBJECTTYPEID SrcObjectTypeId, IN MIG_OBJECTSTRINGHANDLE SrcObjectName, IN PMIG_CONTENT SrcContent, IN MIG_OBJECTTYPEID DestObjectTypeId, IN MIG_OBJECTSTRINGHANDLE DestObjectName, IN PMIG_CONTENT DestContent, OUT PBOOL Identical, OUT PBOOL DifferentDetailsOnly );
//
// Code
//
BOOL pIsUncPath ( IN PCTSTR Path ) { return (Path && (Path[0] == TEXT('\\')) && (Path[1] == TEXT('\\'))); }
BOOL LinksInitialize ( VOID ) { g_LinksPool = PmCreateNamedPool ("Links"); return (g_LinksPool != NULL); }
VOID LinksTerminate ( VOID ) { if (g_LinksPool) { PmDestroyPool (g_LinksPool); g_LinksPool = NULL; } }
BOOL pCommonInitialize ( IN PMIG_LOGCALLBACK LogCallback ) { LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
g_LnkMigAttr_Shortcut = IsmRegisterAttribute (S_LNKMIGATTR_SHORTCUT, FALSE); g_CopyIfRelevantAttr = IsmRegisterAttribute (S_ATTRIBUTE_COPYIFRELEVANT, FALSE);
g_LnkMigProp_Target = IsmRegisterProperty (S_LNKMIGPROP_TARGET, FALSE); g_LnkMigProp_Params = IsmRegisterProperty (S_LNKMIGPROP_PARAMS, FALSE); g_LnkMigProp_WorkDir = IsmRegisterProperty (S_LNKMIGPROP_WORKDIR, FALSE); g_LnkMigProp_RawWorkDir = IsmRegisterProperty (S_LNKMIGPROP_RAWWORKDIR, FALSE); g_LnkMigProp_IconPath = IsmRegisterProperty (S_LNKMIGPROP_ICONPATH, FALSE); g_LnkMigProp_IconNumber = IsmRegisterProperty (S_LNKMIGPROP_ICONNUMBER, FALSE); g_LnkMigProp_IconData = IsmRegisterProperty (S_LNKMIGPROP_ICONDATA, FALSE); g_LnkMigProp_HotKey = IsmRegisterProperty (S_LNKMIGPROP_HOTKEY, FALSE); g_LnkMigProp_DosApp = IsmRegisterProperty (S_LNKMIGPROP_DOSAPP, FALSE); g_LnkMigProp_MsDosMode = IsmRegisterProperty (S_LNKMIGPROP_MSDOSMODE, FALSE); g_LnkMigProp_ExtraData = IsmRegisterProperty (S_LNKMIGPROP_EXTRADATA, FALSE);
g_LnkMigOp_FixContent = IsmRegisterOperation (S_OPERATION_LNKMIG_FIXCONTENT, FALSE);
return TRUE; }
BOOL WINAPI LnkMigVcmInitialize ( IN PMIG_LOGCALLBACK LogCallback, IN PVOID Reserved ) { g_VcmMode = TRUE; return pCommonInitialize (LogCallback); }
BOOL WINAPI LnkMigSgmInitialize ( IN PMIG_LOGCALLBACK LogCallback, IN PVOID Reserved ) { return pCommonInitialize (LogCallback); }
BOOL LnkMigPreEnumeration ( VOID ) { if (!InitCOMLink (&g_ShellLink, &g_PersistFile)) { DEBUGMSG ((DBG_ERROR, "Error initializing COM %d", GetLastError ())); } return TRUE; }
BOOL LnkMigPostEnumeration ( VOID ) { FreeCOMLink (&g_ShellLink, &g_PersistFile); g_ShellLink = NULL; g_PersistFile = NULL; return TRUE; }
MIG_OBJECTSTRINGHANDLE pBuildEncodedNameFromNativeName ( IN PCTSTR NativeName ) { PCTSTR nodeName; PTSTR leafName; MIG_OBJECTSTRINGHANDLE result = NULL; MIG_OBJECT_ENUM objEnum;
result = IsmCreateObjectHandle (NativeName, NULL); if (result) { if (IsmEnumFirstSourceObject (&objEnum, MIG_FILE_TYPE | PLATFORM_SOURCE, result)) { IsmAbortObjectEnum (&objEnum); return result; } IsmDestroyObjectHandle (result); result = NULL; }
// we have to split this path because it could be a file
nodeName = DuplicatePathString (NativeName, 0); leafName = _tcsrchr (nodeName, TEXT('\\')); if (leafName) { *leafName = 0; leafName ++; result = IsmCreateObjectHandle (nodeName, leafName); } else { // we have no \ in the name. This can only mean that the
// file specification has only a leaf
result = IsmCreateObjectHandle (NULL, NativeName); } FreePathString (nodeName);
return result; }
PCTSTR pSpecialExpandEnvironmentString ( IN PCTSTR SrcString, IN PCTSTR Context ) { PCTSTR result = NULL; PCTSTR srcWinDir = NULL; PCTSTR destWinDir = NULL; PTSTR newSrcString = NULL; PCTSTR copyPtr = NULL;
if (IsmGetRealPlatform () == PLATFORM_DESTINATION) { // Special case where this is actually the destination machine and
// first part of SrcString matches %windir%. In this case, it is likely that
// the shell replaced the source windows directory with the destination one.
// We need to change it back
destWinDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT ("%windir%"), NULL); if (destWinDir) { if (StringIPrefix (SrcString, destWinDir)) { srcWinDir = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT ("%windir%"), NULL); if (srcWinDir) { newSrcString = IsmGetMemory (SizeOfString (srcWinDir) + SizeOfString (SrcString)); if (newSrcString) { copyPtr = SrcString + TcharCount (destWinDir); StringCopy (newSrcString, srcWinDir); StringCat (newSrcString, copyPtr); } IsmReleaseMemory (srcWinDir); srcWinDir = NULL; } } IsmReleaseMemory (destWinDir); destWinDir = NULL; } }
result = IsmExpandEnvironmentString ( PLATFORM_SOURCE, S_SYSENVVAR_GROUP, newSrcString?newSrcString:SrcString, Context );
if (newSrcString) { IsmReleaseMemory (newSrcString); }
return result; }
MIG_OBJECTSTRINGHANDLE pTryObject ( IN PCTSTR LeafName, IN PCTSTR EnvName ) { MIG_OBJECT_ENUM objEnum; PTSTR envData = NULL; DWORD envSize = 0; PATH_ENUM pathEnum; MIG_OBJECTSTRINGHANDLE result = NULL;
if (IsmGetEnvironmentString ( PLATFORM_SOURCE, S_SYSENVVAR_GROUP, EnvName, NULL, 0, &envSize )) { envData = IsmGetMemory (envSize); if (envData) { if (IsmGetEnvironmentString ( PLATFORM_SOURCE, S_SYSENVVAR_GROUP, EnvName, envData, envSize, &envSize )) { // let's enumerate the paths from this env variable (should be separated by ;)
if (EnumFirstPathEx (&pathEnum, envData, NULL, NULL, FALSE)) { do { result = IsmCreateObjectHandle (pathEnum.PtrCurrPath, LeafName); if (IsmEnumFirstSourceObject (&objEnum, MIG_FILE_TYPE | PLATFORM_SOURCE, result)) { IsmAbortObjectEnum (&objEnum); } else { IsmDestroyObjectHandle (result); result = NULL; } if (result) { AbortPathEnum (&pathEnum); break; } } while (EnumNextPath (&pathEnum)); } } IsmReleaseMemory (envData); envData = NULL; } } return result; }
MIG_OBJECTSTRINGHANDLE pGetFullEncodedName ( IN MIG_OBJECTSTRINGHANDLE ObjectName ) { PCTSTR node = NULL, leaf = NULL; MIG_OBJECTSTRINGHANDLE result = NULL;
// let's split the ObjectName into node and leaf.
// If it's leaf only we are going to try to find
// that leaf in %path%, %windir% and %system% and
// reconstruct the object name.
if (IsmCreateObjectStringsFromHandle (ObjectName, &node, &leaf)) {
if (!node) { // this is leaf only. We need to find out where this leaf
// is located. We are going to look for the leaf in the
// following directories (in this order)
// 1. %system%
// 2. %system16%
// 3. %windir%
// 4. All directories in %path% env. variable
result = pTryObject (leaf, TEXT("system")); if (!result) { result = pTryObject (leaf, TEXT("system16")); } if (!result) { result = pTryObject (leaf, TEXT("windir")); } if (!result) { result = pTryObject (leaf, TEXT("path")); } }
IsmDestroyObjectString (node); IsmDestroyObjectString (leaf); }
return result; }
BOOL pIsLnkExcluded ( IN MIG_OBJECTID ObjectId, IN PCTSTR Target, IN PCTSTR Params, IN PCTSTR WorkDir ) { PTSTR multiSz = NULL; MULTISZ_ENUM e; UINT sizeNeeded; HINF infHandle = INVALID_HANDLE_VALUE; ENVENTRY_TYPE dataType; INFSTRUCT is = INITINFSTRUCT_PMHANDLE; PCTSTR targetPattern = NULL; PCTSTR targetPatternExp = NULL; PCTSTR paramsPattern = NULL; PCTSTR paramsPatternExp = NULL; PCTSTR workDirPattern = NULL; PCTSTR workDirPatternExp = NULL; BOOL result = FALSE;
if (IsmIsAttributeSetOnObjectId (ObjectId, g_CopyIfRelevantAttr)) { // let's look in the INFs in section [ExcludedLinks] and see if our LNK matches
// one of the lines. If it does and it has the CopyIfRelevand attribute then
// it's excluded
if (IsmGetEnvironmentValue ( IsmGetRealPlatform (), NULL, S_GLOBAL_INF_HANDLE, (PBYTE)(&infHandle), sizeof (HINF), &sizeNeeded, &dataType ) && (sizeNeeded == sizeof (HINF)) && (dataType == ENVENTRY_BINARY) ) {
if (InfFindFirstLine (infHandle, TEXT("ExcludedLinks"), NULL, &is)) {
do { targetPattern = InfGetStringField (&is, 1); targetPatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, targetPattern, NULL); if (!targetPatternExp) { targetPatternExp = targetPattern; } paramsPattern = InfGetStringField (&is, 2); paramsPatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, paramsPattern, NULL); if (!paramsPatternExp) { paramsPatternExp = paramsPattern; } workDirPattern = InfGetStringField (&is, 3); workDirPatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, workDirPattern, NULL); if (!workDirPatternExp) { workDirPatternExp = workDirPattern; } if (IsPatternMatch (targetPatternExp?targetPatternExp:TEXT("*"), Target?Target:TEXT("")) && IsPatternMatch (paramsPatternExp?paramsPatternExp:TEXT("*"), Params?Params:TEXT("")) && IsPatternMatch (workDirPatternExp?workDirPatternExp:TEXT("*"), WorkDir?WorkDir:TEXT("")) ) { result = TRUE; if (workDirPatternExp && (workDirPatternExp != workDirPattern)) { IsmReleaseMemory (workDirPatternExp); workDirPatternExp = NULL; } if (paramsPatternExp && (paramsPatternExp != paramsPattern)) { IsmReleaseMemory (paramsPatternExp); paramsPatternExp = NULL; } if (targetPatternExp && (targetPatternExp != targetPattern)) { IsmReleaseMemory (targetPatternExp); targetPatternExp = NULL; } break; } if (workDirPatternExp && (workDirPatternExp != workDirPattern)) { IsmReleaseMemory (workDirPatternExp); workDirPatternExp = NULL; } if (paramsPatternExp && (paramsPatternExp != paramsPattern)) { IsmReleaseMemory (paramsPatternExp); paramsPatternExp = NULL; } if (targetPatternExp && (targetPatternExp != targetPattern)) { IsmReleaseMemory (targetPatternExp); targetPatternExp = NULL; } } while (InfFindNextLine (&is)); }
InfNameHandle (infHandle, NULL, FALSE);
} else {
if (IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, NULL, 0, &sizeNeeded, NULL)) { __try { multiSz = AllocText (sizeNeeded);
if (!IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, (PBYTE) multiSz, sizeNeeded, NULL, NULL)) { __leave; }
if (EnumFirstMultiSz (&e, multiSz)) {
do {
infHandle = InfOpenInfFile (e.CurrentString); if (infHandle != INVALID_HANDLE_VALUE) {
if (InfFindFirstLine (infHandle, TEXT("ExcludedLinks"), NULL, &is)) {
do { targetPattern = InfGetStringField (&is, 1); paramsPattern = InfGetStringField (&is, 2); workDirPattern = InfGetStringField (&is, 3); if (IsPatternMatch (targetPattern?targetPattern:TEXT("*"), Target?Target:TEXT("")) && IsPatternMatch (paramsPattern?paramsPattern:TEXT("*"), Params?Params:TEXT("")) && IsPatternMatch (workDirPattern?workDirPattern:TEXT("*"), WorkDir?WorkDir:TEXT("")) ) { result = TRUE; break; } } while (InfFindNextLine (&is)); } }
InfCloseInfFile (infHandle); infHandle = INVALID_HANDLE_VALUE;
if (result) { break; }
} while (EnumNextMultiSz (&e));
} } __finally { FreeText (multiSz); } } }
InfResetInfStruct (&is); }
return result; }
UINT LinksCallback ( IN PCMIG_OBJECTENUMDATA Data, IN ULONG_PTR CallerArg ) { MIG_OBJECTID objectId; BOOL extractResult = FALSE; PCTSTR lnkTarget = NULL; PCTSTR newLnkTarget = NULL; PCTSTR expLnkTarget = NULL; PCTSTR lnkParams = NULL; PCTSTR lnkWorkDir = NULL; PCTSTR lnkIconPath = NULL; INT lnkIconNumber; WORD lnkHotKey; BOOL lnkDosApp; BOOL lnkMsDosMode; LNK_EXTRA_DATA lnkExtraData; MIG_OBJECTSTRINGHANDLE encodedName; MIG_OBJECTSTRINGHANDLE longEncodedName; MIG_OBJECTSTRINGHANDLE fullEncodedName; MIG_BLOB migBlob; PCTSTR expTmpStr; MIG_CONTENT lnkContent; MIG_CONTENT lnkIconContent; PICON_GROUP iconGroup = NULL; ICON_SGROUP iconSGroup; PCTSTR lnkIconResId = NULL; PCTSTR extPtr = NULL; BOOL exeDefaultIcon = FALSE;
if (Data->IsLeaf) {
objectId = IsmGetObjectIdFromName (MIG_FILE_TYPE, Data->ObjectName, TRUE); if (IsmIsPersistentObjectId (objectId)) {
IsmSetAttributeOnObjectId (objectId, g_LnkMigAttr_Shortcut);
if (IsmAcquireObjectEx ( Data->ObjectTypeId, Data->ObjectName, &lnkContent, CONTENTTYPE_FILE, 0 )) {
if (lnkContent.ContentInFile && lnkContent.FileContent.ContentPath) {
if (ExtractShortcutInfo ( lnkContent.FileContent.ContentPath, &lnkTarget, &lnkParams, &lnkWorkDir, &lnkIconPath, &lnkIconNumber, &lnkHotKey, &lnkDosApp, &lnkMsDosMode, &lnkExtraData, g_ShellLink, g_PersistFile )) { // let's check if the LNK is excluded
if (pIsLnkExcluded ( objectId, lnkTarget, lnkParams, lnkWorkDir )) { IsmClearPersistenceOnObjectId (objectId); } else { // let's get all the paths through the hooks and add everything as properties of this shortcut
if (lnkTarget) { if (*lnkTarget) { // If we are on the destination system, we are going to have major problems here.
// If the LNK had IDLISTs, we are going to get back a path that's local to the
// destination machine. For example if the target was c:\Windows\Favorites on the
// source system and that was the CSIDL_FAVORITES we are going to get back:
// c:\Documents and Settings\username\Favorites.
// Because of this problem we need to compress the path and then expand it back
// using env. variables from the source system.
if (IsmGetRealPlatform () == PLATFORM_DESTINATION) { newLnkTarget = IsmCompressEnvironmentString ( PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, lnkTarget, Data->NativeObjectName, TRUE ); } // let's look if this is a valid file specification. If it is not, it might be
// an URL or something else, so we will just migrate the thing
expTmpStr = pSpecialExpandEnvironmentString (newLnkTarget?newLnkTarget:lnkTarget, Data->NativeObjectName); if (IsValidFileSpec (expTmpStr)) { // we are going to need this (maybe) later, if the icon path is NULL and this is an EXE
expLnkTarget = DuplicatePathString (expTmpStr, 0);
encodedName = pBuildEncodedNameFromNativeName (expTmpStr); longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, encodedName); if (!longEncodedName) { longEncodedName = encodedName; } IsmExecuteHooks (MIG_FILE_TYPE|PLATFORM_SOURCE, longEncodedName); if (!g_VcmMode) { migBlob.Type = BLOBTYPE_STRING; migBlob.String = longEncodedName; IsmAddPropertyToObjectId (objectId, g_LnkMigProp_Target, &migBlob); } else { // persist the target so we can examine it later
if (!IsmIsPersistentObject (MIG_FILE_TYPE, longEncodedName)) { IsmMakePersistentObject (MIG_FILE_TYPE, longEncodedName); IsmMakeNonCriticalObject (MIG_FILE_TYPE, longEncodedName); } } if (longEncodedName != encodedName) { IsmDestroyObjectHandle (longEncodedName); } if (encodedName) { IsmDestroyObjectHandle (encodedName); } } else { encodedName = pBuildEncodedNameFromNativeName (expTmpStr); if (!g_VcmMode) { migBlob.Type = BLOBTYPE_STRING; migBlob.String = encodedName; IsmAddPropertyToObjectId (objectId, g_LnkMigProp_Target, &migBlob); } if (encodedName) { IsmDestroyObjectHandle (encodedName); } } if (newLnkTarget) { IsmReleaseMemory (newLnkTarget); newLnkTarget = NULL; } IsmReleaseMemory (expTmpStr); expTmpStr = NULL; } else { if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) { IsmClearPersistenceOnObjectId (objectId); } } FreePathString (lnkTarget); } else { if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) { IsmClearPersistenceOnObjectId (objectId); } } if (lnkParams) { if (*lnkParams) { if (!g_VcmMode) { migBlob.Type = BLOBTYPE_STRING; migBlob.String = lnkParams; IsmAddPropertyToObjectId (objectId, g_LnkMigProp_Params, &migBlob); } } FreePathString (lnkParams); } if (lnkWorkDir) { if (*lnkWorkDir) { // let's save the raw working directory
if (!g_VcmMode) { migBlob.Type = BLOBTYPE_STRING; migBlob.String = lnkWorkDir; IsmAddPropertyToObjectId (objectId, g_LnkMigProp_RawWorkDir, &migBlob); } expTmpStr = pSpecialExpandEnvironmentString (lnkWorkDir, Data->NativeObjectName); if (IsValidFileSpec (expTmpStr)) { encodedName = pBuildEncodedNameFromNativeName (expTmpStr); longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, encodedName); if (!longEncodedName) { longEncodedName = encodedName; } IsmExecuteHooks (MIG_FILE_TYPE|PLATFORM_SOURCE, longEncodedName); if (!g_VcmMode) { migBlob.Type = BLOBTYPE_STRING; migBlob.String = longEncodedName; IsmAddPropertyToObjectId (objectId, g_LnkMigProp_WorkDir, &migBlob); } else { // persist the working directory (it has almost no space impact)
// so we can examine it later
if (!IsmIsPersistentObject (MIG_FILE_TYPE, longEncodedName)) { IsmMakePersistentObject (MIG_FILE_TYPE, longEncodedName); IsmMakeNonCriticalObject (MIG_FILE_TYPE, longEncodedName); } } if (longEncodedName != encodedName) { IsmDestroyObjectHandle (longEncodedName); } if (encodedName) { IsmDestroyObjectHandle (encodedName); } } else { encodedName = pBuildEncodedNameFromNativeName (expTmpStr); if (!g_VcmMode) { migBlob.Type = BLOBTYPE_STRING; migBlob.String = encodedName; IsmAddPropertyToObjectId (objectId, g_LnkMigProp_WorkDir, &migBlob); } if (encodedName) { IsmDestroyObjectHandle (encodedName); } } IsmReleaseMemory (expTmpStr); expTmpStr = NULL; } FreePathString (lnkWorkDir); } if (((!lnkIconPath) || (!(*lnkIconPath))) && expLnkTarget) { extPtr = GetFileExtensionFromPath (expLnkTarget); if (extPtr) { exeDefaultIcon = StringIMatch (extPtr, TEXT("EXE")); if (exeDefaultIcon) { if (lnkIconPath) { FreePathString (lnkIconPath); } lnkIconPath = expLnkTarget; } } } if (lnkIconPath) { if (*lnkIconPath) { // let's look if this is a valid file specification. If it is not, it might be
// an URL or something else, so we will just migrate the thing
expTmpStr = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, lnkIconPath, Data->NativeObjectName); if (IsValidFileSpec (expTmpStr)) { encodedName = pBuildEncodedNameFromNativeName (expTmpStr); longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, encodedName); if (!longEncodedName) { longEncodedName = encodedName; } // Sometimes the icon is specified without full path (like foo.dll instead
// of c:\windows\system\foo.dll). When this is the case we are going to
// walk the %path% and %windir% and %system% and try to find the file there.
fullEncodedName = pGetFullEncodedName (longEncodedName); if (fullEncodedName) { if (longEncodedName != encodedName) { IsmDestroyObjectHandle (longEncodedName); } longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, fullEncodedName); if (!longEncodedName) { longEncodedName = fullEncodedName; } else { IsmDestroyObjectHandle (fullEncodedName); fullEncodedName = NULL; } } IsmExecuteHooks (MIG_FILE_TYPE|PLATFORM_SOURCE, longEncodedName); if (!g_VcmMode) { if (!exeDefaultIcon) { migBlob.Type = BLOBTYPE_STRING; migBlob.String = longEncodedName; IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconPath, &migBlob); }
// one last thing: let's extract the icon and preserve it just in case.
if (IsmAcquireObjectEx ( MIG_FILE_TYPE, longEncodedName, &lnkIconContent, CONTENTTYPE_FILE, 0 )) { if (lnkIconContent.ContentInFile && lnkIconContent.FileContent.ContentPath) { if (lnkIconNumber >= 0) { iconGroup = IcoExtractIconGroupByIndexFromFile ( lnkIconContent.FileContent.ContentPath, lnkIconNumber, NULL ); } else { lnkIconResId = (PCTSTR) (LONG_PTR) (-lnkIconNumber); iconGroup = IcoExtractIconGroupFromFile ( lnkIconContent.FileContent.ContentPath, lnkIconResId, NULL ); } if (iconGroup) { if (IcoSerializeIconGroup (iconGroup, &iconSGroup)) { migBlob.Type = BLOBTYPE_BINARY; migBlob.BinaryData = (PCBYTE)(iconSGroup.Data); migBlob.BinarySize = iconSGroup.DataSize; IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconData, &migBlob); IcoReleaseIconSGroup (&iconSGroup); } IcoReleaseIconGroup (iconGroup); } } IsmReleaseObject (&lnkIconContent); } } else { // persist the icon file so we can examine it later
if (!IsmIsPersistentObject (MIG_FILE_TYPE, longEncodedName)) { IsmMakePersistentObject (MIG_FILE_TYPE, longEncodedName); IsmMakeNonCriticalObject (MIG_FILE_TYPE, longEncodedName); } }
if (longEncodedName != encodedName) { IsmDestroyObjectHandle (longEncodedName); longEncodedName = NULL; } if (encodedName) { IsmDestroyObjectHandle (encodedName); encodedName = NULL; } } else { encodedName = pBuildEncodedNameFromNativeName (expTmpStr); if (!g_VcmMode) { if (!exeDefaultIcon) { migBlob.Type = BLOBTYPE_STRING; migBlob.String = encodedName; IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconPath, &migBlob); } } if (encodedName) { IsmDestroyObjectHandle (encodedName); } }
IsmReleaseMemory (expTmpStr); expTmpStr = NULL; } if (lnkIconPath != expLnkTarget) { FreePathString (lnkIconPath); } }
if (!g_VcmMode) { migBlob.Type = BLOBTYPE_BINARY; migBlob.BinaryData = (PCBYTE)(&lnkIconNumber); migBlob.BinarySize = sizeof (INT); IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconNumber, &migBlob); migBlob.Type = BLOBTYPE_BINARY; migBlob.BinaryData = (PCBYTE)(&lnkDosApp); migBlob.BinarySize = sizeof (BOOL); IsmAddPropertyToObjectId (objectId, g_LnkMigProp_DosApp, &migBlob); if (lnkDosApp) { migBlob.Type = BLOBTYPE_BINARY; migBlob.BinaryData = (PCBYTE)(&lnkMsDosMode); migBlob.BinarySize = sizeof (BOOL); IsmAddPropertyToObjectId (objectId, g_LnkMigProp_MsDosMode, &migBlob); migBlob.Type = BLOBTYPE_BINARY; migBlob.BinaryData = (PCBYTE)(&lnkExtraData); migBlob.BinarySize = sizeof (LNK_EXTRA_DATA); IsmAddPropertyToObjectId (objectId, g_LnkMigProp_ExtraData, &migBlob); } else { migBlob.Type = BLOBTYPE_BINARY; migBlob.BinaryData = (PCBYTE)(&lnkHotKey); migBlob.BinarySize = sizeof (WORD); IsmAddPropertyToObjectId (objectId, g_LnkMigProp_HotKey, &migBlob); } IsmSetOperationOnObjectId ( objectId, g_LnkMigOp_FixContent, NULL, NULL ); }
if (expLnkTarget) { FreePathString (expLnkTarget); expLnkTarget = NULL; } }
} else { if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) { IsmClearPersistenceOnObjectId (objectId); } } } else { if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) { IsmClearPersistenceOnObjectId (objectId); } } IsmReleaseObject (&lnkContent); } else { if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) { IsmClearPersistenceOnObjectId (objectId); } } } } return CALLBACK_ENUM_CONTINUE; }
BOOL pCommonLnkMigQueueEnumeration ( VOID ) { ENCODEDSTRHANDLE pattern;
// hook all LNK files
pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, TEXT("*.lnk"), TRUE); if (pattern) { IsmHookEnumeration (MIG_FILE_TYPE, pattern, LinksCallback, (ULONG_PTR) 0, TEXT("Links.Files")); IsmDestroyObjectHandle (pattern); }
// hook all PIF files
pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, TEXT("*.pif"), TRUE); if (pattern) { IsmHookEnumeration (MIG_FILE_TYPE, pattern, LinksCallback, (ULONG_PTR) 0, TEXT("Links.Files")); IsmDestroyObjectHandle (pattern); }
// hook all URL files
pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, TEXT("*.url"), TRUE); if (pattern) { IsmHookEnumeration (MIG_FILE_TYPE, pattern, LinksCallback, (ULONG_PTR) 0, TEXT("Links.Files")); IsmDestroyObjectHandle (pattern); }
IsmRegisterPreEnumerationCallback (LnkMigPreEnumeration, NULL); IsmRegisterPostEnumerationCallback (LnkMigPostEnumeration, NULL);
return TRUE; }
BOOL WINAPI LnkMigVcmQueueEnumeration ( IN PVOID Reserved ) { return pCommonLnkMigQueueEnumeration (); }
BOOL WINAPI LnkMigSgmQueueEnumeration ( IN PVOID Reserved ) { return pCommonLnkMigQueueEnumeration (); }
BOOL pLnkFindFile ( IN PCTSTR FileName ) { MIG_OBJECTSTRINGHANDLE objectName; PTSTR node, leaf, leafPtr; BOOL result = FALSE;
objectName = IsmCreateObjectHandle (FileName, NULL); if (objectName) { if (IsmGetObjectIdFromName (MIG_FILE_TYPE | PLATFORM_SOURCE, objectName, TRUE) != 0) { result = TRUE; } IsmDestroyObjectHandle (objectName); } if (!result) { node = DuplicateText (FileName); leaf = _tcsrchr (node, TEXT('\\')); if (leaf) { leafPtr = (PTSTR) leaf; leaf = _tcsinc (leaf); *leafPtr = 0; objectName = IsmCreateObjectHandle (node, leaf); if (objectName) { if (IsmGetObjectIdFromName (MIG_FILE_TYPE | PLATFORM_SOURCE, objectName, TRUE) != 0) { result = TRUE; } IsmDestroyObjectHandle (objectName); } *leafPtr = TEXT('\\'); } FreeText (node); }
return result; }
BOOL pLnkSearchPath ( IN PCTSTR FileName, IN DWORD BufferLength, OUT PTSTR Buffer ) { return FALSE; }
MIG_OBJECTSTRINGHANDLE pLnkSimpleTryHandle ( IN PCTSTR FullPath ) { PCTSTR buffer; PTSTR leafPtr, leaf; MIG_OBJECTSTRINGHANDLE source = NULL; MIG_OBJECTSTRINGHANDLE result = NULL; PTSTR workingPath; PCTSTR sanitizedPath; BOOL orgDeleted = FALSE; BOOL orgReplaced = FALSE; PCTSTR saved = NULL;
sanitizedPath = SanitizePath (FullPath); if (!sanitizedPath) { return NULL; }
source = IsmCreateObjectHandle (sanitizedPath, NULL); if (source) { result = IsmFilterObject ( MIG_FILE_TYPE | PLATFORM_SOURCE, source, NULL, &orgDeleted, &orgReplaced ); // we do not want replaced directories
// since they can be false hits
if (orgDeleted) { if (result) { saved = result; result = NULL; } } if (!result && !orgDeleted) { result = source; } else { IsmDestroyObjectHandle (source); source = NULL; } }
if (result) { goto exit; }
buffer = DuplicatePathString (sanitizedPath, 0);
leaf = _tcsrchr (buffer, TEXT('\\'));
if (leaf) { leafPtr = leaf; leaf = _tcsinc (leaf); *leafPtr = 0; source = IsmCreateObjectHandle (buffer, leaf); *leafPtr = TEXT('\\'); }
FreePathString (buffer);
if (source) { result = IsmFilterObject ( MIG_FILE_TYPE | PLATFORM_SOURCE, source, NULL, &orgDeleted, &orgReplaced ); if (!result && !orgDeleted) { result = source; } else { if (!result) { result = saved; } IsmDestroyObjectHandle (source); source = NULL; } }
if (result != saved) { IsmDestroyObjectHandle (saved); saved = NULL; }
exit: FreePathString (sanitizedPath); return result; }
MIG_OBJECTSTRINGHANDLE pLnkTryHandle ( IN PCTSTR FullPath, IN PCTSTR Hint, OUT PCTSTR *TrimmedResult ) { PATH_ENUM pathEnum; PCTSTR newPath; MIG_OBJECTSTRINGHANDLE result = NULL; PCTSTR nativeName = NULL; PCTSTR lastSegPtr;
if (TrimmedResult) { *TrimmedResult = NULL; }
result = pLnkSimpleTryHandle (FullPath); if (result || (!Hint)) { return result; } if (EnumFirstPathEx (&pathEnum, Hint, NULL, NULL, FALSE)) { do { newPath = JoinPaths (pathEnum.PtrCurrPath, FullPath); result = pLnkSimpleTryHandle (newPath); if (result) { AbortPathEnum (&pathEnum); FreePathString (newPath); // now, if the initial FullPath did not have any wack in it
// we will take the last segment of the result and put it
// in TrimmedResult
if (TrimmedResult && (!_tcschr (FullPath, TEXT('\\')))) { nativeName = IsmGetNativeObjectName (MIG_FILE_TYPE, result); if (nativeName) { lastSegPtr = _tcsrchr (nativeName, TEXT('\\')); if (lastSegPtr) { lastSegPtr = _tcsinc (lastSegPtr); if (lastSegPtr) { *TrimmedResult = DuplicatePathString (lastSegPtr, 0); } } } } return result; } FreePathString (newPath); } while (EnumNextPath (&pathEnum)); } AbortPathEnum (&pathEnum); return NULL; }
PCTSTR pFilterBuffer ( IN PCTSTR SourceBuffer, IN PCTSTR HintBuffer ) { PCTSTR result = NULL; PCTSTR expBuffer = NULL; MIG_OBJECTSTRINGHANDLE destination; PCTSTR trimmedResult = NULL; BOOL replaced = FALSE; BOOL orgDeleted = FALSE; BOOL orgReplaced = FALSE; GROWBUFFER resultBuffer = INIT_GROWBUFFER; PCTSTR nativeDest; BOOL newContent = TRUE; PCTSTR destResult = NULL; PCTSTR newData, oldData; PCMDLINE cmdLine; GROWBUFFER cmdLineBuffer = INIT_GROWBUFFER; UINT u; PCTSTR p;
expBuffer = IsmExpandEnvironmentString ( PLATFORM_SOURCE, S_SYSENVVAR_GROUP, SourceBuffer, NULL );
if (expBuffer) {
destination = pLnkTryHandle (expBuffer, HintBuffer, &trimmedResult);
if (destination) { replaced = TRUE; if (trimmedResult) { GbAppendString (&resultBuffer, trimmedResult); FreePathString (trimmedResult); } else { nativeDest = IsmGetNativeObjectName (MIG_FILE_TYPE, destination); GbAppendString (&resultBuffer, nativeDest); IsmReleaseMemory (nativeDest); } }
// finally, if we failed we are going to assume it's a command line
if (!replaced) { newData = DuplicatePathString (expBuffer, 0); cmdLine = ParseCmdLineEx (expBuffer, NULL, &pLnkFindFile, &pLnkSearchPath, &cmdLineBuffer); if (cmdLine) {
//
// Find the file referenced in the list or command line
//
for (u = 0 ; u < cmdLine->ArgCount ; u++) { p = cmdLine->Args[u].CleanedUpArg;
// first we try it as is
destination = pLnkTryHandle (p, HintBuffer, &trimmedResult);
// maybe we have something like /m:c:\foo.txt
// we need to go forward until we find a sequence of
// <alpha>:\<something>
if (!destination && p[0] && p[1]) {
while (p[2]) { if (_istalpha ((CHARTYPE) _tcsnextc (p)) && p[1] == TEXT(':') && p[2] == TEXT('\\') ) {
destination = pLnkTryHandle (p, HintBuffer, &trimmedResult);
if (destination) { break; } } p ++; } } if (destination) { replaced = TRUE; if (trimmedResult) { oldData = StringSearchAndReplace (newData, p, trimmedResult); if (oldData) { FreePathString (newData); newData = oldData; } FreePathString (trimmedResult); } else { nativeDest = IsmGetNativeObjectName (MIG_FILE_TYPE, destination); oldData = StringSearchAndReplace (newData, p, nativeDest); if (oldData) { FreePathString (newData); newData = oldData; } IsmReleaseMemory (nativeDest); } IsmDestroyObjectHandle (destination); destination = NULL; } } } GbFree (&cmdLineBuffer); if (!replaced) { if (newData) { FreePathString (newData); } } else { if (newData) { GbAppendString (&resultBuffer, newData); FreePathString (newData); } } }
if (destination) { IsmDestroyObjectHandle (destination); destination = NULL; }
if (replaced && resultBuffer.Buf) { // looks like we have new content
// Let's do one more check. If this is a REG_EXPAND_SZ we will do our best to
// keep the stuff unexpanded. So if the source string expanded on the destination
// machine is the same as the destination string we won't do anything.
newContent = TRUE; destResult = IsmExpandEnvironmentString ( PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, SourceBuffer, NULL ); if (destResult && StringIMatch (destResult, (PCTSTR)resultBuffer.Buf)) { newContent = FALSE; } if (destResult) { IsmReleaseMemory (destResult); destResult = NULL; } if (newContent) { result = DuplicatePathString ((PCTSTR)resultBuffer.Buf, 0); } }
GbFree (&resultBuffer); }
return result; }
BOOL WINAPI DoLnkContentFix ( IN MIG_OBJECTTYPEID SrcObjectTypeId, IN MIG_OBJECTSTRINGHANDLE SrcObjectName, IN PCMIG_CONTENT OriginalContent, IN PCMIG_CONTENT CurrentContent, OUT PMIG_CONTENT NewContent, IN PCMIG_BLOB SourceOperationData, OPTIONAL IN PCMIG_BLOB DestinationOperationData OPTIONAL ) { MIG_PROPERTYDATAID propDataId; MIG_BLOBTYPE propDataType; UINT requiredSize; BOOL lnkTargetPresent = FALSE; PCTSTR lnkTargetNode = NULL; PCTSTR lnkTargetLeaf = NULL; PCTSTR objectNode = NULL; PCTSTR objectLeaf = NULL; MIG_OBJECTSTRINGHANDLE lnkTarget = NULL; MIG_OBJECTTYPEID lnkTargetDestType = 0; MIG_OBJECTSTRINGHANDLE lnkTargetDest = NULL; BOOL lnkTargetDestDel = FALSE; BOOL lnkTargetDestRepl = FALSE; PCTSTR lnkTargetDestNative = NULL; PCTSTR lnkParams = NULL; PCTSTR lnkParamsNew = NULL; MIG_OBJECTSTRINGHANDLE lnkWorkDir = NULL; MIG_OBJECTTYPEID lnkWorkDirDestType = 0; MIG_OBJECTSTRINGHANDLE lnkWorkDirDest = NULL; BOOL lnkWorkDirDestDel = FALSE; BOOL lnkWorkDirDestRepl = FALSE; PCTSTR lnkWorkDirDestNative = NULL; PCTSTR lnkRawWorkDir = NULL; PCTSTR lnkRawWorkDirExp = NULL; MIG_OBJECTSTRINGHANDLE lnkIconPath = NULL; MIG_OBJECTTYPEID lnkIconPathDestType = 0; MIG_OBJECTSTRINGHANDLE lnkIconPathDest = NULL; BOOL lnkIconPathDestDel = FALSE; BOOL lnkIconPathDestRepl = FALSE; PCTSTR lnkIconPathDestNative = NULL; INT lnkIconNumber = 0; PICON_GROUP lnkIconGroup = NULL; ICON_SGROUP lnkIconSGroup = {0, NULL}; WORD lnkHotKey = 0; BOOL lnkDosApp = FALSE; BOOL lnkMsDosMode = FALSE; PLNK_EXTRA_DATA lnkExtraData = NULL; BOOL comInit = FALSE; BOOL modifyFile = FALSE; PTSTR iconLibPath = NULL; PTSTR newShortcutPath = NULL; MIG_CONTENT lnkIconContent;
// now it's finally time to fix the LNK file content
if ((g_ShellLink == NULL) || (g_PersistFile == NULL)) { comInit = TRUE; if (!InitCOMLink (&g_ShellLink, &g_PersistFile)) { DEBUGMSG ((DBG_ERROR, "Error initializing COM %d", GetLastError ())); return TRUE; } }
// first, retrieve the properties
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_Target); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { lnkTarget = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)lnkTarget, requiredSize, NULL, &propDataType); } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_Params); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { lnkParams = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)lnkParams, requiredSize, NULL, &propDataType); } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_WorkDir); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { lnkWorkDir = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)lnkWorkDir, requiredSize, NULL, &propDataType); } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_RawWorkDir); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { lnkRawWorkDir = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)lnkRawWorkDir, requiredSize, NULL, &propDataType); } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconPath); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { lnkIconPath = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)lnkIconPath, requiredSize, NULL, &propDataType); } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconNumber); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { if (requiredSize == sizeof (INT)) { IsmGetPropertyData (propDataId, (PBYTE)(&lnkIconNumber), requiredSize, NULL, &propDataType); } } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconData); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { lnkIconSGroup.DataSize = requiredSize; lnkIconSGroup.Data = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)lnkIconSGroup.Data, requiredSize, NULL, &propDataType); } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_HotKey); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { if (requiredSize == sizeof (WORD)) { IsmGetPropertyData (propDataId, (PBYTE)(&lnkHotKey), requiredSize, NULL, &propDataType); } } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_DosApp); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { if (requiredSize == sizeof (BOOL)) { IsmGetPropertyData (propDataId, (PBYTE)(&lnkDosApp), requiredSize, NULL, &propDataType); } } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_MsDosMode); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { if (requiredSize == sizeof (BOOL)) { IsmGetPropertyData (propDataId, (PBYTE)(&lnkMsDosMode), requiredSize, NULL, &propDataType); } } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_ExtraData); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { lnkExtraData = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)lnkExtraData, requiredSize, NULL, &propDataType); } }
// let's examine the target, see if it was migrated
if (lnkTarget) { lnkTargetDest = IsmFilterObject ( MIG_FILE_TYPE | PLATFORM_SOURCE, lnkTarget, &lnkTargetDestType, &lnkTargetDestDel, &lnkTargetDestRepl ); if (((lnkTargetDestDel == FALSE) || (lnkTargetDestRepl == TRUE)) && ((lnkTargetDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE) ) { if (lnkTargetDest) { // the target changed location, we need to adjust the link
modifyFile = TRUE; lnkTargetDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkTargetDest); } } lnkTargetPresent = !lnkTargetDestDel; }
// let's examine the parameters
if (lnkParams) { lnkParamsNew = pFilterBuffer (lnkParams, NULL); if (lnkParamsNew) { modifyFile = TRUE; } }
// let's examine the working directory
if (lnkWorkDir) { lnkWorkDirDest = IsmFilterObject ( MIG_FILE_TYPE | PLATFORM_SOURCE, lnkWorkDir, &lnkWorkDirDestType, &lnkWorkDirDestDel, &lnkWorkDirDestRepl ); if (((lnkWorkDirDestDel == FALSE) || (lnkWorkDirDestRepl == TRUE)) && ((lnkWorkDirDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE) ) { if (lnkWorkDirDest) { // the working directory changed location
// Normally we would want to adjust the link's working directory
// to point to the new location. However, let's take the raw working directory,
// expand it and see if it matches the lnkWorkDirDest. If it does we won't touch
// it since the raw working directory is working great. If it doesn't we will
// modify the link
lnkWorkDirDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkWorkDirDest); lnkRawWorkDirExp = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, lnkRawWorkDir, NULL); if ((!lnkWorkDirDestNative) || (!lnkRawWorkDirExp) || (!StringIMatch (lnkRawWorkDirExp, lnkWorkDirDestNative))) { modifyFile = TRUE; } else { IsmReleaseMemory (lnkWorkDirDestNative); lnkWorkDirDestNative = NULL; } if (lnkRawWorkDirExp) { IsmReleaseMemory (lnkRawWorkDirExp); lnkRawWorkDirExp = NULL; } } } else { // seems like the working directory is gone. If the target is still present, we will adjust
// the working directory to point where the target is located
if (lnkTargetPresent) { if (IsmCreateObjectStringsFromHandle (lnkTargetDest?lnkTargetDest:lnkTarget, &lnkTargetNode, &lnkTargetLeaf)) { lnkWorkDirDest = IsmCreateObjectHandle (lnkTargetNode, NULL); if (lnkWorkDirDest) { modifyFile = TRUE; lnkWorkDirDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkWorkDirDest); } IsmDestroyObjectString (lnkTargetNode); IsmDestroyObjectString (lnkTargetLeaf); } } } }
// let's examine the icon path
if (lnkIconPath) { lnkIconPathDest = IsmFilterObject ( MIG_FILE_TYPE | PLATFORM_SOURCE, lnkIconPath, &lnkIconPathDestType, &lnkIconPathDestDel, &lnkIconPathDestRepl ); // if the icon holder is deleted we will extract the icon and put it in our lib.
// The point is, even if the icon holder is replaced (that is, exists on the destination
// machine), we cannot guarantee that the icon indexes will be the same. Typically, shell32.dll
// icon indexes changed from version to version, and if a user picked an shell32.dll icon on Win9x,
// he will have a surprise on Win XP. If we wanted to keep the icon from the replacement file, we just
// need to check for lnkIconPathDestRepl.
if ((lnkIconPathDestDel == FALSE) && ((lnkIconPathDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE) ) { if (lnkIconPathDest) { // the icon path changed location, we need to adjust the link
modifyFile = TRUE; lnkIconPathDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkIconPathDest); } } else { // seems like the icon path is gone. If the we have the icon extracted we will try to add it to the
// icon library and adjust this link to point there.
if (lnkIconSGroup.DataSize) { lnkIconGroup = IcoDeSerializeIconGroup (&lnkIconSGroup); if (lnkIconGroup) { if (IsmGetEnvironmentString ( PLATFORM_DESTINATION, NULL, S_ENV_ICONLIB, NULL, 0, &requiredSize )) { iconLibPath = PmGetMemory (g_LinksPool, requiredSize); if (IsmGetEnvironmentString ( PLATFORM_DESTINATION, NULL, S_ENV_ICONLIB, iconLibPath, requiredSize, NULL )) { if (IcoWriteIconGroupToPeFile (iconLibPath, lnkIconGroup, NULL, &lnkIconNumber)) { modifyFile = TRUE; lnkIconPathDestNative = IsmGetMemory (SizeOfString (iconLibPath)); StringCopy ((PTSTR)lnkIconPathDestNative, iconLibPath); IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_ENV_SAVE_ICONLIB); } } PmReleaseMemory (g_LinksPool, iconLibPath); } IcoReleaseIconGroup (lnkIconGroup); } } else { // we don't have the icon extracted. Let's just do our best and update the
// icon path to point to the destination replacement.
if (((lnkIconPathDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE) && (lnkIconPathDest) ) { // the icon path changed location, we need to adjust the link
modifyFile = TRUE; lnkIconPathDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkIconPathDest); } } } } else { // If we have an icon extracted, but the icon path is NULL, it
// means that the original LNK had no icon associated with it
// but it's target was an EXE. In this case the icon that was
// displayed was the first icon from the EXE. Now we want to
// make sure that the destination target has at least one icon
// in it. If it doesn't we will just hook the source extracted icon.
if (lnkIconSGroup.DataSize) { // let's see if the destination target has at least one icon
if (IsmAcquireObjectEx ( MIG_FILE_TYPE | PLATFORM_DESTINATION, lnkTargetDest?lnkTargetDest:lnkTarget, &lnkIconContent, CONTENTTYPE_FILE, 0 )) { if (lnkIconContent.ContentInFile && lnkIconContent.FileContent.ContentPath) { lnkIconGroup = IcoExtractIconGroupByIndexFromFile ( lnkIconContent.FileContent.ContentPath, 0, NULL ); if (lnkIconGroup) { // Yes, it has at least one icon, we're safe
IcoReleaseIconGroup (lnkIconGroup); lnkIconGroup = NULL; } else { // Nope, it does not have any icons
lnkIconGroup = IcoDeSerializeIconGroup (&lnkIconSGroup); if (lnkIconGroup) { if (IsmGetEnvironmentString ( PLATFORM_DESTINATION, NULL, S_ENV_ICONLIB, NULL, 0, &requiredSize )) { iconLibPath = PmGetMemory (g_LinksPool, requiredSize); if (IsmGetEnvironmentString ( PLATFORM_DESTINATION, NULL, S_ENV_ICONLIB, iconLibPath, requiredSize, NULL )) { if (IcoWriteIconGroupToPeFile (iconLibPath, lnkIconGroup, NULL, &lnkIconNumber)) { modifyFile = TRUE; lnkIconPathDestNative = IsmGetMemory (SizeOfString (iconLibPath)); StringCopy ((PTSTR)lnkIconPathDestNative, iconLibPath); IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_ENV_SAVE_ICONLIB); } } PmReleaseMemory (g_LinksPool, iconLibPath); } IcoReleaseIconGroup (lnkIconGroup); } } } IsmReleaseObject (&lnkIconContent); } } }
if (modifyFile) { if (CurrentContent->ContentInFile) { if (IsmCreateObjectStringsFromHandle (SrcObjectName, &objectNode, &objectLeaf)) { // We need to modify the shortcut. Unfortunately, if this is the command
// line tool, the shortcut we are going to modify is not some temporary file,
// it is the actual shortcut from the store. As a result, if you try to
// apply a second time, the shortcut would be already modified and problems
// may appear. For this, we will get a temporary directory from ISM,
// copy the current shortcut (CurrentContent->FileContent.ContentPath) and
// modify it and generate a new content.
newShortcutPath = IsmGetMemory (MAX_PATH); if (newShortcutPath) { if (IsmGetTempFile (newShortcutPath, MAX_PATH)) { if (CopyFile ( (PCTSTR) CurrentContent->FileContent.ContentPath, newShortcutPath, FALSE )) { if (ModifyShortcutFileEx ( newShortcutPath, GetFileExtensionFromPath (objectLeaf), lnkTargetDestNative, lnkParamsNew, lnkWorkDirDestNative, lnkIconPathDestNative, lnkIconNumber, lnkHotKey, NULL, g_ShellLink, g_PersistFile )) { NewContent->FileContent.ContentPath = newShortcutPath; } } } } IsmDestroyObjectString (objectNode); IsmDestroyObjectString (objectLeaf); } } else { // something is wrong, the content of this shortcut should be in a file
MYASSERT (FALSE); } }
if (lnkIconPathDestNative) { IsmReleaseMemory (lnkIconPathDestNative); lnkIconPathDestNative = NULL; }
if (lnkWorkDirDestNative) { IsmReleaseMemory (lnkWorkDirDestNative); lnkWorkDirDestNative = NULL; }
if (lnkTargetDestNative) { IsmReleaseMemory (lnkTargetDestNative); lnkTargetDestNative = NULL; }
if (lnkIconPathDest) { IsmDestroyObjectHandle (lnkIconPathDest); lnkIconPathDest = NULL; }
if (lnkWorkDirDest) { IsmDestroyObjectHandle (lnkWorkDirDest); lnkWorkDirDest = NULL; }
if (lnkTargetDest) { IsmDestroyObjectHandle (lnkTargetDest); lnkTargetDest = NULL; }
if (lnkExtraData) { PmReleaseMemory (g_LinksPool, lnkExtraData); lnkExtraData = NULL; }
if (lnkIconSGroup.DataSize && lnkIconSGroup.Data) { PmReleaseMemory (g_LinksPool, lnkIconSGroup.Data); lnkIconSGroup.DataSize = 0; lnkIconSGroup.Data = NULL; }
if (lnkIconPath) { PmReleaseMemory (g_LinksPool, lnkIconPath); lnkIconPath = NULL; }
if (lnkWorkDir) { PmReleaseMemory (g_LinksPool, lnkWorkDir); lnkWorkDir = NULL; }
if (lnkParams) { PmReleaseMemory (g_LinksPool, lnkParams); lnkParams = NULL; }
if (lnkTarget) { PmReleaseMemory (g_LinksPool, lnkTarget); lnkTarget = NULL; }
if (comInit) { FreeCOMLink (&g_ShellLink, &g_PersistFile); g_ShellLink = NULL; g_PersistFile = NULL; }
return TRUE; }
BOOL LinkRestoreCallback ( IN MIG_OBJECTTYPEID ObjectTypeId, IN MIG_OBJECTID ObjectId, IN MIG_OBJECTSTRINGHANDLE ObjectName ) { MIG_PROPERTYDATAID propDataId; MIG_BLOBTYPE propDataType; UINT requiredSize; MIG_OBJECTSTRINGHANDLE lnkTarget = NULL; MIG_OBJECTTYPEID lnkTargetDestType = 0; MIG_OBJECTSTRINGHANDLE lnkTargetDest = NULL; BOOL lnkTargetDestDel = FALSE; BOOL lnkTargetDestRepl = FALSE; PCTSTR lnkTargetNative = NULL; PCTSTR objectNode = NULL; PCTSTR objectLeaf = NULL; PCTSTR extPtr = NULL; PCTSTR userProfile = NULL; PCTSTR allUsersProfile = NULL; PCTSTR newObjectNode = NULL; MIG_OBJECTSTRINGHANDLE newObjectName = NULL; MIG_CONTENT oldContent; MIG_CONTENT newContent; BOOL identical = FALSE; BOOL diffDetailsOnly = FALSE; BOOL result = TRUE;
if (IsmIsAttributeSetOnObjectId (ObjectId, g_CopyIfRelevantAttr)) { if (IsmCreateObjectStringsFromHandle (ObjectName, &objectNode, &objectLeaf)) { if (objectLeaf) { extPtr = GetFileExtensionFromPath (objectLeaf); if (extPtr && (StringIMatch (extPtr, TEXT("LNK")) || StringIMatch (extPtr, TEXT("PIF")) ) ) { propDataId = IsmGetPropertyFromObject (ObjectTypeId, ObjectName, g_LnkMigProp_Target); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { lnkTarget = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)lnkTarget, requiredSize, NULL, &propDataType); lnkTargetNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkTarget); if (lnkTargetNative) { if (pIsUncPath (lnkTargetNative)) { result = TRUE; } else { lnkTargetDest = IsmFilterObject ( MIG_FILE_TYPE | PLATFORM_SOURCE, lnkTarget, &lnkTargetDestType, &lnkTargetDestDel, &lnkTargetDestRepl ); result = (lnkTargetDestDel == FALSE) || (lnkTargetDestRepl == TRUE); if (lnkTargetDest) { IsmDestroyObjectHandle (lnkTargetDest); } } IsmReleaseMemory (lnkTargetNative); } else { result = FALSE; } PmReleaseMemory (g_LinksPool, lnkTarget); } } if (result) { // one more thing. If this LNK is in %USERPROFILE% and an equivalent LNK
// (same name, same target, same arguments, same working dir) can be found
// in %ALLUSERSPROFILE% then we won't restore this LNK. Similarly, if the
// LNK is in %ALLUSERSPROFILE% and an equivalent LNK exists in %USERPROFILE%
// we won't restore the LNK.
userProfile = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT ("%USERPROFILE%"), NULL); allUsersProfile = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT ("%ALLUSERSPROFILE%"), NULL); if (userProfile && allUsersProfile && objectNode) { if (StringIPrefix (objectNode, userProfile)) { newObjectNode = StringSearchAndReplace (objectNode, userProfile, allUsersProfile); if (newObjectNode) { newObjectName = IsmCreateObjectHandle (newObjectNode, objectLeaf); if (newObjectName) { if (IsmAcquireObjectEx ( (ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION, newObjectName, &newContent, CONTENTTYPE_FILE, 0 )) { if (IsmAcquireObjectEx ( ObjectTypeId, ObjectName, &oldContent, CONTENTTYPE_FILE, 0 )) { if (LinkDoesContentMatch ( FALSE, ObjectTypeId, ObjectName, &oldContent, (ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION, newObjectName, &newContent, &identical, &diffDetailsOnly )) { result = (!identical) && (!diffDetailsOnly); } IsmReleaseObject (&oldContent); } IsmReleaseObject (&newContent); } IsmDestroyObjectHandle (newObjectName); newObjectName = NULL; } FreePathString (newObjectNode); newObjectNode = NULL; } } } if (userProfile) { IsmReleaseMemory (userProfile); userProfile = NULL; } if (allUsersProfile) { IsmReleaseMemory (allUsersProfile); allUsersProfile = NULL; } allUsersProfile = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT ("%ALLUSERSPROFILE%"), NULL); userProfile = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT ("%USERPROFILE%"), NULL); if (userProfile && allUsersProfile && objectNode) { if (StringIPrefix (objectNode, allUsersProfile)) { newObjectNode = StringSearchAndReplace (objectNode, allUsersProfile, userProfile); if (newObjectNode) { newObjectName = IsmCreateObjectHandle (newObjectNode, objectLeaf); if (newObjectName) { if (IsmAcquireObjectEx ( (ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION, newObjectName, &newContent, CONTENTTYPE_FILE, 0 )) { if (IsmAcquireObjectEx ( ObjectTypeId, ObjectName, &oldContent, CONTENTTYPE_FILE, 0 )) { if (LinkDoesContentMatch ( FALSE, ObjectTypeId, ObjectName, &oldContent, (ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION, newObjectName, &newContent, &identical, &diffDetailsOnly )) { result = (!identical) || (!diffDetailsOnly); } IsmReleaseObject (&oldContent); } IsmReleaseObject (&newContent); } IsmDestroyObjectHandle (newObjectName); newObjectName = NULL; } FreePathString (newObjectNode); newObjectNode = NULL; } } } if (userProfile) { IsmReleaseMemory (userProfile); userProfile = NULL; } if (allUsersProfile) { IsmReleaseMemory (allUsersProfile); allUsersProfile = NULL; } } } } IsmDestroyObjectString (objectNode); IsmDestroyObjectString (objectLeaf); } } return result; }
BOOL pMatchWinSysFiles ( IN PCTSTR Source, IN PCTSTR Destination ) { PCTSTR srcLeaf; PCTSTR destLeaf; PCTSTR winDir = NULL; PCTSTR sysDir = NULL; BOOL result = FALSE;
__try { if ((!Source) || (!Destination)) { __leave; } srcLeaf = _tcsrchr (Source, TEXT('\\')); destLeaf = _tcsrchr (Destination, TEXT('\\')); if ((!srcLeaf) || (!destLeaf)) { __leave; } if (!StringIMatch (srcLeaf, destLeaf)) { __leave; } // now let's see if the directory for each is either
// %windir% or %system%
// Source is already modified to what it would look like on the destination machine,
// let's just expand the PLATFORM_DESTINATION env. variables.
winDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%windir%"), NULL); sysDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%system%"), NULL); if ((!winDir) || (!sysDir)) { __leave; } if (!StringIPrefix (Source, winDir) && !StringIPrefix (Source, sysDir)) { __leave; } IsmReleaseMemory (winDir); winDir = NULL; IsmReleaseMemory (sysDir); sysDir = NULL;
winDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%windir%"), NULL); sysDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%system%"), NULL); if ((!winDir) || (!sysDir)) { __leave; } if (!StringIPrefix (Destination, winDir) && !StringIPrefix (Destination, sysDir)) { __leave; } IsmReleaseMemory (winDir); winDir = NULL; IsmReleaseMemory (sysDir); sysDir = NULL;
result = TRUE; } __finally { if (winDir) { IsmReleaseMemory (winDir); winDir = NULL; } if (sysDir) { IsmReleaseMemory (sysDir); sysDir = NULL; } } return result; }
BOOL pForcedLnkMatch ( IN PCTSTR SrcTarget, IN PCTSTR SrcParams, IN PCTSTR SrcWorkDir, IN PCTSTR DestTarget, IN PCTSTR DestParams, IN PCTSTR DestWorkDir ) { PTSTR multiSz = NULL; MULTISZ_ENUM e; UINT sizeNeeded; HINF infHandle = INVALID_HANDLE_VALUE; ENVENTRY_TYPE dataType; INFSTRUCT is = INITINFSTRUCT_PMHANDLE; PCTSTR srcTargetPat = NULL; PCTSTR srcParamsPat = NULL; PCTSTR srcWorkDirPat = NULL; PCTSTR destTargetPat = NULL; PCTSTR destParamsPat = NULL; PCTSTR destWorkDirPat = NULL; BOOL result = FALSE;
// let's look in the INFs in section [EquivalentLinks] and see if our LNKs match
// one of the lines. If they do then they are equivalent
if (IsmGetEnvironmentValue ( IsmGetRealPlatform (), NULL, S_GLOBAL_INF_HANDLE, (PBYTE)(&infHandle), sizeof (HINF), &sizeNeeded, &dataType ) && (sizeNeeded == sizeof (HINF)) && (dataType == ENVENTRY_BINARY) ) {
if (InfFindFirstLine (infHandle, TEXT("EquivalentLinks"), NULL, &is)) {
do { srcTargetPat = InfGetStringField (&is, 1); srcParamsPat = InfGetStringField (&is, 2); srcWorkDirPat = InfGetStringField (&is, 3); destTargetPat = InfGetStringField (&is, 4); destParamsPat = InfGetStringField (&is, 5); destWorkDirPat = InfGetStringField (&is, 6); if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) && IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) && IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT("")) && IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) && IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) && IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT("")) ) { result = TRUE; break; } if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) && IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) && IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT("")) && IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) && IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) && IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT("")) ) { result = TRUE; break; } } while (InfFindNextLine (&is)); }
InfNameHandle (infHandle, NULL, FALSE);
} else {
if (IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, NULL, 0, &sizeNeeded, NULL)) { __try { multiSz = AllocText (sizeNeeded);
if (!IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, (PBYTE) multiSz, sizeNeeded, NULL, NULL)) { __leave; }
if (EnumFirstMultiSz (&e, multiSz)) {
do {
infHandle = InfOpenInfFile (e.CurrentString); if (infHandle != INVALID_HANDLE_VALUE) {
if (InfFindFirstLine (infHandle, TEXT("EquivalentLinks"), NULL, &is)) {
do { srcTargetPat = InfGetStringField (&is, 1); srcParamsPat = InfGetStringField (&is, 2); srcWorkDirPat = InfGetStringField (&is, 3); destTargetPat = InfGetStringField (&is, 4); destParamsPat = InfGetStringField (&is, 5); destWorkDirPat = InfGetStringField (&is, 6); if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) && IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) && IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT("")) && IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) && IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) && IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT("")) ) { result = TRUE; break; } if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) && IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) && IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT("")) && IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) && IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) && IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT("")) ) { result = TRUE; break; } } while (InfFindNextLine (&is)); } }
InfCloseInfFile (infHandle); infHandle = INVALID_HANDLE_VALUE;
if (result) { break; }
} while (EnumNextMultiSz (&e));
} } __finally { FreeText (multiSz); } } }
InfResetInfStruct (&is);
return result; }
BOOL LinkDoesContentMatch ( IN BOOL AlreadyProcessed, IN MIG_OBJECTTYPEID SrcObjectTypeId, IN MIG_OBJECTSTRINGHANDLE SrcObjectName, IN PMIG_CONTENT SrcContent, IN MIG_OBJECTTYPEID DestObjectTypeId, IN MIG_OBJECTSTRINGHANDLE DestObjectName, IN PMIG_CONTENT DestContent, OUT PBOOL Identical, OUT PBOOL DifferentDetailsOnly ) { PCTSTR objectNode = NULL; PCTSTR objectLeaf = NULL; PCTSTR extPtr = NULL; MIG_PROPERTYDATAID propDataId; MIG_BLOBTYPE propDataType; UINT requiredSize; MIG_OBJECTSTRINGHANDLE srcTarget = NULL; PCTSTR srcTargetNative = NULL; PCTSTR srcParams = NULL; PCTSTR srcParamsNew = NULL; MIG_OBJECTSTRINGHANDLE srcWorkDir = NULL; PCTSTR srcWorkDirNative = NULL; PCTSTR srcRawWorkDir = NULL; BOOL lnkWorkDirDestDel = FALSE; BOOL lnkWorkDirDestRepl = FALSE; PCTSTR destTarget = NULL; PCTSTR destParams = NULL; PCTSTR destWorkDir = NULL; PCTSTR destIconPath = NULL; PCTSTR expTmpStr; PCTSTR longExpTmpStr; INT destIconNumber; WORD destHotKey; BOOL destDosApp; BOOL destMsDosMode; BOOL comInit = FALSE; MIG_OBJECTSTRINGHANDLE lnkDest = NULL; PCTSTR lnkNative = NULL; BOOL targetOsFile = FALSE; BOOL match = FALSE; BOOL result = FALSE;
if ((SrcObjectTypeId & ~PLATFORM_MASK) != MIG_FILE_TYPE) { return FALSE; }
if ((DestObjectTypeId & ~PLATFORM_MASK) != MIG_FILE_TYPE) { return FALSE; }
// let's check that the source is a shortcut
if (IsmCreateObjectStringsFromHandle (SrcObjectName, &objectNode, &objectLeaf)) { if (objectLeaf) { extPtr = GetFileExtensionFromPath (objectLeaf); if (extPtr && (StringIMatch (extPtr, TEXT("LNK")) || StringIMatch (extPtr, TEXT("PIF")) || StringIMatch (extPtr, TEXT("URL")) ) ) { result = TRUE; } } IsmDestroyObjectString (objectNode); IsmDestroyObjectString (objectLeaf); } if (!result) { return FALSE; } result = FALSE;
// let's check that the destination is a shortcut
if (IsmCreateObjectStringsFromHandle (DestObjectName, &objectNode, &objectLeaf)) { if (objectLeaf) { extPtr = GetFileExtensionFromPath (objectLeaf); if (extPtr && (StringIMatch (extPtr, TEXT("LNK")) || StringIMatch (extPtr, TEXT("PIF")) || StringIMatch (extPtr, TEXT("URL")) ) ) { result = TRUE; } } IsmDestroyObjectString (objectNode); IsmDestroyObjectString (objectLeaf); } if (!result) { return FALSE; }
// some safety checks
if (!SrcContent->ContentInFile) { return FALSE; } if (!SrcContent->FileContent.ContentPath) { return FALSE; } if (!DestContent->ContentInFile) { return FALSE; } if (!DestContent->FileContent.ContentPath) { return FALSE; }
result = FALSE;
__try {
// let's get info from the source. We will not look inside the LNK file, we will
// just get it's properties. If there are no properties, we'll just exit, leaving
// the default compare to solve the problem.
// first, retrieve the properties
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_Target); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { srcTarget = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)srcTarget, requiredSize, NULL, &propDataType); } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_Params); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { srcParams = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)srcParams, requiredSize, NULL, &propDataType); } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_RawWorkDir); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { srcRawWorkDir = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)srcRawWorkDir, requiredSize, NULL, &propDataType); } }
propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_WorkDir); if (propDataId) { if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) { srcWorkDir = PmGetMemory (g_LinksPool, requiredSize); IsmGetPropertyData (propDataId, (PBYTE)srcWorkDir, requiredSize, NULL, &propDataType); } }
// now, let's get the info from the destination shortcut
if ((g_ShellLink == NULL) || (g_PersistFile == NULL)) { comInit = TRUE; if (!InitCOMLink (&g_ShellLink, &g_PersistFile)) { DEBUGMSG ((DBG_ERROR, "Error initializing COM %d", GetLastError ())); return TRUE; } } if (!ExtractShortcutInfo ( DestContent->FileContent.ContentPath, &destTarget, &destParams, &destWorkDir, &destIconPath, &destIconNumber, &destHotKey, &destDosApp, &destMsDosMode, NULL, g_ShellLink, g_PersistFile )) { __leave; }
srcTargetNative = IsmGetNativeObjectName (MIG_FILE_TYPE, srcTarget); srcWorkDirNative = IsmGetNativeObjectName (MIG_FILE_TYPE, srcWorkDir);
if (pForcedLnkMatch ( srcTargetNative, srcParams, srcWorkDirNative, destTarget, destParams, destWorkDir )) { if (srcTargetNative) { IsmReleaseMemory (srcTargetNative); srcTargetNative = NULL; } if (srcWorkDirNative) { IsmReleaseMemory (srcWorkDirNative); srcWorkDirNative = NULL; } result = TRUE; if (Identical) { *Identical = TRUE; } if (DifferentDetailsOnly) { *DifferentDetailsOnly = FALSE; } __leave; } if (srcTargetNative) { IsmReleaseMemory (srcTargetNative); srcTargetNative = NULL; } if (srcWorkDirNative) { IsmReleaseMemory (srcWorkDirNative); srcWorkDirNative = NULL; }
// let's filter the source target and see if it matches the dest target
match = TRUE; if (srcTarget && *srcTarget && destTarget && *destTarget) {
// let's see if the source target is an OS file
targetOsFile = IsmIsAttributeSetOnObject (MIG_FILE_TYPE|PLATFORM_SOURCE, srcTarget, g_OsFileAttribute);
lnkDest = IsmFilterObject ( MIG_FILE_TYPE | PLATFORM_SOURCE, srcTarget, NULL, NULL, NULL ); if (!lnkDest) { lnkDest = srcTarget; } lnkNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkDest); if (lnkNative) { expTmpStr = IsmExpandEnvironmentString ( PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, destTarget, NULL ); if (!expTmpStr) { expTmpStr = destTarget; } longExpTmpStr = BfGetLongFileName (expTmpStr); if (!longExpTmpStr) { longExpTmpStr = expTmpStr; } if (!StringIMatch (lnkNative, longExpTmpStr)) { // different targets
// Let's try another trick to catch some OS files getting moved.
// For example, in Win9x systems, notepad.exe is in %windir%.
// In XP, it was moved to %system%. We'll try to match the target
// if the last segment is the same and the rest is either %windir%
// or %system%
if (!pMatchWinSysFiles (lnkNative, longExpTmpStr)) { match = FALSE; } } if (longExpTmpStr != expTmpStr) { FreePathString (longExpTmpStr); } if (expTmpStr != destTarget) { IsmReleaseMemory (expTmpStr); } IsmReleaseMemory (lnkNative); lnkNative = NULL; } else { match = FALSE; } if (lnkDest != srcTarget) { IsmDestroyObjectHandle (lnkDest); } lnkDest = NULL; } else { if (srcTarget && *srcTarget) { match = FALSE; } if (destTarget && *destTarget) { match = FALSE; } }
// the target did not match
if (!match) { __leave; }
// let's match the src and dest parameters
match = TRUE; if (srcParams && *srcParams && destParams && *destParams) { // srcParams might have source paths embedded in them.
// Let's try to filter them and get the parameters as
// they would look on the destination machine
srcParamsNew = pFilterBuffer (srcParams, NULL); if (!StringIMatch (srcParamsNew?srcParamsNew:srcParams, destParams)) { // different parameters
match = FALSE; } if (srcParamsNew) { FreePathString (srcParamsNew); srcParamsNew = NULL; } } else { if (srcParams && *srcParams) { match = FALSE; } if (destParams && *destParams) { match = FALSE; } }
// the parameters did not match
if (!match) { __leave; }
// let's filter the source work dir and see if it matches the dest work dir.
match = TRUE; // if the source target was an OS file we will ignore the working directory match
if (!targetOsFile) { if (srcWorkDir && *srcWorkDir && destWorkDir && *destWorkDir) { lnkDest = IsmFilterObject ( MIG_FILE_TYPE | PLATFORM_SOURCE, srcWorkDir, NULL, &lnkWorkDirDestDel, &lnkWorkDirDestRepl ); if (!lnkDest) { // if the working directory is deleted and not
// replaced it means it will go away. In that case
// we don't really care about working directory
// matching the destination one.
if ((!lnkWorkDirDestDel) || lnkWorkDirDestRepl) { lnkDest = srcWorkDir; } } if (lnkDest) { lnkNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkDest); if (lnkNative) { expTmpStr = IsmExpandEnvironmentString ( PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, destWorkDir, NULL ); if (!expTmpStr) { expTmpStr = destWorkDir; } longExpTmpStr = BfGetLongFileName (expTmpStr); if (!longExpTmpStr) { longExpTmpStr = expTmpStr; } if (!StringIMatch (lnkNative, longExpTmpStr)) { // different working directories
// let's test the raw versions just in case
if (!srcRawWorkDir || !StringIMatch (srcRawWorkDir, destWorkDir)) { match = FALSE; } } if (longExpTmpStr != expTmpStr) { FreePathString (longExpTmpStr); } if (expTmpStr != destWorkDir) { IsmReleaseMemory (expTmpStr); } IsmReleaseMemory (lnkNative); lnkNative = NULL; } else { match = FALSE; } if (lnkDest != srcWorkDir) { IsmDestroyObjectHandle (lnkDest); } lnkDest = NULL; } } else { if (srcWorkDir && *srcWorkDir) { match = FALSE; } if (destWorkDir && *destWorkDir) { match = FALSE; } } }
// the working directory did not match
if (!match) { __leave; }
result = TRUE;
if (Identical) { *Identical = TRUE; } if (DifferentDetailsOnly) { *DifferentDetailsOnly = FALSE; }
} __finally { if (srcTarget) { PmReleaseMemory (g_LinksPool, srcTarget); srcTarget = NULL; } if (srcParams) { PmReleaseMemory (g_LinksPool, srcParams); srcParams = NULL; } if (srcRawWorkDir) { PmReleaseMemory (g_LinksPool, srcRawWorkDir); srcRawWorkDir = NULL; } if (srcWorkDir) { PmReleaseMemory (g_LinksPool, srcWorkDir); srcWorkDir = NULL; } if (destTarget) { FreePathString (destTarget); destTarget = NULL; } if (destParams) { FreePathString (destParams); destParams = NULL; } if (destWorkDir) { FreePathString (destWorkDir); destWorkDir = NULL; } if (destIconPath) { FreePathString (destIconPath); destIconPath = NULL; } if (comInit) { FreeCOMLink (&g_ShellLink, &g_PersistFile); g_ShellLink = NULL; g_PersistFile = NULL; } if (lnkNative) { IsmReleaseMemory (lnkNative); lnkNative = NULL; } }
return result; }
BOOL WINAPI LnkMigOpmInitialize ( IN PMIG_LOGCALLBACK LogCallback, IN PVOID Reserved ) { LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
g_LnkMigAttr_Shortcut = IsmRegisterAttribute (S_LNKMIGATTR_SHORTCUT, FALSE); g_CopyIfRelevantAttr = IsmRegisterAttribute (S_ATTRIBUTE_COPYIFRELEVANT, FALSE); g_OsFileAttribute = IsmRegisterAttribute (S_ATTRIBUTE_OSFILE, FALSE);
g_LnkMigProp_Target = IsmRegisterProperty (S_LNKMIGPROP_TARGET, FALSE); g_LnkMigProp_Params = IsmRegisterProperty (S_LNKMIGPROP_PARAMS, FALSE); g_LnkMigProp_WorkDir = IsmRegisterProperty (S_LNKMIGPROP_WORKDIR, FALSE); g_LnkMigProp_IconPath = IsmRegisterProperty (S_LNKMIGPROP_ICONPATH, FALSE); g_LnkMigProp_IconNumber = IsmRegisterProperty (S_LNKMIGPROP_ICONNUMBER, FALSE); g_LnkMigProp_IconData = IsmRegisterProperty (S_LNKMIGPROP_ICONDATA, FALSE); g_LnkMigProp_HotKey = IsmRegisterProperty (S_LNKMIGPROP_HOTKEY, FALSE); g_LnkMigProp_DosApp = IsmRegisterProperty (S_LNKMIGPROP_DOSAPP, FALSE); g_LnkMigProp_MsDosMode = IsmRegisterProperty (S_LNKMIGPROP_MSDOSMODE, FALSE); g_LnkMigProp_ExtraData = IsmRegisterProperty (S_LNKMIGPROP_EXTRADATA, FALSE);
g_LnkMigOp_FixContent = IsmRegisterOperation (S_OPERATION_LNKMIG_FIXCONTENT, FALSE);
IsmRegisterRestoreCallback (LinkRestoreCallback); IsmRegisterCompareCallback (MIG_FILE_TYPE, LinkDoesContentMatch); IsmRegisterOperationApplyCallback (g_LnkMigOp_FixContent, DoLnkContentFix, TRUE);
return TRUE; }
|