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.

2718 lines
111 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. lnkmig.c
  5. Abstract:
  6. <abstract>
  7. Author:
  8. Calin Negreanu (calinn) 08 Mar 2000
  9. Revision History:
  10. <alias> <date> <comments>
  11. --*/
  12. //
  13. // Includes
  14. //
  15. #include "pch.h"
  16. #include "logmsg.h"
  17. #include "lnkmig.h"
  18. #define DBG_LINKS "Links"
  19. //
  20. // Strings
  21. //
  22. // None
  23. //
  24. // Constants
  25. //
  26. // None
  27. //
  28. // Macros
  29. //
  30. // None
  31. //
  32. // Types
  33. //
  34. // None
  35. //
  36. // Globals
  37. //
  38. PMHANDLE g_LinksPool = NULL;
  39. MIG_ATTRIBUTEID g_LnkMigAttr_Shortcut = 0;
  40. MIG_ATTRIBUTEID g_CopyIfRelevantAttr;
  41. MIG_ATTRIBUTEID g_OsFileAttribute;
  42. MIG_PROPERTYID g_LnkMigProp_Target = 0;
  43. MIG_PROPERTYID g_LnkMigProp_Params = 0;
  44. MIG_PROPERTYID g_LnkMigProp_WorkDir = 0;
  45. MIG_PROPERTYID g_LnkMigProp_RawWorkDir = 0;
  46. MIG_PROPERTYID g_LnkMigProp_IconPath = 0;
  47. MIG_PROPERTYID g_LnkMigProp_IconNumber = 0;
  48. MIG_PROPERTYID g_LnkMigProp_IconData = 0;
  49. MIG_PROPERTYID g_LnkMigProp_HotKey = 0;
  50. MIG_PROPERTYID g_LnkMigProp_DosApp = 0;
  51. MIG_PROPERTYID g_LnkMigProp_MsDosMode = 0;
  52. MIG_PROPERTYID g_LnkMigProp_ExtraData = 0;
  53. MIG_OPERATIONID g_LnkMigOp_FixContent;
  54. IShellLink *g_ShellLink = NULL;
  55. IPersistFile *g_PersistFile = NULL;
  56. BOOL g_VcmMode = FALSE;
  57. //
  58. // Macro expansion list
  59. //
  60. // None
  61. //
  62. // Private function prototypes
  63. //
  64. // None
  65. //
  66. // Macro expansion definition
  67. //
  68. // None
  69. //
  70. // Private prototypes
  71. //
  72. MIG_OBJECTENUMCALLBACK LinksCallback;
  73. MIG_PREENUMCALLBACK LnkMigPreEnumeration;
  74. MIG_POSTENUMCALLBACK LnkMigPostEnumeration;
  75. OPMAPPLYCALLBACK DoLnkContentFix;
  76. MIG_RESTORECALLBACK LinkRestoreCallback;
  77. BOOL
  78. LinkDoesContentMatch (
  79. IN BOOL AlreadyProcessed,
  80. IN MIG_OBJECTTYPEID SrcObjectTypeId,
  81. IN MIG_OBJECTSTRINGHANDLE SrcObjectName,
  82. IN PMIG_CONTENT SrcContent,
  83. IN MIG_OBJECTTYPEID DestObjectTypeId,
  84. IN MIG_OBJECTSTRINGHANDLE DestObjectName,
  85. IN PMIG_CONTENT DestContent,
  86. OUT PBOOL Identical,
  87. OUT PBOOL DifferentDetailsOnly
  88. );
  89. //
  90. // Code
  91. //
  92. BOOL
  93. pIsUncPath (
  94. IN PCTSTR Path
  95. )
  96. {
  97. return (Path && (Path[0] == TEXT('\\')) && (Path[1] == TEXT('\\')));
  98. }
  99. BOOL
  100. LinksInitialize (
  101. VOID
  102. )
  103. {
  104. g_LinksPool = PmCreateNamedPool ("Links");
  105. return (g_LinksPool != NULL);
  106. }
  107. VOID
  108. LinksTerminate (
  109. VOID
  110. )
  111. {
  112. if (g_LinksPool) {
  113. PmDestroyPool (g_LinksPool);
  114. g_LinksPool = NULL;
  115. }
  116. }
  117. BOOL
  118. pCommonInitialize (
  119. IN PMIG_LOGCALLBACK LogCallback
  120. )
  121. {
  122. LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
  123. g_LnkMigAttr_Shortcut = IsmRegisterAttribute (S_LNKMIGATTR_SHORTCUT, FALSE);
  124. g_CopyIfRelevantAttr = IsmRegisterAttribute (S_ATTRIBUTE_COPYIFRELEVANT, FALSE);
  125. g_LnkMigProp_Target = IsmRegisterProperty (S_LNKMIGPROP_TARGET, FALSE);
  126. g_LnkMigProp_Params = IsmRegisterProperty (S_LNKMIGPROP_PARAMS, FALSE);
  127. g_LnkMigProp_WorkDir = IsmRegisterProperty (S_LNKMIGPROP_WORKDIR, FALSE);
  128. g_LnkMigProp_RawWorkDir = IsmRegisterProperty (S_LNKMIGPROP_RAWWORKDIR, FALSE);
  129. g_LnkMigProp_IconPath = IsmRegisterProperty (S_LNKMIGPROP_ICONPATH, FALSE);
  130. g_LnkMigProp_IconNumber = IsmRegisterProperty (S_LNKMIGPROP_ICONNUMBER, FALSE);
  131. g_LnkMigProp_IconData = IsmRegisterProperty (S_LNKMIGPROP_ICONDATA, FALSE);
  132. g_LnkMigProp_HotKey = IsmRegisterProperty (S_LNKMIGPROP_HOTKEY, FALSE);
  133. g_LnkMigProp_DosApp = IsmRegisterProperty (S_LNKMIGPROP_DOSAPP, FALSE);
  134. g_LnkMigProp_MsDosMode = IsmRegisterProperty (S_LNKMIGPROP_MSDOSMODE, FALSE);
  135. g_LnkMigProp_ExtraData = IsmRegisterProperty (S_LNKMIGPROP_EXTRADATA, FALSE);
  136. g_LnkMigOp_FixContent = IsmRegisterOperation (S_OPERATION_LNKMIG_FIXCONTENT, FALSE);
  137. return TRUE;
  138. }
  139. BOOL
  140. WINAPI
  141. LnkMigVcmInitialize (
  142. IN PMIG_LOGCALLBACK LogCallback,
  143. IN PVOID Reserved
  144. )
  145. {
  146. g_VcmMode = TRUE;
  147. return pCommonInitialize (LogCallback);
  148. }
  149. BOOL
  150. WINAPI
  151. LnkMigSgmInitialize (
  152. IN PMIG_LOGCALLBACK LogCallback,
  153. IN PVOID Reserved
  154. )
  155. {
  156. return pCommonInitialize (LogCallback);
  157. }
  158. BOOL
  159. LnkMigPreEnumeration (
  160. VOID
  161. )
  162. {
  163. if (!InitCOMLink (&g_ShellLink, &g_PersistFile)) {
  164. DEBUGMSG ((DBG_ERROR, "Error initializing COM %d", GetLastError ()));
  165. }
  166. return TRUE;
  167. }
  168. BOOL
  169. LnkMigPostEnumeration (
  170. VOID
  171. )
  172. {
  173. FreeCOMLink (&g_ShellLink, &g_PersistFile);
  174. g_ShellLink = NULL;
  175. g_PersistFile = NULL;
  176. return TRUE;
  177. }
  178. MIG_OBJECTSTRINGHANDLE
  179. pBuildEncodedNameFromNativeName (
  180. IN PCTSTR NativeName
  181. )
  182. {
  183. PCTSTR nodeName;
  184. PTSTR leafName;
  185. MIG_OBJECTSTRINGHANDLE result = NULL;
  186. MIG_OBJECT_ENUM objEnum;
  187. result = IsmCreateObjectHandle (NativeName, NULL);
  188. if (result) {
  189. if (IsmEnumFirstSourceObject (&objEnum, MIG_FILE_TYPE | PLATFORM_SOURCE, result)) {
  190. IsmAbortObjectEnum (&objEnum);
  191. return result;
  192. }
  193. IsmDestroyObjectHandle (result);
  194. result = NULL;
  195. }
  196. // we have to split this path because it could be a file
  197. nodeName = DuplicatePathString (NativeName, 0);
  198. leafName = _tcsrchr (nodeName, TEXT('\\'));
  199. if (leafName) {
  200. *leafName = 0;
  201. leafName ++;
  202. result = IsmCreateObjectHandle (nodeName, leafName);
  203. } else {
  204. // we have no \ in the name. This can only mean that the
  205. // file specification has only a leaf
  206. result = IsmCreateObjectHandle (NULL, NativeName);
  207. }
  208. FreePathString (nodeName);
  209. return result;
  210. }
  211. PCTSTR
  212. pSpecialExpandEnvironmentString (
  213. IN PCTSTR SrcString,
  214. IN PCTSTR Context
  215. )
  216. {
  217. PCTSTR result = NULL;
  218. PCTSTR srcWinDir = NULL;
  219. PCTSTR destWinDir = NULL;
  220. PTSTR newSrcString = NULL;
  221. PCTSTR copyPtr = NULL;
  222. if (IsmGetRealPlatform () == PLATFORM_DESTINATION) {
  223. // Special case where this is actually the destination machine and
  224. // first part of SrcString matches %windir%. In this case, it is likely that
  225. // the shell replaced the source windows directory with the destination one.
  226. // We need to change it back
  227. destWinDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT ("%windir%"), NULL);
  228. if (destWinDir) {
  229. if (StringIPrefix (SrcString, destWinDir)) {
  230. srcWinDir = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT ("%windir%"), NULL);
  231. if (srcWinDir) {
  232. newSrcString = IsmGetMemory (SizeOfString (srcWinDir) + SizeOfString (SrcString));
  233. if (newSrcString) {
  234. copyPtr = SrcString + TcharCount (destWinDir);
  235. StringCopy (newSrcString, srcWinDir);
  236. StringCat (newSrcString, copyPtr);
  237. }
  238. IsmReleaseMemory (srcWinDir);
  239. srcWinDir = NULL;
  240. }
  241. }
  242. IsmReleaseMemory (destWinDir);
  243. destWinDir = NULL;
  244. }
  245. }
  246. result = IsmExpandEnvironmentString (
  247. PLATFORM_SOURCE,
  248. S_SYSENVVAR_GROUP,
  249. newSrcString?newSrcString:SrcString,
  250. Context
  251. );
  252. if (newSrcString) {
  253. IsmReleaseMemory (newSrcString);
  254. }
  255. return result;
  256. }
  257. MIG_OBJECTSTRINGHANDLE
  258. pTryObject (
  259. IN PCTSTR LeafName,
  260. IN PCTSTR EnvName
  261. )
  262. {
  263. MIG_OBJECT_ENUM objEnum;
  264. PTSTR envData = NULL;
  265. DWORD envSize = 0;
  266. PATH_ENUM pathEnum;
  267. MIG_OBJECTSTRINGHANDLE result = NULL;
  268. if (IsmGetEnvironmentString (
  269. PLATFORM_SOURCE,
  270. S_SYSENVVAR_GROUP,
  271. EnvName,
  272. NULL,
  273. 0,
  274. &envSize
  275. )) {
  276. envData = IsmGetMemory (envSize);
  277. if (envData) {
  278. if (IsmGetEnvironmentString (
  279. PLATFORM_SOURCE,
  280. S_SYSENVVAR_GROUP,
  281. EnvName,
  282. envData,
  283. envSize,
  284. &envSize
  285. )) {
  286. // let's enumerate the paths from this env variable (should be separated by ;)
  287. if (EnumFirstPathEx (&pathEnum, envData, NULL, NULL, FALSE)) {
  288. do {
  289. result = IsmCreateObjectHandle (pathEnum.PtrCurrPath, LeafName);
  290. if (IsmEnumFirstSourceObject (&objEnum, MIG_FILE_TYPE | PLATFORM_SOURCE, result)) {
  291. IsmAbortObjectEnum (&objEnum);
  292. } else {
  293. IsmDestroyObjectHandle (result);
  294. result = NULL;
  295. }
  296. if (result) {
  297. AbortPathEnum (&pathEnum);
  298. break;
  299. }
  300. } while (EnumNextPath (&pathEnum));
  301. }
  302. }
  303. IsmReleaseMemory (envData);
  304. envData = NULL;
  305. }
  306. }
  307. return result;
  308. }
  309. MIG_OBJECTSTRINGHANDLE
  310. pGetFullEncodedName (
  311. IN MIG_OBJECTSTRINGHANDLE ObjectName
  312. )
  313. {
  314. PCTSTR node = NULL, leaf = NULL;
  315. MIG_OBJECTSTRINGHANDLE result = NULL;
  316. // let's split the ObjectName into node and leaf.
  317. // If it's leaf only we are going to try to find
  318. // that leaf in %path%, %windir% and %system% and
  319. // reconstruct the object name.
  320. if (IsmCreateObjectStringsFromHandle (ObjectName, &node, &leaf)) {
  321. if (!node) {
  322. // this is leaf only. We need to find out where this leaf
  323. // is located. We are going to look for the leaf in the
  324. // following directories (in this order)
  325. // 1. %system%
  326. // 2. %system16%
  327. // 3. %windir%
  328. // 4. All directories in %path% env. variable
  329. result = pTryObject (leaf, TEXT("system"));
  330. if (!result) {
  331. result = pTryObject (leaf, TEXT("system16"));
  332. }
  333. if (!result) {
  334. result = pTryObject (leaf, TEXT("windir"));
  335. }
  336. if (!result) {
  337. result = pTryObject (leaf, TEXT("path"));
  338. }
  339. }
  340. IsmDestroyObjectString (node);
  341. IsmDestroyObjectString (leaf);
  342. }
  343. return result;
  344. }
  345. BOOL
  346. pIsLnkExcluded (
  347. IN MIG_OBJECTID ObjectId,
  348. IN PCTSTR Target,
  349. IN PCTSTR Params,
  350. IN PCTSTR WorkDir
  351. )
  352. {
  353. PTSTR multiSz = NULL;
  354. MULTISZ_ENUM e;
  355. UINT sizeNeeded;
  356. HINF infHandle = INVALID_HANDLE_VALUE;
  357. ENVENTRY_TYPE dataType;
  358. INFSTRUCT is = INITINFSTRUCT_PMHANDLE;
  359. PCTSTR targetPattern = NULL;
  360. PCTSTR targetPatternExp = NULL;
  361. PCTSTR paramsPattern = NULL;
  362. PCTSTR paramsPatternExp = NULL;
  363. PCTSTR workDirPattern = NULL;
  364. PCTSTR workDirPatternExp = NULL;
  365. BOOL result = FALSE;
  366. if (IsmIsAttributeSetOnObjectId (ObjectId, g_CopyIfRelevantAttr)) {
  367. // let's look in the INFs in section [ExcludedLinks] and see if our LNK matches
  368. // one of the lines. If it does and it has the CopyIfRelevand attribute then
  369. // it's excluded
  370. if (IsmGetEnvironmentValue (
  371. IsmGetRealPlatform (),
  372. NULL,
  373. S_GLOBAL_INF_HANDLE,
  374. (PBYTE)(&infHandle),
  375. sizeof (HINF),
  376. &sizeNeeded,
  377. &dataType
  378. ) &&
  379. (sizeNeeded == sizeof (HINF)) &&
  380. (dataType == ENVENTRY_BINARY)
  381. ) {
  382. if (InfFindFirstLine (infHandle, TEXT("ExcludedLinks"), NULL, &is)) {
  383. do {
  384. targetPattern = InfGetStringField (&is, 1);
  385. targetPatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, targetPattern, NULL);
  386. if (!targetPatternExp) {
  387. targetPatternExp = targetPattern;
  388. }
  389. paramsPattern = InfGetStringField (&is, 2);
  390. paramsPatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, paramsPattern, NULL);
  391. if (!paramsPatternExp) {
  392. paramsPatternExp = paramsPattern;
  393. }
  394. workDirPattern = InfGetStringField (&is, 3);
  395. workDirPatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, workDirPattern, NULL);
  396. if (!workDirPatternExp) {
  397. workDirPatternExp = workDirPattern;
  398. }
  399. if (IsPatternMatch (targetPatternExp?targetPatternExp:TEXT("*"), Target?Target:TEXT("")) &&
  400. IsPatternMatch (paramsPatternExp?paramsPatternExp:TEXT("*"), Params?Params:TEXT("")) &&
  401. IsPatternMatch (workDirPatternExp?workDirPatternExp:TEXT("*"), WorkDir?WorkDir:TEXT(""))
  402. ) {
  403. result = TRUE;
  404. if (workDirPatternExp && (workDirPatternExp != workDirPattern)) {
  405. IsmReleaseMemory (workDirPatternExp);
  406. workDirPatternExp = NULL;
  407. }
  408. if (paramsPatternExp && (paramsPatternExp != paramsPattern)) {
  409. IsmReleaseMemory (paramsPatternExp);
  410. paramsPatternExp = NULL;
  411. }
  412. if (targetPatternExp && (targetPatternExp != targetPattern)) {
  413. IsmReleaseMemory (targetPatternExp);
  414. targetPatternExp = NULL;
  415. }
  416. break;
  417. }
  418. if (workDirPatternExp && (workDirPatternExp != workDirPattern)) {
  419. IsmReleaseMemory (workDirPatternExp);
  420. workDirPatternExp = NULL;
  421. }
  422. if (paramsPatternExp && (paramsPatternExp != paramsPattern)) {
  423. IsmReleaseMemory (paramsPatternExp);
  424. paramsPatternExp = NULL;
  425. }
  426. if (targetPatternExp && (targetPatternExp != targetPattern)) {
  427. IsmReleaseMemory (targetPatternExp);
  428. targetPatternExp = NULL;
  429. }
  430. } while (InfFindNextLine (&is));
  431. }
  432. InfNameHandle (infHandle, NULL, FALSE);
  433. } else {
  434. if (IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, NULL, 0, &sizeNeeded, NULL)) {
  435. __try {
  436. multiSz = AllocText (sizeNeeded);
  437. if (!IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, (PBYTE) multiSz, sizeNeeded, NULL, NULL)) {
  438. __leave;
  439. }
  440. if (EnumFirstMultiSz (&e, multiSz)) {
  441. do {
  442. infHandle = InfOpenInfFile (e.CurrentString);
  443. if (infHandle != INVALID_HANDLE_VALUE) {
  444. if (InfFindFirstLine (infHandle, TEXT("ExcludedLinks"), NULL, &is)) {
  445. do {
  446. targetPattern = InfGetStringField (&is, 1);
  447. paramsPattern = InfGetStringField (&is, 2);
  448. workDirPattern = InfGetStringField (&is, 3);
  449. if (IsPatternMatch (targetPattern?targetPattern:TEXT("*"), Target?Target:TEXT("")) &&
  450. IsPatternMatch (paramsPattern?paramsPattern:TEXT("*"), Params?Params:TEXT("")) &&
  451. IsPatternMatch (workDirPattern?workDirPattern:TEXT("*"), WorkDir?WorkDir:TEXT(""))
  452. ) {
  453. result = TRUE;
  454. break;
  455. }
  456. } while (InfFindNextLine (&is));
  457. }
  458. }
  459. InfCloseInfFile (infHandle);
  460. infHandle = INVALID_HANDLE_VALUE;
  461. if (result) {
  462. break;
  463. }
  464. } while (EnumNextMultiSz (&e));
  465. }
  466. }
  467. __finally {
  468. FreeText (multiSz);
  469. }
  470. }
  471. }
  472. InfResetInfStruct (&is);
  473. }
  474. return result;
  475. }
  476. UINT
  477. LinksCallback (
  478. IN PCMIG_OBJECTENUMDATA Data,
  479. IN ULONG_PTR CallerArg
  480. )
  481. {
  482. MIG_OBJECTID objectId;
  483. BOOL extractResult = FALSE;
  484. PCTSTR lnkTarget = NULL;
  485. PCTSTR newLnkTarget = NULL;
  486. PCTSTR expLnkTarget = NULL;
  487. PCTSTR lnkParams = NULL;
  488. PCTSTR lnkWorkDir = NULL;
  489. PCTSTR lnkIconPath = NULL;
  490. INT lnkIconNumber;
  491. WORD lnkHotKey;
  492. BOOL lnkDosApp;
  493. BOOL lnkMsDosMode;
  494. LNK_EXTRA_DATA lnkExtraData;
  495. MIG_OBJECTSTRINGHANDLE encodedName;
  496. MIG_OBJECTSTRINGHANDLE longEncodedName;
  497. MIG_OBJECTSTRINGHANDLE fullEncodedName;
  498. MIG_BLOB migBlob;
  499. PCTSTR expTmpStr;
  500. MIG_CONTENT lnkContent;
  501. MIG_CONTENT lnkIconContent;
  502. PICON_GROUP iconGroup = NULL;
  503. ICON_SGROUP iconSGroup;
  504. PCTSTR lnkIconResId = NULL;
  505. PCTSTR extPtr = NULL;
  506. BOOL exeDefaultIcon = FALSE;
  507. if (Data->IsLeaf) {
  508. objectId = IsmGetObjectIdFromName (MIG_FILE_TYPE, Data->ObjectName, TRUE);
  509. if (IsmIsPersistentObjectId (objectId)) {
  510. IsmSetAttributeOnObjectId (objectId, g_LnkMigAttr_Shortcut);
  511. if (IsmAcquireObjectEx (
  512. Data->ObjectTypeId,
  513. Data->ObjectName,
  514. &lnkContent,
  515. CONTENTTYPE_FILE,
  516. 0
  517. )) {
  518. if (lnkContent.ContentInFile && lnkContent.FileContent.ContentPath) {
  519. if (ExtractShortcutInfo (
  520. lnkContent.FileContent.ContentPath,
  521. &lnkTarget,
  522. &lnkParams,
  523. &lnkWorkDir,
  524. &lnkIconPath,
  525. &lnkIconNumber,
  526. &lnkHotKey,
  527. &lnkDosApp,
  528. &lnkMsDosMode,
  529. &lnkExtraData,
  530. g_ShellLink,
  531. g_PersistFile
  532. )) {
  533. // let's check if the LNK is excluded
  534. if (pIsLnkExcluded (
  535. objectId,
  536. lnkTarget,
  537. lnkParams,
  538. lnkWorkDir
  539. )) {
  540. IsmClearPersistenceOnObjectId (objectId);
  541. } else {
  542. // let's get all the paths through the hooks and add everything as properties of this shortcut
  543. if (lnkTarget) {
  544. if (*lnkTarget) {
  545. // If we are on the destination system, we are going to have major problems here.
  546. // If the LNK had IDLISTs, we are going to get back a path that's local to the
  547. // destination machine. For example if the target was c:\Windows\Favorites on the
  548. // source system and that was the CSIDL_FAVORITES we are going to get back:
  549. // c:\Documents and Settings\username\Favorites.
  550. // Because of this problem we need to compress the path and then expand it back
  551. // using env. variables from the source system.
  552. if (IsmGetRealPlatform () == PLATFORM_DESTINATION) {
  553. newLnkTarget = IsmCompressEnvironmentString (
  554. PLATFORM_DESTINATION,
  555. S_SYSENVVAR_GROUP,
  556. lnkTarget,
  557. Data->NativeObjectName,
  558. TRUE
  559. );
  560. }
  561. // let's look if this is a valid file specification. If it is not, it might be
  562. // an URL or something else, so we will just migrate the thing
  563. expTmpStr = pSpecialExpandEnvironmentString (newLnkTarget?newLnkTarget:lnkTarget, Data->NativeObjectName);
  564. if (IsValidFileSpec (expTmpStr)) {
  565. // we are going to need this (maybe) later, if the icon path is NULL and this is an EXE
  566. expLnkTarget = DuplicatePathString (expTmpStr, 0);
  567. encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
  568. longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, encodedName);
  569. if (!longEncodedName) {
  570. longEncodedName = encodedName;
  571. }
  572. IsmExecuteHooks (MIG_FILE_TYPE|PLATFORM_SOURCE, longEncodedName);
  573. if (!g_VcmMode) {
  574. migBlob.Type = BLOBTYPE_STRING;
  575. migBlob.String = longEncodedName;
  576. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_Target, &migBlob);
  577. } else {
  578. // persist the target so we can examine it later
  579. if (!IsmIsPersistentObject (MIG_FILE_TYPE, longEncodedName)) {
  580. IsmMakePersistentObject (MIG_FILE_TYPE, longEncodedName);
  581. IsmMakeNonCriticalObject (MIG_FILE_TYPE, longEncodedName);
  582. }
  583. }
  584. if (longEncodedName != encodedName) {
  585. IsmDestroyObjectHandle (longEncodedName);
  586. }
  587. if (encodedName) {
  588. IsmDestroyObjectHandle (encodedName);
  589. }
  590. } else {
  591. encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
  592. if (!g_VcmMode) {
  593. migBlob.Type = BLOBTYPE_STRING;
  594. migBlob.String = encodedName;
  595. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_Target, &migBlob);
  596. }
  597. if (encodedName) {
  598. IsmDestroyObjectHandle (encodedName);
  599. }
  600. }
  601. if (newLnkTarget) {
  602. IsmReleaseMemory (newLnkTarget);
  603. newLnkTarget = NULL;
  604. }
  605. IsmReleaseMemory (expTmpStr);
  606. expTmpStr = NULL;
  607. } else {
  608. if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
  609. IsmClearPersistenceOnObjectId (objectId);
  610. }
  611. }
  612. FreePathString (lnkTarget);
  613. } else {
  614. if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
  615. IsmClearPersistenceOnObjectId (objectId);
  616. }
  617. }
  618. if (lnkParams) {
  619. if (*lnkParams) {
  620. if (!g_VcmMode) {
  621. migBlob.Type = BLOBTYPE_STRING;
  622. migBlob.String = lnkParams;
  623. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_Params, &migBlob);
  624. }
  625. }
  626. FreePathString (lnkParams);
  627. }
  628. if (lnkWorkDir) {
  629. if (*lnkWorkDir) {
  630. // let's save the raw working directory
  631. if (!g_VcmMode) {
  632. migBlob.Type = BLOBTYPE_STRING;
  633. migBlob.String = lnkWorkDir;
  634. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_RawWorkDir, &migBlob);
  635. }
  636. expTmpStr = pSpecialExpandEnvironmentString (lnkWorkDir, Data->NativeObjectName);
  637. if (IsValidFileSpec (expTmpStr)) {
  638. encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
  639. longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, encodedName);
  640. if (!longEncodedName) {
  641. longEncodedName = encodedName;
  642. }
  643. IsmExecuteHooks (MIG_FILE_TYPE|PLATFORM_SOURCE, longEncodedName);
  644. if (!g_VcmMode) {
  645. migBlob.Type = BLOBTYPE_STRING;
  646. migBlob.String = longEncodedName;
  647. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_WorkDir, &migBlob);
  648. } else {
  649. // persist the working directory (it has almost no space impact)
  650. // so we can examine it later
  651. if (!IsmIsPersistentObject (MIG_FILE_TYPE, longEncodedName)) {
  652. IsmMakePersistentObject (MIG_FILE_TYPE, longEncodedName);
  653. IsmMakeNonCriticalObject (MIG_FILE_TYPE, longEncodedName);
  654. }
  655. }
  656. if (longEncodedName != encodedName) {
  657. IsmDestroyObjectHandle (longEncodedName);
  658. }
  659. if (encodedName) {
  660. IsmDestroyObjectHandle (encodedName);
  661. }
  662. } else {
  663. encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
  664. if (!g_VcmMode) {
  665. migBlob.Type = BLOBTYPE_STRING;
  666. migBlob.String = encodedName;
  667. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_WorkDir, &migBlob);
  668. }
  669. if (encodedName) {
  670. IsmDestroyObjectHandle (encodedName);
  671. }
  672. }
  673. IsmReleaseMemory (expTmpStr);
  674. expTmpStr = NULL;
  675. }
  676. FreePathString (lnkWorkDir);
  677. }
  678. if (((!lnkIconPath) || (!(*lnkIconPath))) && expLnkTarget) {
  679. extPtr = GetFileExtensionFromPath (expLnkTarget);
  680. if (extPtr) {
  681. exeDefaultIcon = StringIMatch (extPtr, TEXT("EXE"));
  682. if (exeDefaultIcon) {
  683. if (lnkIconPath) {
  684. FreePathString (lnkIconPath);
  685. }
  686. lnkIconPath = expLnkTarget;
  687. }
  688. }
  689. }
  690. if (lnkIconPath) {
  691. if (*lnkIconPath) {
  692. // let's look if this is a valid file specification. If it is not, it might be
  693. // an URL or something else, so we will just migrate the thing
  694. expTmpStr = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, lnkIconPath, Data->NativeObjectName);
  695. if (IsValidFileSpec (expTmpStr)) {
  696. encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
  697. longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, encodedName);
  698. if (!longEncodedName) {
  699. longEncodedName = encodedName;
  700. }
  701. // Sometimes the icon is specified without full path (like foo.dll instead
  702. // of c:\windows\system\foo.dll). When this is the case we are going to
  703. // walk the %path% and %windir% and %system% and try to find the file there.
  704. fullEncodedName = pGetFullEncodedName (longEncodedName);
  705. if (fullEncodedName) {
  706. if (longEncodedName != encodedName) {
  707. IsmDestroyObjectHandle (longEncodedName);
  708. }
  709. longEncodedName = IsmGetLongName (MIG_FILE_TYPE|PLATFORM_SOURCE, fullEncodedName);
  710. if (!longEncodedName) {
  711. longEncodedName = fullEncodedName;
  712. } else {
  713. IsmDestroyObjectHandle (fullEncodedName);
  714. fullEncodedName = NULL;
  715. }
  716. }
  717. IsmExecuteHooks (MIG_FILE_TYPE|PLATFORM_SOURCE, longEncodedName);
  718. if (!g_VcmMode) {
  719. if (!exeDefaultIcon) {
  720. migBlob.Type = BLOBTYPE_STRING;
  721. migBlob.String = longEncodedName;
  722. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconPath, &migBlob);
  723. }
  724. // one last thing: let's extract the icon and preserve it just in case.
  725. if (IsmAcquireObjectEx (
  726. MIG_FILE_TYPE,
  727. longEncodedName,
  728. &lnkIconContent,
  729. CONTENTTYPE_FILE,
  730. 0
  731. )) {
  732. if (lnkIconContent.ContentInFile && lnkIconContent.FileContent.ContentPath) {
  733. if (lnkIconNumber >= 0) {
  734. iconGroup = IcoExtractIconGroupByIndexFromFile (
  735. lnkIconContent.FileContent.ContentPath,
  736. lnkIconNumber,
  737. NULL
  738. );
  739. } else {
  740. lnkIconResId = (PCTSTR) (LONG_PTR) (-lnkIconNumber);
  741. iconGroup = IcoExtractIconGroupFromFile (
  742. lnkIconContent.FileContent.ContentPath,
  743. lnkIconResId,
  744. NULL
  745. );
  746. }
  747. if (iconGroup) {
  748. if (IcoSerializeIconGroup (iconGroup, &iconSGroup)) {
  749. migBlob.Type = BLOBTYPE_BINARY;
  750. migBlob.BinaryData = (PCBYTE)(iconSGroup.Data);
  751. migBlob.BinarySize = iconSGroup.DataSize;
  752. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconData, &migBlob);
  753. IcoReleaseIconSGroup (&iconSGroup);
  754. }
  755. IcoReleaseIconGroup (iconGroup);
  756. }
  757. }
  758. IsmReleaseObject (&lnkIconContent);
  759. }
  760. } else {
  761. // persist the icon file so we can examine it later
  762. if (!IsmIsPersistentObject (MIG_FILE_TYPE, longEncodedName)) {
  763. IsmMakePersistentObject (MIG_FILE_TYPE, longEncodedName);
  764. IsmMakeNonCriticalObject (MIG_FILE_TYPE, longEncodedName);
  765. }
  766. }
  767. if (longEncodedName != encodedName) {
  768. IsmDestroyObjectHandle (longEncodedName);
  769. longEncodedName = NULL;
  770. }
  771. if (encodedName) {
  772. IsmDestroyObjectHandle (encodedName);
  773. encodedName = NULL;
  774. }
  775. } else {
  776. encodedName = pBuildEncodedNameFromNativeName (expTmpStr);
  777. if (!g_VcmMode) {
  778. if (!exeDefaultIcon) {
  779. migBlob.Type = BLOBTYPE_STRING;
  780. migBlob.String = encodedName;
  781. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconPath, &migBlob);
  782. }
  783. }
  784. if (encodedName) {
  785. IsmDestroyObjectHandle (encodedName);
  786. }
  787. }
  788. IsmReleaseMemory (expTmpStr);
  789. expTmpStr = NULL;
  790. }
  791. if (lnkIconPath != expLnkTarget) {
  792. FreePathString (lnkIconPath);
  793. }
  794. }
  795. if (!g_VcmMode) {
  796. migBlob.Type = BLOBTYPE_BINARY;
  797. migBlob.BinaryData = (PCBYTE)(&lnkIconNumber);
  798. migBlob.BinarySize = sizeof (INT);
  799. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconNumber, &migBlob);
  800. migBlob.Type = BLOBTYPE_BINARY;
  801. migBlob.BinaryData = (PCBYTE)(&lnkDosApp);
  802. migBlob.BinarySize = sizeof (BOOL);
  803. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_DosApp, &migBlob);
  804. if (lnkDosApp) {
  805. migBlob.Type = BLOBTYPE_BINARY;
  806. migBlob.BinaryData = (PCBYTE)(&lnkMsDosMode);
  807. migBlob.BinarySize = sizeof (BOOL);
  808. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_MsDosMode, &migBlob);
  809. migBlob.Type = BLOBTYPE_BINARY;
  810. migBlob.BinaryData = (PCBYTE)(&lnkExtraData);
  811. migBlob.BinarySize = sizeof (LNK_EXTRA_DATA);
  812. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_ExtraData, &migBlob);
  813. } else {
  814. migBlob.Type = BLOBTYPE_BINARY;
  815. migBlob.BinaryData = (PCBYTE)(&lnkHotKey);
  816. migBlob.BinarySize = sizeof (WORD);
  817. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_HotKey, &migBlob);
  818. }
  819. IsmSetOperationOnObjectId (
  820. objectId,
  821. g_LnkMigOp_FixContent,
  822. NULL,
  823. NULL
  824. );
  825. }
  826. if (expLnkTarget) {
  827. FreePathString (expLnkTarget);
  828. expLnkTarget = NULL;
  829. }
  830. }
  831. } else {
  832. if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
  833. IsmClearPersistenceOnObjectId (objectId);
  834. }
  835. }
  836. } else {
  837. if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
  838. IsmClearPersistenceOnObjectId (objectId);
  839. }
  840. }
  841. IsmReleaseObject (&lnkContent);
  842. } else {
  843. if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
  844. IsmClearPersistenceOnObjectId (objectId);
  845. }
  846. }
  847. }
  848. }
  849. return CALLBACK_ENUM_CONTINUE;
  850. }
  851. BOOL
  852. pCommonLnkMigQueueEnumeration (
  853. VOID
  854. )
  855. {
  856. ENCODEDSTRHANDLE pattern;
  857. // hook all LNK files
  858. pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, TEXT("*.lnk"), TRUE);
  859. if (pattern) {
  860. IsmHookEnumeration (MIG_FILE_TYPE, pattern, LinksCallback, (ULONG_PTR) 0, TEXT("Links.Files"));
  861. IsmDestroyObjectHandle (pattern);
  862. }
  863. // hook all PIF files
  864. pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, TEXT("*.pif"), TRUE);
  865. if (pattern) {
  866. IsmHookEnumeration (MIG_FILE_TYPE, pattern, LinksCallback, (ULONG_PTR) 0, TEXT("Links.Files"));
  867. IsmDestroyObjectHandle (pattern);
  868. }
  869. // hook all URL files
  870. pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, TEXT("*.url"), TRUE);
  871. if (pattern) {
  872. IsmHookEnumeration (MIG_FILE_TYPE, pattern, LinksCallback, (ULONG_PTR) 0, TEXT("Links.Files"));
  873. IsmDestroyObjectHandle (pattern);
  874. }
  875. IsmRegisterPreEnumerationCallback (LnkMigPreEnumeration, NULL);
  876. IsmRegisterPostEnumerationCallback (LnkMigPostEnumeration, NULL);
  877. return TRUE;
  878. }
  879. BOOL
  880. WINAPI
  881. LnkMigVcmQueueEnumeration (
  882. IN PVOID Reserved
  883. )
  884. {
  885. return pCommonLnkMigQueueEnumeration ();
  886. }
  887. BOOL
  888. WINAPI
  889. LnkMigSgmQueueEnumeration (
  890. IN PVOID Reserved
  891. )
  892. {
  893. return pCommonLnkMigQueueEnumeration ();
  894. }
  895. BOOL
  896. pLnkFindFile (
  897. IN PCTSTR FileName
  898. )
  899. {
  900. MIG_OBJECTSTRINGHANDLE objectName;
  901. PTSTR node, leaf, leafPtr;
  902. BOOL result = FALSE;
  903. objectName = IsmCreateObjectHandle (FileName, NULL);
  904. if (objectName) {
  905. if (IsmGetObjectIdFromName (MIG_FILE_TYPE | PLATFORM_SOURCE, objectName, TRUE) != 0) {
  906. result = TRUE;
  907. }
  908. IsmDestroyObjectHandle (objectName);
  909. }
  910. if (!result) {
  911. node = DuplicateText (FileName);
  912. leaf = _tcsrchr (node, TEXT('\\'));
  913. if (leaf) {
  914. leafPtr = (PTSTR) leaf;
  915. leaf = _tcsinc (leaf);
  916. *leafPtr = 0;
  917. objectName = IsmCreateObjectHandle (node, leaf);
  918. if (objectName) {
  919. if (IsmGetObjectIdFromName (MIG_FILE_TYPE | PLATFORM_SOURCE, objectName, TRUE) != 0) {
  920. result = TRUE;
  921. }
  922. IsmDestroyObjectHandle (objectName);
  923. }
  924. *leafPtr = TEXT('\\');
  925. }
  926. FreeText (node);
  927. }
  928. return result;
  929. }
  930. BOOL
  931. pLnkSearchPath (
  932. IN PCTSTR FileName,
  933. IN DWORD BufferLength,
  934. OUT PTSTR Buffer
  935. )
  936. {
  937. return FALSE;
  938. }
  939. MIG_OBJECTSTRINGHANDLE
  940. pLnkSimpleTryHandle (
  941. IN PCTSTR FullPath
  942. )
  943. {
  944. PCTSTR buffer;
  945. PTSTR leafPtr, leaf;
  946. MIG_OBJECTSTRINGHANDLE source = NULL;
  947. MIG_OBJECTSTRINGHANDLE result = NULL;
  948. PTSTR workingPath;
  949. PCTSTR sanitizedPath;
  950. BOOL orgDeleted = FALSE;
  951. BOOL orgReplaced = FALSE;
  952. PCTSTR saved = NULL;
  953. sanitizedPath = SanitizePath (FullPath);
  954. if (!sanitizedPath) {
  955. return NULL;
  956. }
  957. source = IsmCreateObjectHandle (sanitizedPath, NULL);
  958. if (source) {
  959. result = IsmFilterObject (
  960. MIG_FILE_TYPE | PLATFORM_SOURCE,
  961. source,
  962. NULL,
  963. &orgDeleted,
  964. &orgReplaced
  965. );
  966. // we do not want replaced directories
  967. // since they can be false hits
  968. if (orgDeleted) {
  969. if (result) {
  970. saved = result;
  971. result = NULL;
  972. }
  973. }
  974. if (!result && !orgDeleted) {
  975. result = source;
  976. } else {
  977. IsmDestroyObjectHandle (source);
  978. source = NULL;
  979. }
  980. }
  981. if (result) {
  982. goto exit;
  983. }
  984. buffer = DuplicatePathString (sanitizedPath, 0);
  985. leaf = _tcsrchr (buffer, TEXT('\\'));
  986. if (leaf) {
  987. leafPtr = leaf;
  988. leaf = _tcsinc (leaf);
  989. *leafPtr = 0;
  990. source = IsmCreateObjectHandle (buffer, leaf);
  991. *leafPtr = TEXT('\\');
  992. }
  993. FreePathString (buffer);
  994. if (source) {
  995. result = IsmFilterObject (
  996. MIG_FILE_TYPE | PLATFORM_SOURCE,
  997. source,
  998. NULL,
  999. &orgDeleted,
  1000. &orgReplaced
  1001. );
  1002. if (!result && !orgDeleted) {
  1003. result = source;
  1004. } else {
  1005. if (!result) {
  1006. result = saved;
  1007. }
  1008. IsmDestroyObjectHandle (source);
  1009. source = NULL;
  1010. }
  1011. }
  1012. if (result != saved) {
  1013. IsmDestroyObjectHandle (saved);
  1014. saved = NULL;
  1015. }
  1016. exit:
  1017. FreePathString (sanitizedPath);
  1018. return result;
  1019. }
  1020. MIG_OBJECTSTRINGHANDLE
  1021. pLnkTryHandle (
  1022. IN PCTSTR FullPath,
  1023. IN PCTSTR Hint,
  1024. OUT PCTSTR *TrimmedResult
  1025. )
  1026. {
  1027. PATH_ENUM pathEnum;
  1028. PCTSTR newPath;
  1029. MIG_OBJECTSTRINGHANDLE result = NULL;
  1030. PCTSTR nativeName = NULL;
  1031. PCTSTR lastSegPtr;
  1032. if (TrimmedResult) {
  1033. *TrimmedResult = NULL;
  1034. }
  1035. result = pLnkSimpleTryHandle (FullPath);
  1036. if (result || (!Hint)) {
  1037. return result;
  1038. }
  1039. if (EnumFirstPathEx (&pathEnum, Hint, NULL, NULL, FALSE)) {
  1040. do {
  1041. newPath = JoinPaths (pathEnum.PtrCurrPath, FullPath);
  1042. result = pLnkSimpleTryHandle (newPath);
  1043. if (result) {
  1044. AbortPathEnum (&pathEnum);
  1045. FreePathString (newPath);
  1046. // now, if the initial FullPath did not have any wack in it
  1047. // we will take the last segment of the result and put it
  1048. // in TrimmedResult
  1049. if (TrimmedResult && (!_tcschr (FullPath, TEXT('\\')))) {
  1050. nativeName = IsmGetNativeObjectName (MIG_FILE_TYPE, result);
  1051. if (nativeName) {
  1052. lastSegPtr = _tcsrchr (nativeName, TEXT('\\'));
  1053. if (lastSegPtr) {
  1054. lastSegPtr = _tcsinc (lastSegPtr);
  1055. if (lastSegPtr) {
  1056. *TrimmedResult = DuplicatePathString (lastSegPtr, 0);
  1057. }
  1058. }
  1059. }
  1060. }
  1061. return result;
  1062. }
  1063. FreePathString (newPath);
  1064. } while (EnumNextPath (&pathEnum));
  1065. }
  1066. AbortPathEnum (&pathEnum);
  1067. return NULL;
  1068. }
  1069. PCTSTR
  1070. pFilterBuffer (
  1071. IN PCTSTR SourceBuffer,
  1072. IN PCTSTR HintBuffer
  1073. )
  1074. {
  1075. PCTSTR result = NULL;
  1076. PCTSTR expBuffer = NULL;
  1077. MIG_OBJECTSTRINGHANDLE destination;
  1078. PCTSTR trimmedResult = NULL;
  1079. BOOL replaced = FALSE;
  1080. BOOL orgDeleted = FALSE;
  1081. BOOL orgReplaced = FALSE;
  1082. GROWBUFFER resultBuffer = INIT_GROWBUFFER;
  1083. PCTSTR nativeDest;
  1084. BOOL newContent = TRUE;
  1085. PCTSTR destResult = NULL;
  1086. PCTSTR newData, oldData;
  1087. PCMDLINE cmdLine;
  1088. GROWBUFFER cmdLineBuffer = INIT_GROWBUFFER;
  1089. UINT u;
  1090. PCTSTR p;
  1091. expBuffer = IsmExpandEnvironmentString (
  1092. PLATFORM_SOURCE,
  1093. S_SYSENVVAR_GROUP,
  1094. SourceBuffer,
  1095. NULL
  1096. );
  1097. if (expBuffer) {
  1098. destination = pLnkTryHandle (expBuffer, HintBuffer, &trimmedResult);
  1099. if (destination) {
  1100. replaced = TRUE;
  1101. if (trimmedResult) {
  1102. GbAppendString (&resultBuffer, trimmedResult);
  1103. FreePathString (trimmedResult);
  1104. } else {
  1105. nativeDest = IsmGetNativeObjectName (MIG_FILE_TYPE, destination);
  1106. GbAppendString (&resultBuffer, nativeDest);
  1107. IsmReleaseMemory (nativeDest);
  1108. }
  1109. }
  1110. // finally, if we failed we are going to assume it's a command line
  1111. if (!replaced) {
  1112. newData = DuplicatePathString (expBuffer, 0);
  1113. cmdLine = ParseCmdLineEx (expBuffer, NULL, &pLnkFindFile, &pLnkSearchPath, &cmdLineBuffer);
  1114. if (cmdLine) {
  1115. //
  1116. // Find the file referenced in the list or command line
  1117. //
  1118. for (u = 0 ; u < cmdLine->ArgCount ; u++) {
  1119. p = cmdLine->Args[u].CleanedUpArg;
  1120. // first we try it as is
  1121. destination = pLnkTryHandle (p, HintBuffer, &trimmedResult);
  1122. // maybe we have something like /m:c:\foo.txt
  1123. // we need to go forward until we find a sequence of
  1124. // <alpha>:\<something>
  1125. if (!destination && p[0] && p[1]) {
  1126. while (p[2]) {
  1127. if (_istalpha ((CHARTYPE) _tcsnextc (p)) &&
  1128. p[1] == TEXT(':') &&
  1129. p[2] == TEXT('\\')
  1130. ) {
  1131. destination = pLnkTryHandle (p, HintBuffer, &trimmedResult);
  1132. if (destination) {
  1133. break;
  1134. }
  1135. }
  1136. p ++;
  1137. }
  1138. }
  1139. if (destination) {
  1140. replaced = TRUE;
  1141. if (trimmedResult) {
  1142. oldData = StringSearchAndReplace (newData, p, trimmedResult);
  1143. if (oldData) {
  1144. FreePathString (newData);
  1145. newData = oldData;
  1146. }
  1147. FreePathString (trimmedResult);
  1148. } else {
  1149. nativeDest = IsmGetNativeObjectName (MIG_FILE_TYPE, destination);
  1150. oldData = StringSearchAndReplace (newData, p, nativeDest);
  1151. if (oldData) {
  1152. FreePathString (newData);
  1153. newData = oldData;
  1154. }
  1155. IsmReleaseMemory (nativeDest);
  1156. }
  1157. IsmDestroyObjectHandle (destination);
  1158. destination = NULL;
  1159. }
  1160. }
  1161. }
  1162. GbFree (&cmdLineBuffer);
  1163. if (!replaced) {
  1164. if (newData) {
  1165. FreePathString (newData);
  1166. }
  1167. } else {
  1168. if (newData) {
  1169. GbAppendString (&resultBuffer, newData);
  1170. FreePathString (newData);
  1171. }
  1172. }
  1173. }
  1174. if (destination) {
  1175. IsmDestroyObjectHandle (destination);
  1176. destination = NULL;
  1177. }
  1178. if (replaced && resultBuffer.Buf) {
  1179. // looks like we have new content
  1180. // Let's do one more check. If this is a REG_EXPAND_SZ we will do our best to
  1181. // keep the stuff unexpanded. So if the source string expanded on the destination
  1182. // machine is the same as the destination string we won't do anything.
  1183. newContent = TRUE;
  1184. destResult = IsmExpandEnvironmentString (
  1185. PLATFORM_DESTINATION,
  1186. S_SYSENVVAR_GROUP,
  1187. SourceBuffer,
  1188. NULL
  1189. );
  1190. if (destResult && StringIMatch (destResult, (PCTSTR)resultBuffer.Buf)) {
  1191. newContent = FALSE;
  1192. }
  1193. if (destResult) {
  1194. IsmReleaseMemory (destResult);
  1195. destResult = NULL;
  1196. }
  1197. if (newContent) {
  1198. result = DuplicatePathString ((PCTSTR)resultBuffer.Buf, 0);
  1199. }
  1200. }
  1201. GbFree (&resultBuffer);
  1202. }
  1203. return result;
  1204. }
  1205. BOOL
  1206. WINAPI
  1207. DoLnkContentFix (
  1208. IN MIG_OBJECTTYPEID SrcObjectTypeId,
  1209. IN MIG_OBJECTSTRINGHANDLE SrcObjectName,
  1210. IN PCMIG_CONTENT OriginalContent,
  1211. IN PCMIG_CONTENT CurrentContent,
  1212. OUT PMIG_CONTENT NewContent,
  1213. IN PCMIG_BLOB SourceOperationData, OPTIONAL
  1214. IN PCMIG_BLOB DestinationOperationData OPTIONAL
  1215. )
  1216. {
  1217. MIG_PROPERTYDATAID propDataId;
  1218. MIG_BLOBTYPE propDataType;
  1219. UINT requiredSize;
  1220. BOOL lnkTargetPresent = FALSE;
  1221. PCTSTR lnkTargetNode = NULL;
  1222. PCTSTR lnkTargetLeaf = NULL;
  1223. PCTSTR objectNode = NULL;
  1224. PCTSTR objectLeaf = NULL;
  1225. MIG_OBJECTSTRINGHANDLE lnkTarget = NULL;
  1226. MIG_OBJECTTYPEID lnkTargetDestType = 0;
  1227. MIG_OBJECTSTRINGHANDLE lnkTargetDest = NULL;
  1228. BOOL lnkTargetDestDel = FALSE;
  1229. BOOL lnkTargetDestRepl = FALSE;
  1230. PCTSTR lnkTargetDestNative = NULL;
  1231. PCTSTR lnkParams = NULL;
  1232. PCTSTR lnkParamsNew = NULL;
  1233. MIG_OBJECTSTRINGHANDLE lnkWorkDir = NULL;
  1234. MIG_OBJECTTYPEID lnkWorkDirDestType = 0;
  1235. MIG_OBJECTSTRINGHANDLE lnkWorkDirDest = NULL;
  1236. BOOL lnkWorkDirDestDel = FALSE;
  1237. BOOL lnkWorkDirDestRepl = FALSE;
  1238. PCTSTR lnkWorkDirDestNative = NULL;
  1239. PCTSTR lnkRawWorkDir = NULL;
  1240. PCTSTR lnkRawWorkDirExp = NULL;
  1241. MIG_OBJECTSTRINGHANDLE lnkIconPath = NULL;
  1242. MIG_OBJECTTYPEID lnkIconPathDestType = 0;
  1243. MIG_OBJECTSTRINGHANDLE lnkIconPathDest = NULL;
  1244. BOOL lnkIconPathDestDel = FALSE;
  1245. BOOL lnkIconPathDestRepl = FALSE;
  1246. PCTSTR lnkIconPathDestNative = NULL;
  1247. INT lnkIconNumber = 0;
  1248. PICON_GROUP lnkIconGroup = NULL;
  1249. ICON_SGROUP lnkIconSGroup = {0, NULL};
  1250. WORD lnkHotKey = 0;
  1251. BOOL lnkDosApp = FALSE;
  1252. BOOL lnkMsDosMode = FALSE;
  1253. PLNK_EXTRA_DATA lnkExtraData = NULL;
  1254. BOOL comInit = FALSE;
  1255. BOOL modifyFile = FALSE;
  1256. PTSTR iconLibPath = NULL;
  1257. PTSTR newShortcutPath = NULL;
  1258. MIG_CONTENT lnkIconContent;
  1259. // now it's finally time to fix the LNK file content
  1260. if ((g_ShellLink == NULL) || (g_PersistFile == NULL)) {
  1261. comInit = TRUE;
  1262. if (!InitCOMLink (&g_ShellLink, &g_PersistFile)) {
  1263. DEBUGMSG ((DBG_ERROR, "Error initializing COM %d", GetLastError ()));
  1264. return TRUE;
  1265. }
  1266. }
  1267. // first, retrieve the properties
  1268. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_Target);
  1269. if (propDataId) {
  1270. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1271. lnkTarget = PmGetMemory (g_LinksPool, requiredSize);
  1272. IsmGetPropertyData (propDataId, (PBYTE)lnkTarget, requiredSize, NULL, &propDataType);
  1273. }
  1274. }
  1275. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_Params);
  1276. if (propDataId) {
  1277. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1278. lnkParams = PmGetMemory (g_LinksPool, requiredSize);
  1279. IsmGetPropertyData (propDataId, (PBYTE)lnkParams, requiredSize, NULL, &propDataType);
  1280. }
  1281. }
  1282. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_WorkDir);
  1283. if (propDataId) {
  1284. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1285. lnkWorkDir = PmGetMemory (g_LinksPool, requiredSize);
  1286. IsmGetPropertyData (propDataId, (PBYTE)lnkWorkDir, requiredSize, NULL, &propDataType);
  1287. }
  1288. }
  1289. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_RawWorkDir);
  1290. if (propDataId) {
  1291. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1292. lnkRawWorkDir = PmGetMemory (g_LinksPool, requiredSize);
  1293. IsmGetPropertyData (propDataId, (PBYTE)lnkRawWorkDir, requiredSize, NULL, &propDataType);
  1294. }
  1295. }
  1296. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconPath);
  1297. if (propDataId) {
  1298. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1299. lnkIconPath = PmGetMemory (g_LinksPool, requiredSize);
  1300. IsmGetPropertyData (propDataId, (PBYTE)lnkIconPath, requiredSize, NULL, &propDataType);
  1301. }
  1302. }
  1303. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconNumber);
  1304. if (propDataId) {
  1305. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1306. if (requiredSize == sizeof (INT)) {
  1307. IsmGetPropertyData (propDataId, (PBYTE)(&lnkIconNumber), requiredSize, NULL, &propDataType);
  1308. }
  1309. }
  1310. }
  1311. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconData);
  1312. if (propDataId) {
  1313. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1314. lnkIconSGroup.DataSize = requiredSize;
  1315. lnkIconSGroup.Data = PmGetMemory (g_LinksPool, requiredSize);
  1316. IsmGetPropertyData (propDataId, (PBYTE)lnkIconSGroup.Data, requiredSize, NULL, &propDataType);
  1317. }
  1318. }
  1319. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_HotKey);
  1320. if (propDataId) {
  1321. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1322. if (requiredSize == sizeof (WORD)) {
  1323. IsmGetPropertyData (propDataId, (PBYTE)(&lnkHotKey), requiredSize, NULL, &propDataType);
  1324. }
  1325. }
  1326. }
  1327. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_DosApp);
  1328. if (propDataId) {
  1329. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1330. if (requiredSize == sizeof (BOOL)) {
  1331. IsmGetPropertyData (propDataId, (PBYTE)(&lnkDosApp), requiredSize, NULL, &propDataType);
  1332. }
  1333. }
  1334. }
  1335. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_MsDosMode);
  1336. if (propDataId) {
  1337. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1338. if (requiredSize == sizeof (BOOL)) {
  1339. IsmGetPropertyData (propDataId, (PBYTE)(&lnkMsDosMode), requiredSize, NULL, &propDataType);
  1340. }
  1341. }
  1342. }
  1343. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_ExtraData);
  1344. if (propDataId) {
  1345. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1346. lnkExtraData = PmGetMemory (g_LinksPool, requiredSize);
  1347. IsmGetPropertyData (propDataId, (PBYTE)lnkExtraData, requiredSize, NULL, &propDataType);
  1348. }
  1349. }
  1350. // let's examine the target, see if it was migrated
  1351. if (lnkTarget) {
  1352. lnkTargetDest = IsmFilterObject (
  1353. MIG_FILE_TYPE | PLATFORM_SOURCE,
  1354. lnkTarget,
  1355. &lnkTargetDestType,
  1356. &lnkTargetDestDel,
  1357. &lnkTargetDestRepl
  1358. );
  1359. if (((lnkTargetDestDel == FALSE) || (lnkTargetDestRepl == TRUE)) &&
  1360. ((lnkTargetDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE)
  1361. ) {
  1362. if (lnkTargetDest) {
  1363. // the target changed location, we need to adjust the link
  1364. modifyFile = TRUE;
  1365. lnkTargetDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkTargetDest);
  1366. }
  1367. }
  1368. lnkTargetPresent = !lnkTargetDestDel;
  1369. }
  1370. // let's examine the parameters
  1371. if (lnkParams) {
  1372. lnkParamsNew = pFilterBuffer (lnkParams, NULL);
  1373. if (lnkParamsNew) {
  1374. modifyFile = TRUE;
  1375. }
  1376. }
  1377. // let's examine the working directory
  1378. if (lnkWorkDir) {
  1379. lnkWorkDirDest = IsmFilterObject (
  1380. MIG_FILE_TYPE | PLATFORM_SOURCE,
  1381. lnkWorkDir,
  1382. &lnkWorkDirDestType,
  1383. &lnkWorkDirDestDel,
  1384. &lnkWorkDirDestRepl
  1385. );
  1386. if (((lnkWorkDirDestDel == FALSE) || (lnkWorkDirDestRepl == TRUE)) &&
  1387. ((lnkWorkDirDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE)
  1388. ) {
  1389. if (lnkWorkDirDest) {
  1390. // the working directory changed location
  1391. // Normally we would want to adjust the link's working directory
  1392. // to point to the new location. However, let's take the raw working directory,
  1393. // expand it and see if it matches the lnkWorkDirDest. If it does we won't touch
  1394. // it since the raw working directory is working great. If it doesn't we will
  1395. // modify the link
  1396. lnkWorkDirDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkWorkDirDest);
  1397. lnkRawWorkDirExp = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, lnkRawWorkDir, NULL);
  1398. if ((!lnkWorkDirDestNative) ||
  1399. (!lnkRawWorkDirExp) ||
  1400. (!StringIMatch (lnkRawWorkDirExp, lnkWorkDirDestNative))) {
  1401. modifyFile = TRUE;
  1402. } else {
  1403. IsmReleaseMemory (lnkWorkDirDestNative);
  1404. lnkWorkDirDestNative = NULL;
  1405. }
  1406. if (lnkRawWorkDirExp) {
  1407. IsmReleaseMemory (lnkRawWorkDirExp);
  1408. lnkRawWorkDirExp = NULL;
  1409. }
  1410. }
  1411. } else {
  1412. // seems like the working directory is gone. If the target is still present, we will adjust
  1413. // the working directory to point where the target is located
  1414. if (lnkTargetPresent) {
  1415. if (IsmCreateObjectStringsFromHandle (lnkTargetDest?lnkTargetDest:lnkTarget, &lnkTargetNode, &lnkTargetLeaf)) {
  1416. lnkWorkDirDest = IsmCreateObjectHandle (lnkTargetNode, NULL);
  1417. if (lnkWorkDirDest) {
  1418. modifyFile = TRUE;
  1419. lnkWorkDirDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkWorkDirDest);
  1420. }
  1421. IsmDestroyObjectString (lnkTargetNode);
  1422. IsmDestroyObjectString (lnkTargetLeaf);
  1423. }
  1424. }
  1425. }
  1426. }
  1427. // let's examine the icon path
  1428. if (lnkIconPath) {
  1429. lnkIconPathDest = IsmFilterObject (
  1430. MIG_FILE_TYPE | PLATFORM_SOURCE,
  1431. lnkIconPath,
  1432. &lnkIconPathDestType,
  1433. &lnkIconPathDestDel,
  1434. &lnkIconPathDestRepl
  1435. );
  1436. // if the icon holder is deleted we will extract the icon and put it in our lib.
  1437. // The point is, even if the icon holder is replaced (that is, exists on the destination
  1438. // machine), we cannot guarantee that the icon indexes will be the same. Typically, shell32.dll
  1439. // icon indexes changed from version to version, and if a user picked an shell32.dll icon on Win9x,
  1440. // he will have a surprise on Win XP. If we wanted to keep the icon from the replacement file, we just
  1441. // need to check for lnkIconPathDestRepl.
  1442. if ((lnkIconPathDestDel == FALSE) &&
  1443. ((lnkIconPathDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE)
  1444. ) {
  1445. if (lnkIconPathDest) {
  1446. // the icon path changed location, we need to adjust the link
  1447. modifyFile = TRUE;
  1448. lnkIconPathDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkIconPathDest);
  1449. }
  1450. } else {
  1451. // seems like the icon path is gone. If the we have the icon extracted we will try to add it to the
  1452. // icon library and adjust this link to point there.
  1453. if (lnkIconSGroup.DataSize) {
  1454. lnkIconGroup = IcoDeSerializeIconGroup (&lnkIconSGroup);
  1455. if (lnkIconGroup) {
  1456. if (IsmGetEnvironmentString (
  1457. PLATFORM_DESTINATION,
  1458. NULL,
  1459. S_ENV_ICONLIB,
  1460. NULL,
  1461. 0,
  1462. &requiredSize
  1463. )) {
  1464. iconLibPath = PmGetMemory (g_LinksPool, requiredSize);
  1465. if (IsmGetEnvironmentString (
  1466. PLATFORM_DESTINATION,
  1467. NULL,
  1468. S_ENV_ICONLIB,
  1469. iconLibPath,
  1470. requiredSize,
  1471. NULL
  1472. )) {
  1473. if (IcoWriteIconGroupToPeFile (iconLibPath, lnkIconGroup, NULL, &lnkIconNumber)) {
  1474. modifyFile = TRUE;
  1475. lnkIconPathDestNative = IsmGetMemory (SizeOfString (iconLibPath));
  1476. StringCopy ((PTSTR)lnkIconPathDestNative, iconLibPath);
  1477. IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_ENV_SAVE_ICONLIB);
  1478. }
  1479. }
  1480. PmReleaseMemory (g_LinksPool, iconLibPath);
  1481. }
  1482. IcoReleaseIconGroup (lnkIconGroup);
  1483. }
  1484. } else {
  1485. // we don't have the icon extracted. Let's just do our best and update the
  1486. // icon path to point to the destination replacement.
  1487. if (((lnkIconPathDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE) &&
  1488. (lnkIconPathDest)
  1489. ) {
  1490. // the icon path changed location, we need to adjust the link
  1491. modifyFile = TRUE;
  1492. lnkIconPathDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkIconPathDest);
  1493. }
  1494. }
  1495. }
  1496. } else {
  1497. // If we have an icon extracted, but the icon path is NULL, it
  1498. // means that the original LNK had no icon associated with it
  1499. // but it's target was an EXE. In this case the icon that was
  1500. // displayed was the first icon from the EXE. Now we want to
  1501. // make sure that the destination target has at least one icon
  1502. // in it. If it doesn't we will just hook the source extracted icon.
  1503. if (lnkIconSGroup.DataSize) {
  1504. // let's see if the destination target has at least one icon
  1505. if (IsmAcquireObjectEx (
  1506. MIG_FILE_TYPE | PLATFORM_DESTINATION,
  1507. lnkTargetDest?lnkTargetDest:lnkTarget,
  1508. &lnkIconContent,
  1509. CONTENTTYPE_FILE,
  1510. 0
  1511. )) {
  1512. if (lnkIconContent.ContentInFile && lnkIconContent.FileContent.ContentPath) {
  1513. lnkIconGroup = IcoExtractIconGroupByIndexFromFile (
  1514. lnkIconContent.FileContent.ContentPath,
  1515. 0,
  1516. NULL
  1517. );
  1518. if (lnkIconGroup) {
  1519. // Yes, it has at least one icon, we're safe
  1520. IcoReleaseIconGroup (lnkIconGroup);
  1521. lnkIconGroup = NULL;
  1522. } else {
  1523. // Nope, it does not have any icons
  1524. lnkIconGroup = IcoDeSerializeIconGroup (&lnkIconSGroup);
  1525. if (lnkIconGroup) {
  1526. if (IsmGetEnvironmentString (
  1527. PLATFORM_DESTINATION,
  1528. NULL,
  1529. S_ENV_ICONLIB,
  1530. NULL,
  1531. 0,
  1532. &requiredSize
  1533. )) {
  1534. iconLibPath = PmGetMemory (g_LinksPool, requiredSize);
  1535. if (IsmGetEnvironmentString (
  1536. PLATFORM_DESTINATION,
  1537. NULL,
  1538. S_ENV_ICONLIB,
  1539. iconLibPath,
  1540. requiredSize,
  1541. NULL
  1542. )) {
  1543. if (IcoWriteIconGroupToPeFile (iconLibPath, lnkIconGroup, NULL, &lnkIconNumber)) {
  1544. modifyFile = TRUE;
  1545. lnkIconPathDestNative = IsmGetMemory (SizeOfString (iconLibPath));
  1546. StringCopy ((PTSTR)lnkIconPathDestNative, iconLibPath);
  1547. IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_ENV_SAVE_ICONLIB);
  1548. }
  1549. }
  1550. PmReleaseMemory (g_LinksPool, iconLibPath);
  1551. }
  1552. IcoReleaseIconGroup (lnkIconGroup);
  1553. }
  1554. }
  1555. }
  1556. IsmReleaseObject (&lnkIconContent);
  1557. }
  1558. }
  1559. }
  1560. if (modifyFile) {
  1561. if (CurrentContent->ContentInFile) {
  1562. if (IsmCreateObjectStringsFromHandle (SrcObjectName, &objectNode, &objectLeaf)) {
  1563. // We need to modify the shortcut. Unfortunately, if this is the command
  1564. // line tool, the shortcut we are going to modify is not some temporary file,
  1565. // it is the actual shortcut from the store. As a result, if you try to
  1566. // apply a second time, the shortcut would be already modified and problems
  1567. // may appear. For this, we will get a temporary directory from ISM,
  1568. // copy the current shortcut (CurrentContent->FileContent.ContentPath) and
  1569. // modify it and generate a new content.
  1570. newShortcutPath = IsmGetMemory (MAX_PATH);
  1571. if (newShortcutPath) {
  1572. if (IsmGetTempFile (newShortcutPath, MAX_PATH)) {
  1573. if (CopyFile (
  1574. (PCTSTR) CurrentContent->FileContent.ContentPath,
  1575. newShortcutPath,
  1576. FALSE
  1577. )) {
  1578. if (ModifyShortcutFileEx (
  1579. newShortcutPath,
  1580. GetFileExtensionFromPath (objectLeaf),
  1581. lnkTargetDestNative,
  1582. lnkParamsNew,
  1583. lnkWorkDirDestNative,
  1584. lnkIconPathDestNative,
  1585. lnkIconNumber,
  1586. lnkHotKey,
  1587. NULL,
  1588. g_ShellLink,
  1589. g_PersistFile
  1590. )) {
  1591. NewContent->FileContent.ContentPath = newShortcutPath;
  1592. }
  1593. }
  1594. }
  1595. }
  1596. IsmDestroyObjectString (objectNode);
  1597. IsmDestroyObjectString (objectLeaf);
  1598. }
  1599. } else {
  1600. // something is wrong, the content of this shortcut should be in a file
  1601. MYASSERT (FALSE);
  1602. }
  1603. }
  1604. if (lnkIconPathDestNative) {
  1605. IsmReleaseMemory (lnkIconPathDestNative);
  1606. lnkIconPathDestNative = NULL;
  1607. }
  1608. if (lnkWorkDirDestNative) {
  1609. IsmReleaseMemory (lnkWorkDirDestNative);
  1610. lnkWorkDirDestNative = NULL;
  1611. }
  1612. if (lnkTargetDestNative) {
  1613. IsmReleaseMemory (lnkTargetDestNative);
  1614. lnkTargetDestNative = NULL;
  1615. }
  1616. if (lnkIconPathDest) {
  1617. IsmDestroyObjectHandle (lnkIconPathDest);
  1618. lnkIconPathDest = NULL;
  1619. }
  1620. if (lnkWorkDirDest) {
  1621. IsmDestroyObjectHandle (lnkWorkDirDest);
  1622. lnkWorkDirDest = NULL;
  1623. }
  1624. if (lnkTargetDest) {
  1625. IsmDestroyObjectHandle (lnkTargetDest);
  1626. lnkTargetDest = NULL;
  1627. }
  1628. if (lnkExtraData) {
  1629. PmReleaseMemory (g_LinksPool, lnkExtraData);
  1630. lnkExtraData = NULL;
  1631. }
  1632. if (lnkIconSGroup.DataSize && lnkIconSGroup.Data) {
  1633. PmReleaseMemory (g_LinksPool, lnkIconSGroup.Data);
  1634. lnkIconSGroup.DataSize = 0;
  1635. lnkIconSGroup.Data = NULL;
  1636. }
  1637. if (lnkIconPath) {
  1638. PmReleaseMemory (g_LinksPool, lnkIconPath);
  1639. lnkIconPath = NULL;
  1640. }
  1641. if (lnkWorkDir) {
  1642. PmReleaseMemory (g_LinksPool, lnkWorkDir);
  1643. lnkWorkDir = NULL;
  1644. }
  1645. if (lnkParams) {
  1646. PmReleaseMemory (g_LinksPool, lnkParams);
  1647. lnkParams = NULL;
  1648. }
  1649. if (lnkTarget) {
  1650. PmReleaseMemory (g_LinksPool, lnkTarget);
  1651. lnkTarget = NULL;
  1652. }
  1653. if (comInit) {
  1654. FreeCOMLink (&g_ShellLink, &g_PersistFile);
  1655. g_ShellLink = NULL;
  1656. g_PersistFile = NULL;
  1657. }
  1658. return TRUE;
  1659. }
  1660. BOOL
  1661. LinkRestoreCallback (
  1662. IN MIG_OBJECTTYPEID ObjectTypeId,
  1663. IN MIG_OBJECTID ObjectId,
  1664. IN MIG_OBJECTSTRINGHANDLE ObjectName
  1665. )
  1666. {
  1667. MIG_PROPERTYDATAID propDataId;
  1668. MIG_BLOBTYPE propDataType;
  1669. UINT requiredSize;
  1670. MIG_OBJECTSTRINGHANDLE lnkTarget = NULL;
  1671. MIG_OBJECTTYPEID lnkTargetDestType = 0;
  1672. MIG_OBJECTSTRINGHANDLE lnkTargetDest = NULL;
  1673. BOOL lnkTargetDestDel = FALSE;
  1674. BOOL lnkTargetDestRepl = FALSE;
  1675. PCTSTR lnkTargetNative = NULL;
  1676. PCTSTR objectNode = NULL;
  1677. PCTSTR objectLeaf = NULL;
  1678. PCTSTR extPtr = NULL;
  1679. PCTSTR userProfile = NULL;
  1680. PCTSTR allUsersProfile = NULL;
  1681. PCTSTR newObjectNode = NULL;
  1682. MIG_OBJECTSTRINGHANDLE newObjectName = NULL;
  1683. MIG_CONTENT oldContent;
  1684. MIG_CONTENT newContent;
  1685. BOOL identical = FALSE;
  1686. BOOL diffDetailsOnly = FALSE;
  1687. BOOL result = TRUE;
  1688. if (IsmIsAttributeSetOnObjectId (ObjectId, g_CopyIfRelevantAttr)) {
  1689. if (IsmCreateObjectStringsFromHandle (ObjectName, &objectNode, &objectLeaf)) {
  1690. if (objectLeaf) {
  1691. extPtr = GetFileExtensionFromPath (objectLeaf);
  1692. if (extPtr &&
  1693. (StringIMatch (extPtr, TEXT("LNK")) ||
  1694. StringIMatch (extPtr, TEXT("PIF"))
  1695. )
  1696. ) {
  1697. propDataId = IsmGetPropertyFromObject (ObjectTypeId, ObjectName, g_LnkMigProp_Target);
  1698. if (propDataId) {
  1699. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  1700. lnkTarget = PmGetMemory (g_LinksPool, requiredSize);
  1701. IsmGetPropertyData (propDataId, (PBYTE)lnkTarget, requiredSize, NULL, &propDataType);
  1702. lnkTargetNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkTarget);
  1703. if (lnkTargetNative) {
  1704. if (pIsUncPath (lnkTargetNative)) {
  1705. result = TRUE;
  1706. } else {
  1707. lnkTargetDest = IsmFilterObject (
  1708. MIG_FILE_TYPE | PLATFORM_SOURCE,
  1709. lnkTarget,
  1710. &lnkTargetDestType,
  1711. &lnkTargetDestDel,
  1712. &lnkTargetDestRepl
  1713. );
  1714. result = (lnkTargetDestDel == FALSE) || (lnkTargetDestRepl == TRUE);
  1715. if (lnkTargetDest) {
  1716. IsmDestroyObjectHandle (lnkTargetDest);
  1717. }
  1718. }
  1719. IsmReleaseMemory (lnkTargetNative);
  1720. } else {
  1721. result = FALSE;
  1722. }
  1723. PmReleaseMemory (g_LinksPool, lnkTarget);
  1724. }
  1725. }
  1726. if (result) {
  1727. // one more thing. If this LNK is in %USERPROFILE% and an equivalent LNK
  1728. // (same name, same target, same arguments, same working dir) can be found
  1729. // in %ALLUSERSPROFILE% then we won't restore this LNK. Similarly, if the
  1730. // LNK is in %ALLUSERSPROFILE% and an equivalent LNK exists in %USERPROFILE%
  1731. // we won't restore the LNK.
  1732. userProfile = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT ("%USERPROFILE%"), NULL);
  1733. allUsersProfile = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT ("%ALLUSERSPROFILE%"), NULL);
  1734. if (userProfile && allUsersProfile && objectNode) {
  1735. if (StringIPrefix (objectNode, userProfile)) {
  1736. newObjectNode = StringSearchAndReplace (objectNode, userProfile, allUsersProfile);
  1737. if (newObjectNode) {
  1738. newObjectName = IsmCreateObjectHandle (newObjectNode, objectLeaf);
  1739. if (newObjectName) {
  1740. if (IsmAcquireObjectEx (
  1741. (ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION,
  1742. newObjectName,
  1743. &newContent,
  1744. CONTENTTYPE_FILE,
  1745. 0
  1746. )) {
  1747. if (IsmAcquireObjectEx (
  1748. ObjectTypeId,
  1749. ObjectName,
  1750. &oldContent,
  1751. CONTENTTYPE_FILE,
  1752. 0
  1753. )) {
  1754. if (LinkDoesContentMatch (
  1755. FALSE,
  1756. ObjectTypeId,
  1757. ObjectName,
  1758. &oldContent,
  1759. (ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION,
  1760. newObjectName,
  1761. &newContent,
  1762. &identical,
  1763. &diffDetailsOnly
  1764. )) {
  1765. result = (!identical) && (!diffDetailsOnly);
  1766. }
  1767. IsmReleaseObject (&oldContent);
  1768. }
  1769. IsmReleaseObject (&newContent);
  1770. }
  1771. IsmDestroyObjectHandle (newObjectName);
  1772. newObjectName = NULL;
  1773. }
  1774. FreePathString (newObjectNode);
  1775. newObjectNode = NULL;
  1776. }
  1777. }
  1778. }
  1779. if (userProfile) {
  1780. IsmReleaseMemory (userProfile);
  1781. userProfile = NULL;
  1782. }
  1783. if (allUsersProfile) {
  1784. IsmReleaseMemory (allUsersProfile);
  1785. allUsersProfile = NULL;
  1786. }
  1787. allUsersProfile = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT ("%ALLUSERSPROFILE%"), NULL);
  1788. userProfile = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT ("%USERPROFILE%"), NULL);
  1789. if (userProfile && allUsersProfile && objectNode) {
  1790. if (StringIPrefix (objectNode, allUsersProfile)) {
  1791. newObjectNode = StringSearchAndReplace (objectNode, allUsersProfile, userProfile);
  1792. if (newObjectNode) {
  1793. newObjectName = IsmCreateObjectHandle (newObjectNode, objectLeaf);
  1794. if (newObjectName) {
  1795. if (IsmAcquireObjectEx (
  1796. (ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION,
  1797. newObjectName,
  1798. &newContent,
  1799. CONTENTTYPE_FILE,
  1800. 0
  1801. )) {
  1802. if (IsmAcquireObjectEx (
  1803. ObjectTypeId,
  1804. ObjectName,
  1805. &oldContent,
  1806. CONTENTTYPE_FILE,
  1807. 0
  1808. )) {
  1809. if (LinkDoesContentMatch (
  1810. FALSE,
  1811. ObjectTypeId,
  1812. ObjectName,
  1813. &oldContent,
  1814. (ObjectTypeId & ~PLATFORM_MASK) | PLATFORM_DESTINATION,
  1815. newObjectName,
  1816. &newContent,
  1817. &identical,
  1818. &diffDetailsOnly
  1819. )) {
  1820. result = (!identical) || (!diffDetailsOnly);
  1821. }
  1822. IsmReleaseObject (&oldContent);
  1823. }
  1824. IsmReleaseObject (&newContent);
  1825. }
  1826. IsmDestroyObjectHandle (newObjectName);
  1827. newObjectName = NULL;
  1828. }
  1829. FreePathString (newObjectNode);
  1830. newObjectNode = NULL;
  1831. }
  1832. }
  1833. }
  1834. if (userProfile) {
  1835. IsmReleaseMemory (userProfile);
  1836. userProfile = NULL;
  1837. }
  1838. if (allUsersProfile) {
  1839. IsmReleaseMemory (allUsersProfile);
  1840. allUsersProfile = NULL;
  1841. }
  1842. }
  1843. }
  1844. }
  1845. IsmDestroyObjectString (objectNode);
  1846. IsmDestroyObjectString (objectLeaf);
  1847. }
  1848. }
  1849. return result;
  1850. }
  1851. BOOL
  1852. pMatchWinSysFiles (
  1853. IN PCTSTR Source,
  1854. IN PCTSTR Destination
  1855. )
  1856. {
  1857. PCTSTR srcLeaf;
  1858. PCTSTR destLeaf;
  1859. PCTSTR winDir = NULL;
  1860. PCTSTR sysDir = NULL;
  1861. BOOL result = FALSE;
  1862. __try {
  1863. if ((!Source) || (!Destination)) {
  1864. __leave;
  1865. }
  1866. srcLeaf = _tcsrchr (Source, TEXT('\\'));
  1867. destLeaf = _tcsrchr (Destination, TEXT('\\'));
  1868. if ((!srcLeaf) || (!destLeaf)) {
  1869. __leave;
  1870. }
  1871. if (!StringIMatch (srcLeaf, destLeaf)) {
  1872. __leave;
  1873. }
  1874. // now let's see if the directory for each is either
  1875. // %windir% or %system%
  1876. // Source is already modified to what it would look like on the destination machine,
  1877. // let's just expand the PLATFORM_DESTINATION env. variables.
  1878. winDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%windir%"), NULL);
  1879. sysDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%system%"), NULL);
  1880. if ((!winDir) || (!sysDir)) {
  1881. __leave;
  1882. }
  1883. if (!StringIPrefix (Source, winDir) && !StringIPrefix (Source, sysDir)) {
  1884. __leave;
  1885. }
  1886. IsmReleaseMemory (winDir);
  1887. winDir = NULL;
  1888. IsmReleaseMemory (sysDir);
  1889. sysDir = NULL;
  1890. winDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%windir%"), NULL);
  1891. sysDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT("%system%"), NULL);
  1892. if ((!winDir) || (!sysDir)) {
  1893. __leave;
  1894. }
  1895. if (!StringIPrefix (Destination, winDir) && !StringIPrefix (Destination, sysDir)) {
  1896. __leave;
  1897. }
  1898. IsmReleaseMemory (winDir);
  1899. winDir = NULL;
  1900. IsmReleaseMemory (sysDir);
  1901. sysDir = NULL;
  1902. result = TRUE;
  1903. }
  1904. __finally {
  1905. if (winDir) {
  1906. IsmReleaseMemory (winDir);
  1907. winDir = NULL;
  1908. }
  1909. if (sysDir) {
  1910. IsmReleaseMemory (sysDir);
  1911. sysDir = NULL;
  1912. }
  1913. }
  1914. return result;
  1915. }
  1916. BOOL
  1917. pForcedLnkMatch (
  1918. IN PCTSTR SrcTarget,
  1919. IN PCTSTR SrcParams,
  1920. IN PCTSTR SrcWorkDir,
  1921. IN PCTSTR DestTarget,
  1922. IN PCTSTR DestParams,
  1923. IN PCTSTR DestWorkDir
  1924. )
  1925. {
  1926. PTSTR multiSz = NULL;
  1927. MULTISZ_ENUM e;
  1928. UINT sizeNeeded;
  1929. HINF infHandle = INVALID_HANDLE_VALUE;
  1930. ENVENTRY_TYPE dataType;
  1931. INFSTRUCT is = INITINFSTRUCT_PMHANDLE;
  1932. PCTSTR srcTargetPat = NULL;
  1933. PCTSTR srcParamsPat = NULL;
  1934. PCTSTR srcWorkDirPat = NULL;
  1935. PCTSTR destTargetPat = NULL;
  1936. PCTSTR destParamsPat = NULL;
  1937. PCTSTR destWorkDirPat = NULL;
  1938. BOOL result = FALSE;
  1939. // let's look in the INFs in section [EquivalentLinks] and see if our LNKs match
  1940. // one of the lines. If they do then they are equivalent
  1941. if (IsmGetEnvironmentValue (
  1942. IsmGetRealPlatform (),
  1943. NULL,
  1944. S_GLOBAL_INF_HANDLE,
  1945. (PBYTE)(&infHandle),
  1946. sizeof (HINF),
  1947. &sizeNeeded,
  1948. &dataType
  1949. ) &&
  1950. (sizeNeeded == sizeof (HINF)) &&
  1951. (dataType == ENVENTRY_BINARY)
  1952. ) {
  1953. if (InfFindFirstLine (infHandle, TEXT("EquivalentLinks"), NULL, &is)) {
  1954. do {
  1955. srcTargetPat = InfGetStringField (&is, 1);
  1956. srcParamsPat = InfGetStringField (&is, 2);
  1957. srcWorkDirPat = InfGetStringField (&is, 3);
  1958. destTargetPat = InfGetStringField (&is, 4);
  1959. destParamsPat = InfGetStringField (&is, 5);
  1960. destWorkDirPat = InfGetStringField (&is, 6);
  1961. if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) &&
  1962. IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) &&
  1963. IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT("")) &&
  1964. IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) &&
  1965. IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) &&
  1966. IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT(""))
  1967. ) {
  1968. result = TRUE;
  1969. break;
  1970. }
  1971. if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) &&
  1972. IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) &&
  1973. IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT("")) &&
  1974. IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) &&
  1975. IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) &&
  1976. IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT(""))
  1977. ) {
  1978. result = TRUE;
  1979. break;
  1980. }
  1981. } while (InfFindNextLine (&is));
  1982. }
  1983. InfNameHandle (infHandle, NULL, FALSE);
  1984. } else {
  1985. if (IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, NULL, 0, &sizeNeeded, NULL)) {
  1986. __try {
  1987. multiSz = AllocText (sizeNeeded);
  1988. if (!IsmGetEnvironmentValue (IsmGetRealPlatform (), NULL, S_INF_FILE_MULTISZ, (PBYTE) multiSz, sizeNeeded, NULL, NULL)) {
  1989. __leave;
  1990. }
  1991. if (EnumFirstMultiSz (&e, multiSz)) {
  1992. do {
  1993. infHandle = InfOpenInfFile (e.CurrentString);
  1994. if (infHandle != INVALID_HANDLE_VALUE) {
  1995. if (InfFindFirstLine (infHandle, TEXT("EquivalentLinks"), NULL, &is)) {
  1996. do {
  1997. srcTargetPat = InfGetStringField (&is, 1);
  1998. srcParamsPat = InfGetStringField (&is, 2);
  1999. srcWorkDirPat = InfGetStringField (&is, 3);
  2000. destTargetPat = InfGetStringField (&is, 4);
  2001. destParamsPat = InfGetStringField (&is, 5);
  2002. destWorkDirPat = InfGetStringField (&is, 6);
  2003. if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) &&
  2004. IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) &&
  2005. IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT("")) &&
  2006. IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) &&
  2007. IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) &&
  2008. IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT(""))
  2009. ) {
  2010. result = TRUE;
  2011. break;
  2012. }
  2013. if (IsPatternMatch (srcTargetPat?srcTargetPat:TEXT("*"), DestTarget?DestTarget:TEXT("")) &&
  2014. IsPatternMatch (srcParamsPat?srcParamsPat:TEXT("*"), DestParams?DestParams:TEXT("")) &&
  2015. IsPatternMatch (srcWorkDirPat?srcWorkDirPat:TEXT("*"), DestWorkDir?DestWorkDir:TEXT("")) &&
  2016. IsPatternMatch (destTargetPat?destTargetPat:TEXT("*"), SrcTarget?SrcTarget:TEXT("")) &&
  2017. IsPatternMatch (destParamsPat?destParamsPat:TEXT("*"), SrcParams?SrcParams:TEXT("")) &&
  2018. IsPatternMatch (destWorkDirPat?destWorkDirPat:TEXT("*"), SrcWorkDir?SrcWorkDir:TEXT(""))
  2019. ) {
  2020. result = TRUE;
  2021. break;
  2022. }
  2023. } while (InfFindNextLine (&is));
  2024. }
  2025. }
  2026. InfCloseInfFile (infHandle);
  2027. infHandle = INVALID_HANDLE_VALUE;
  2028. if (result) {
  2029. break;
  2030. }
  2031. } while (EnumNextMultiSz (&e));
  2032. }
  2033. }
  2034. __finally {
  2035. FreeText (multiSz);
  2036. }
  2037. }
  2038. }
  2039. InfResetInfStruct (&is);
  2040. return result;
  2041. }
  2042. BOOL
  2043. LinkDoesContentMatch (
  2044. IN BOOL AlreadyProcessed,
  2045. IN MIG_OBJECTTYPEID SrcObjectTypeId,
  2046. IN MIG_OBJECTSTRINGHANDLE SrcObjectName,
  2047. IN PMIG_CONTENT SrcContent,
  2048. IN MIG_OBJECTTYPEID DestObjectTypeId,
  2049. IN MIG_OBJECTSTRINGHANDLE DestObjectName,
  2050. IN PMIG_CONTENT DestContent,
  2051. OUT PBOOL Identical,
  2052. OUT PBOOL DifferentDetailsOnly
  2053. )
  2054. {
  2055. PCTSTR objectNode = NULL;
  2056. PCTSTR objectLeaf = NULL;
  2057. PCTSTR extPtr = NULL;
  2058. MIG_PROPERTYDATAID propDataId;
  2059. MIG_BLOBTYPE propDataType;
  2060. UINT requiredSize;
  2061. MIG_OBJECTSTRINGHANDLE srcTarget = NULL;
  2062. PCTSTR srcTargetNative = NULL;
  2063. PCTSTR srcParams = NULL;
  2064. PCTSTR srcParamsNew = NULL;
  2065. MIG_OBJECTSTRINGHANDLE srcWorkDir = NULL;
  2066. PCTSTR srcWorkDirNative = NULL;
  2067. PCTSTR srcRawWorkDir = NULL;
  2068. BOOL lnkWorkDirDestDel = FALSE;
  2069. BOOL lnkWorkDirDestRepl = FALSE;
  2070. PCTSTR destTarget = NULL;
  2071. PCTSTR destParams = NULL;
  2072. PCTSTR destWorkDir = NULL;
  2073. PCTSTR destIconPath = NULL;
  2074. PCTSTR expTmpStr;
  2075. PCTSTR longExpTmpStr;
  2076. INT destIconNumber;
  2077. WORD destHotKey;
  2078. BOOL destDosApp;
  2079. BOOL destMsDosMode;
  2080. BOOL comInit = FALSE;
  2081. MIG_OBJECTSTRINGHANDLE lnkDest = NULL;
  2082. PCTSTR lnkNative = NULL;
  2083. BOOL targetOsFile = FALSE;
  2084. BOOL match = FALSE;
  2085. BOOL result = FALSE;
  2086. if ((SrcObjectTypeId & ~PLATFORM_MASK) != MIG_FILE_TYPE) {
  2087. return FALSE;
  2088. }
  2089. if ((DestObjectTypeId & ~PLATFORM_MASK) != MIG_FILE_TYPE) {
  2090. return FALSE;
  2091. }
  2092. // let's check that the source is a shortcut
  2093. if (IsmCreateObjectStringsFromHandle (SrcObjectName, &objectNode, &objectLeaf)) {
  2094. if (objectLeaf) {
  2095. extPtr = GetFileExtensionFromPath (objectLeaf);
  2096. if (extPtr &&
  2097. (StringIMatch (extPtr, TEXT("LNK")) ||
  2098. StringIMatch (extPtr, TEXT("PIF")) ||
  2099. StringIMatch (extPtr, TEXT("URL"))
  2100. )
  2101. ) {
  2102. result = TRUE;
  2103. }
  2104. }
  2105. IsmDestroyObjectString (objectNode);
  2106. IsmDestroyObjectString (objectLeaf);
  2107. }
  2108. if (!result) {
  2109. return FALSE;
  2110. }
  2111. result = FALSE;
  2112. // let's check that the destination is a shortcut
  2113. if (IsmCreateObjectStringsFromHandle (DestObjectName, &objectNode, &objectLeaf)) {
  2114. if (objectLeaf) {
  2115. extPtr = GetFileExtensionFromPath (objectLeaf);
  2116. if (extPtr &&
  2117. (StringIMatch (extPtr, TEXT("LNK")) ||
  2118. StringIMatch (extPtr, TEXT("PIF")) ||
  2119. StringIMatch (extPtr, TEXT("URL"))
  2120. )
  2121. ) {
  2122. result = TRUE;
  2123. }
  2124. }
  2125. IsmDestroyObjectString (objectNode);
  2126. IsmDestroyObjectString (objectLeaf);
  2127. }
  2128. if (!result) {
  2129. return FALSE;
  2130. }
  2131. // some safety checks
  2132. if (!SrcContent->ContentInFile) {
  2133. return FALSE;
  2134. }
  2135. if (!SrcContent->FileContent.ContentPath) {
  2136. return FALSE;
  2137. }
  2138. if (!DestContent->ContentInFile) {
  2139. return FALSE;
  2140. }
  2141. if (!DestContent->FileContent.ContentPath) {
  2142. return FALSE;
  2143. }
  2144. result = FALSE;
  2145. __try {
  2146. // let's get info from the source. We will not look inside the LNK file, we will
  2147. // just get it's properties. If there are no properties, we'll just exit, leaving
  2148. // the default compare to solve the problem.
  2149. // first, retrieve the properties
  2150. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_Target);
  2151. if (propDataId) {
  2152. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  2153. srcTarget = PmGetMemory (g_LinksPool, requiredSize);
  2154. IsmGetPropertyData (propDataId, (PBYTE)srcTarget, requiredSize, NULL, &propDataType);
  2155. }
  2156. }
  2157. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_Params);
  2158. if (propDataId) {
  2159. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  2160. srcParams = PmGetMemory (g_LinksPool, requiredSize);
  2161. IsmGetPropertyData (propDataId, (PBYTE)srcParams, requiredSize, NULL, &propDataType);
  2162. }
  2163. }
  2164. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_RawWorkDir);
  2165. if (propDataId) {
  2166. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  2167. srcRawWorkDir = PmGetMemory (g_LinksPool, requiredSize);
  2168. IsmGetPropertyData (propDataId, (PBYTE)srcRawWorkDir, requiredSize, NULL, &propDataType);
  2169. }
  2170. }
  2171. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId | PLATFORM_SOURCE, SrcObjectName, g_LnkMigProp_WorkDir);
  2172. if (propDataId) {
  2173. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  2174. srcWorkDir = PmGetMemory (g_LinksPool, requiredSize);
  2175. IsmGetPropertyData (propDataId, (PBYTE)srcWorkDir, requiredSize, NULL, &propDataType);
  2176. }
  2177. }
  2178. // now, let's get the info from the destination shortcut
  2179. if ((g_ShellLink == NULL) || (g_PersistFile == NULL)) {
  2180. comInit = TRUE;
  2181. if (!InitCOMLink (&g_ShellLink, &g_PersistFile)) {
  2182. DEBUGMSG ((DBG_ERROR, "Error initializing COM %d", GetLastError ()));
  2183. return TRUE;
  2184. }
  2185. }
  2186. if (!ExtractShortcutInfo (
  2187. DestContent->FileContent.ContentPath,
  2188. &destTarget,
  2189. &destParams,
  2190. &destWorkDir,
  2191. &destIconPath,
  2192. &destIconNumber,
  2193. &destHotKey,
  2194. &destDosApp,
  2195. &destMsDosMode,
  2196. NULL,
  2197. g_ShellLink,
  2198. g_PersistFile
  2199. )) {
  2200. __leave;
  2201. }
  2202. srcTargetNative = IsmGetNativeObjectName (MIG_FILE_TYPE, srcTarget);
  2203. srcWorkDirNative = IsmGetNativeObjectName (MIG_FILE_TYPE, srcWorkDir);
  2204. if (pForcedLnkMatch (
  2205. srcTargetNative,
  2206. srcParams,
  2207. srcWorkDirNative,
  2208. destTarget,
  2209. destParams,
  2210. destWorkDir
  2211. )) {
  2212. if (srcTargetNative) {
  2213. IsmReleaseMemory (srcTargetNative);
  2214. srcTargetNative = NULL;
  2215. }
  2216. if (srcWorkDirNative) {
  2217. IsmReleaseMemory (srcWorkDirNative);
  2218. srcWorkDirNative = NULL;
  2219. }
  2220. result = TRUE;
  2221. if (Identical) {
  2222. *Identical = TRUE;
  2223. }
  2224. if (DifferentDetailsOnly) {
  2225. *DifferentDetailsOnly = FALSE;
  2226. }
  2227. __leave;
  2228. }
  2229. if (srcTargetNative) {
  2230. IsmReleaseMemory (srcTargetNative);
  2231. srcTargetNative = NULL;
  2232. }
  2233. if (srcWorkDirNative) {
  2234. IsmReleaseMemory (srcWorkDirNative);
  2235. srcWorkDirNative = NULL;
  2236. }
  2237. // let's filter the source target and see if it matches the dest target
  2238. match = TRUE;
  2239. if (srcTarget && *srcTarget && destTarget && *destTarget) {
  2240. // let's see if the source target is an OS file
  2241. targetOsFile = IsmIsAttributeSetOnObject (MIG_FILE_TYPE|PLATFORM_SOURCE, srcTarget, g_OsFileAttribute);
  2242. lnkDest = IsmFilterObject (
  2243. MIG_FILE_TYPE | PLATFORM_SOURCE,
  2244. srcTarget,
  2245. NULL,
  2246. NULL,
  2247. NULL
  2248. );
  2249. if (!lnkDest) {
  2250. lnkDest = srcTarget;
  2251. }
  2252. lnkNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkDest);
  2253. if (lnkNative) {
  2254. expTmpStr = IsmExpandEnvironmentString (
  2255. PLATFORM_DESTINATION,
  2256. S_SYSENVVAR_GROUP,
  2257. destTarget,
  2258. NULL
  2259. );
  2260. if (!expTmpStr) {
  2261. expTmpStr = destTarget;
  2262. }
  2263. longExpTmpStr = BfGetLongFileName (expTmpStr);
  2264. if (!longExpTmpStr) {
  2265. longExpTmpStr = expTmpStr;
  2266. }
  2267. if (!StringIMatch (lnkNative, longExpTmpStr)) {
  2268. // different targets
  2269. // Let's try another trick to catch some OS files getting moved.
  2270. // For example, in Win9x systems, notepad.exe is in %windir%.
  2271. // In XP, it was moved to %system%. We'll try to match the target
  2272. // if the last segment is the same and the rest is either %windir%
  2273. // or %system%
  2274. if (!pMatchWinSysFiles (lnkNative, longExpTmpStr)) {
  2275. match = FALSE;
  2276. }
  2277. }
  2278. if (longExpTmpStr != expTmpStr) {
  2279. FreePathString (longExpTmpStr);
  2280. }
  2281. if (expTmpStr != destTarget) {
  2282. IsmReleaseMemory (expTmpStr);
  2283. }
  2284. IsmReleaseMemory (lnkNative);
  2285. lnkNative = NULL;
  2286. } else {
  2287. match = FALSE;
  2288. }
  2289. if (lnkDest != srcTarget) {
  2290. IsmDestroyObjectHandle (lnkDest);
  2291. }
  2292. lnkDest = NULL;
  2293. } else {
  2294. if (srcTarget && *srcTarget) {
  2295. match = FALSE;
  2296. }
  2297. if (destTarget && *destTarget) {
  2298. match = FALSE;
  2299. }
  2300. }
  2301. // the target did not match
  2302. if (!match) {
  2303. __leave;
  2304. }
  2305. // let's match the src and dest parameters
  2306. match = TRUE;
  2307. if (srcParams && *srcParams && destParams && *destParams) {
  2308. // srcParams might have source paths embedded in them.
  2309. // Let's try to filter them and get the parameters as
  2310. // they would look on the destination machine
  2311. srcParamsNew = pFilterBuffer (srcParams, NULL);
  2312. if (!StringIMatch (srcParamsNew?srcParamsNew:srcParams, destParams)) {
  2313. // different parameters
  2314. match = FALSE;
  2315. }
  2316. if (srcParamsNew) {
  2317. FreePathString (srcParamsNew);
  2318. srcParamsNew = NULL;
  2319. }
  2320. } else {
  2321. if (srcParams && *srcParams) {
  2322. match = FALSE;
  2323. }
  2324. if (destParams && *destParams) {
  2325. match = FALSE;
  2326. }
  2327. }
  2328. // the parameters did not match
  2329. if (!match) {
  2330. __leave;
  2331. }
  2332. // let's filter the source work dir and see if it matches the dest work dir.
  2333. match = TRUE;
  2334. // if the source target was an OS file we will ignore the working directory match
  2335. if (!targetOsFile) {
  2336. if (srcWorkDir && *srcWorkDir && destWorkDir && *destWorkDir) {
  2337. lnkDest = IsmFilterObject (
  2338. MIG_FILE_TYPE | PLATFORM_SOURCE,
  2339. srcWorkDir,
  2340. NULL,
  2341. &lnkWorkDirDestDel,
  2342. &lnkWorkDirDestRepl
  2343. );
  2344. if (!lnkDest) {
  2345. // if the working directory is deleted and not
  2346. // replaced it means it will go away. In that case
  2347. // we don't really care about working directory
  2348. // matching the destination one.
  2349. if ((!lnkWorkDirDestDel) || lnkWorkDirDestRepl) {
  2350. lnkDest = srcWorkDir;
  2351. }
  2352. }
  2353. if (lnkDest) {
  2354. lnkNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkDest);
  2355. if (lnkNative) {
  2356. expTmpStr = IsmExpandEnvironmentString (
  2357. PLATFORM_DESTINATION,
  2358. S_SYSENVVAR_GROUP,
  2359. destWorkDir,
  2360. NULL
  2361. );
  2362. if (!expTmpStr) {
  2363. expTmpStr = destWorkDir;
  2364. }
  2365. longExpTmpStr = BfGetLongFileName (expTmpStr);
  2366. if (!longExpTmpStr) {
  2367. longExpTmpStr = expTmpStr;
  2368. }
  2369. if (!StringIMatch (lnkNative, longExpTmpStr)) {
  2370. // different working directories
  2371. // let's test the raw versions just in case
  2372. if (!srcRawWorkDir || !StringIMatch (srcRawWorkDir, destWorkDir)) {
  2373. match = FALSE;
  2374. }
  2375. }
  2376. if (longExpTmpStr != expTmpStr) {
  2377. FreePathString (longExpTmpStr);
  2378. }
  2379. if (expTmpStr != destWorkDir) {
  2380. IsmReleaseMemory (expTmpStr);
  2381. }
  2382. IsmReleaseMemory (lnkNative);
  2383. lnkNative = NULL;
  2384. } else {
  2385. match = FALSE;
  2386. }
  2387. if (lnkDest != srcWorkDir) {
  2388. IsmDestroyObjectHandle (lnkDest);
  2389. }
  2390. lnkDest = NULL;
  2391. }
  2392. } else {
  2393. if (srcWorkDir && *srcWorkDir) {
  2394. match = FALSE;
  2395. }
  2396. if (destWorkDir && *destWorkDir) {
  2397. match = FALSE;
  2398. }
  2399. }
  2400. }
  2401. // the working directory did not match
  2402. if (!match) {
  2403. __leave;
  2404. }
  2405. result = TRUE;
  2406. if (Identical) {
  2407. *Identical = TRUE;
  2408. }
  2409. if (DifferentDetailsOnly) {
  2410. *DifferentDetailsOnly = FALSE;
  2411. }
  2412. }
  2413. __finally {
  2414. if (srcTarget) {
  2415. PmReleaseMemory (g_LinksPool, srcTarget);
  2416. srcTarget = NULL;
  2417. }
  2418. if (srcParams) {
  2419. PmReleaseMemory (g_LinksPool, srcParams);
  2420. srcParams = NULL;
  2421. }
  2422. if (srcRawWorkDir) {
  2423. PmReleaseMemory (g_LinksPool, srcRawWorkDir);
  2424. srcRawWorkDir = NULL;
  2425. }
  2426. if (srcWorkDir) {
  2427. PmReleaseMemory (g_LinksPool, srcWorkDir);
  2428. srcWorkDir = NULL;
  2429. }
  2430. if (destTarget) {
  2431. FreePathString (destTarget);
  2432. destTarget = NULL;
  2433. }
  2434. if (destParams) {
  2435. FreePathString (destParams);
  2436. destParams = NULL;
  2437. }
  2438. if (destWorkDir) {
  2439. FreePathString (destWorkDir);
  2440. destWorkDir = NULL;
  2441. }
  2442. if (destIconPath) {
  2443. FreePathString (destIconPath);
  2444. destIconPath = NULL;
  2445. }
  2446. if (comInit) {
  2447. FreeCOMLink (&g_ShellLink, &g_PersistFile);
  2448. g_ShellLink = NULL;
  2449. g_PersistFile = NULL;
  2450. }
  2451. if (lnkNative) {
  2452. IsmReleaseMemory (lnkNative);
  2453. lnkNative = NULL;
  2454. }
  2455. }
  2456. return result;
  2457. }
  2458. BOOL
  2459. WINAPI
  2460. LnkMigOpmInitialize (
  2461. IN PMIG_LOGCALLBACK LogCallback,
  2462. IN PVOID Reserved
  2463. )
  2464. {
  2465. LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
  2466. g_LnkMigAttr_Shortcut = IsmRegisterAttribute (S_LNKMIGATTR_SHORTCUT, FALSE);
  2467. g_CopyIfRelevantAttr = IsmRegisterAttribute (S_ATTRIBUTE_COPYIFRELEVANT, FALSE);
  2468. g_OsFileAttribute = IsmRegisterAttribute (S_ATTRIBUTE_OSFILE, FALSE);
  2469. g_LnkMigProp_Target = IsmRegisterProperty (S_LNKMIGPROP_TARGET, FALSE);
  2470. g_LnkMigProp_Params = IsmRegisterProperty (S_LNKMIGPROP_PARAMS, FALSE);
  2471. g_LnkMigProp_WorkDir = IsmRegisterProperty (S_LNKMIGPROP_WORKDIR, FALSE);
  2472. g_LnkMigProp_IconPath = IsmRegisterProperty (S_LNKMIGPROP_ICONPATH, FALSE);
  2473. g_LnkMigProp_IconNumber = IsmRegisterProperty (S_LNKMIGPROP_ICONNUMBER, FALSE);
  2474. g_LnkMigProp_IconData = IsmRegisterProperty (S_LNKMIGPROP_ICONDATA, FALSE);
  2475. g_LnkMigProp_HotKey = IsmRegisterProperty (S_LNKMIGPROP_HOTKEY, FALSE);
  2476. g_LnkMigProp_DosApp = IsmRegisterProperty (S_LNKMIGPROP_DOSAPP, FALSE);
  2477. g_LnkMigProp_MsDosMode = IsmRegisterProperty (S_LNKMIGPROP_MSDOSMODE, FALSE);
  2478. g_LnkMigProp_ExtraData = IsmRegisterProperty (S_LNKMIGPROP_EXTRADATA, FALSE);
  2479. g_LnkMigOp_FixContent = IsmRegisterOperation (S_OPERATION_LNKMIG_FIXCONTENT, FALSE);
  2480. IsmRegisterRestoreCallback (LinkRestoreCallback);
  2481. IsmRegisterCompareCallback (MIG_FILE_TYPE, LinkDoesContentMatch);
  2482. IsmRegisterOperationApplyCallback (g_LnkMigOp_FixContent, DoLnkContentFix, TRUE);
  2483. return TRUE;
  2484. }