Source code of Windows XP (NT5)
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.

1044 lines
39 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_IconPath = 0;
  46. MIG_PROPERTYID g_LnkMigProp_IconNumber = 0;
  47. MIG_PROPERTYID g_LnkMigProp_IconData = 0;
  48. MIG_PROPERTYID g_LnkMigProp_HotKey = 0;
  49. MIG_PROPERTYID g_LnkMigProp_DosApp = 0;
  50. MIG_PROPERTYID g_LnkMigProp_MsDosMode = 0;
  51. MIG_PROPERTYID g_LnkMigProp_ExtraData = 0;
  52. MIG_OPERATIONID g_LnkMigOp_FixContent;
  53. IShellLink *g_ShellLink = NULL;
  54. IPersistFile *g_PersistFile = NULL;
  55. BOOL g_VcmMode = FALSE;
  56. //
  57. // Macro expansion list
  58. //
  59. // None
  60. //
  61. // Private function prototypes
  62. //
  63. // None
  64. //
  65. // Macro expansion definition
  66. //
  67. // None
  68. //
  69. // Private prototypes
  70. //
  71. MIG_OBJECTENUMCALLBACK LinksCallback;
  72. MIG_PREENUMCALLBACK LnkMigPreEnumeration;
  73. MIG_POSTENUMCALLBACK LnkMigPostEnumeration;
  74. OPMAPPLYCALLBACK DoLnkContentFix;
  75. MIG_RESTORECALLBACK LinkRestoreCallback;
  76. //
  77. // Code
  78. //
  79. BOOL
  80. pIsUncPath (
  81. IN PCTSTR Path
  82. )
  83. {
  84. return (Path && (Path[0] == TEXT('\\')) && (Path[1] == TEXT('\\')));
  85. }
  86. BOOL
  87. LinksInitialize (
  88. VOID
  89. )
  90. {
  91. g_LinksPool = PmCreateNamedPool ("Links");
  92. return (g_LinksPool != NULL);
  93. }
  94. VOID
  95. LinksTerminate (
  96. VOID
  97. )
  98. {
  99. if (g_LinksPool) {
  100. PmDestroyPool (g_LinksPool);
  101. g_LinksPool = NULL;
  102. }
  103. }
  104. BOOL
  105. pCommonInitialize (
  106. IN PMIG_LOGCALLBACK LogCallback
  107. )
  108. {
  109. LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
  110. g_LnkMigAttr_Shortcut = IsmRegisterAttribute (S_LNKMIGATTR_SHORTCUT, FALSE);
  111. g_CopyIfRelevantAttr = IsmRegisterAttribute (S_ATTRIBUTE_COPYIFRELEVANT, FALSE);
  112. g_LnkMigProp_Target = IsmRegisterProperty (S_LNKMIGPROP_TARGET, FALSE);
  113. g_LnkMigProp_Params = IsmRegisterProperty (S_LNKMIGPROP_PARAMS, FALSE);
  114. g_LnkMigProp_WorkDir = IsmRegisterProperty (S_LNKMIGPROP_WORKDIR, FALSE);
  115. g_LnkMigProp_IconPath = IsmRegisterProperty (S_LNKMIGPROP_ICONPATH, FALSE);
  116. g_LnkMigProp_IconNumber = IsmRegisterProperty (S_LNKMIGPROP_ICONNUMBER, FALSE);
  117. g_LnkMigProp_IconData = IsmRegisterProperty (S_LNKMIGPROP_ICONDATA, FALSE);
  118. g_LnkMigProp_HotKey = IsmRegisterProperty (S_LNKMIGPROP_HOTKEY, FALSE);
  119. g_LnkMigProp_DosApp = IsmRegisterProperty (S_LNKMIGPROP_DOSAPP, FALSE);
  120. g_LnkMigProp_MsDosMode = IsmRegisterProperty (S_LNKMIGPROP_MSDOSMODE, FALSE);
  121. g_LnkMigProp_ExtraData = IsmRegisterProperty (S_LNKMIGPROP_EXTRADATA, FALSE);
  122. g_LnkMigOp_FixContent = IsmRegisterOperation (S_OPERATION_LNKMIG_FIXCONTENT, FALSE);
  123. return TRUE;
  124. }
  125. BOOL
  126. WINAPI
  127. LnkMigVcmInitialize (
  128. IN PMIG_LOGCALLBACK LogCallback,
  129. IN PVOID Reserved
  130. )
  131. {
  132. g_VcmMode = TRUE;
  133. return pCommonInitialize (LogCallback);
  134. }
  135. BOOL
  136. WINAPI
  137. LnkMigSgmInitialize (
  138. IN PMIG_LOGCALLBACK LogCallback,
  139. IN PVOID Reserved
  140. )
  141. {
  142. return pCommonInitialize (LogCallback);
  143. }
  144. BOOL
  145. LnkMigPreEnumeration (
  146. VOID
  147. )
  148. {
  149. if (!InitCOMLink (&g_ShellLink, &g_PersistFile)) {
  150. DEBUGMSG ((DBG_ERROR, "Error initializing COM %d", GetLastError ()));
  151. }
  152. return TRUE;
  153. }
  154. BOOL
  155. LnkMigPostEnumeration (
  156. VOID
  157. )
  158. {
  159. FreeCOMLink (&g_ShellLink, &g_PersistFile);
  160. g_ShellLink = NULL;
  161. g_PersistFile = NULL;
  162. return TRUE;
  163. }
  164. ENCODEDSTRHANDLE
  165. pBuildEncodedNameFromNativeName (
  166. IN PCTSTR NativeName
  167. )
  168. {
  169. PCTSTR nodeName;
  170. PTSTR leafName;
  171. ENCODEDSTRHANDLE result;
  172. MIG_OBJECT_ENUM objEnum;
  173. result = IsmCreateObjectHandle (NativeName, NULL);
  174. if (result) {
  175. if (IsmEnumFirstSourceObject (&objEnum, MIG_FILE_TYPE | PLATFORM_SOURCE, result)) {
  176. IsmAbortObjectEnum (&objEnum);
  177. return result;
  178. }
  179. IsmDestroyObjectHandle (result);
  180. }
  181. // we have to split this path because it could be a file
  182. nodeName = DuplicatePathString (NativeName, 0);
  183. leafName = _tcsrchr (nodeName, TEXT('\\'));
  184. if (leafName) {
  185. *leafName = 0;
  186. leafName ++;
  187. }
  188. result = IsmCreateObjectHandle (nodeName, leafName);
  189. FreePathString (nodeName);
  190. return result;
  191. }
  192. PCTSTR
  193. pSpecialExpandEnvironmentString (
  194. IN PCTSTR SrcString,
  195. IN PCTSTR Context
  196. )
  197. {
  198. PCTSTR result = NULL;
  199. PCTSTR srcWinDir = NULL;
  200. PCTSTR destWinDir = NULL;
  201. PTSTR newSrcString = NULL;
  202. PCTSTR copyPtr = NULL;
  203. if (IsmGetRealPlatform () == PLATFORM_DESTINATION) {
  204. // Special case where this is actually the destination machine and
  205. // first part of SrcString matches %windir%. In this case, it is likely that
  206. // the shell replaced the source windows directory with the destination one.
  207. // We need to change it back
  208. destWinDir = IsmExpandEnvironmentString (PLATFORM_DESTINATION, S_SYSENVVAR_GROUP, TEXT ("%windir%"), NULL);
  209. if (destWinDir) {
  210. if (StringIPrefix (SrcString, destWinDir)) {
  211. srcWinDir = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT ("%windir%"), NULL);
  212. if (srcWinDir) {
  213. newSrcString = IsmGetMemory (SizeOfString (srcWinDir) + SizeOfString (SrcString));
  214. if (newSrcString) {
  215. copyPtr = SrcString + TcharCount (destWinDir);
  216. StringCopy (newSrcString, srcWinDir);
  217. StringCat (newSrcString, copyPtr);
  218. }
  219. IsmReleaseMemory (srcWinDir);
  220. srcWinDir = NULL;
  221. }
  222. }
  223. IsmReleaseMemory (destWinDir);
  224. destWinDir = NULL;
  225. }
  226. }
  227. result = IsmExpandEnvironmentString (
  228. PLATFORM_SOURCE,
  229. S_SYSENVVAR_GROUP,
  230. newSrcString?newSrcString:SrcString,
  231. Context
  232. );
  233. if (newSrcString) {
  234. IsmReleaseMemory (newSrcString);
  235. }
  236. return result;
  237. }
  238. UINT
  239. LinksCallback (
  240. IN PCMIG_OBJECTENUMDATA Data,
  241. IN ULONG_PTR CallerArg
  242. )
  243. {
  244. MIG_OBJECTID objectId;
  245. BOOL extractResult = FALSE;
  246. PCTSTR lnkTarget;
  247. PCTSTR lnkParams;
  248. PCTSTR lnkWorkDir;
  249. PCTSTR lnkIconPath;
  250. INT lnkIconNumber;
  251. WORD lnkHotKey;
  252. BOOL lnkDosApp;
  253. BOOL lnkMsDosMode;
  254. LNK_EXTRA_DATA lnkExtraData;
  255. ENCODEDSTRHANDLE encodedName;
  256. MIG_BLOB migBlob;
  257. PCTSTR expTmpStr;
  258. PCTSTR longTmpStr;
  259. MIG_CONTENT lnkContent;
  260. MIG_CONTENT lnkIconContent;
  261. PICON_GROUP iconGroup = NULL;
  262. ICON_SGROUP iconSGroup;
  263. PCTSTR lnkIconResId = NULL;
  264. if (Data->IsLeaf) {
  265. objectId = IsmGetObjectIdFromName (MIG_FILE_TYPE, Data->ObjectName, TRUE);
  266. if (IsmIsPersistentObjectId (objectId)) {
  267. IsmSetAttributeOnObjectId (objectId, g_LnkMigAttr_Shortcut);
  268. if (IsmAcquireObjectEx (
  269. Data->ObjectTypeId,
  270. Data->ObjectName,
  271. &lnkContent,
  272. CONTENTTYPE_FILE,
  273. 0
  274. )) {
  275. if (lnkContent.ContentInFile && lnkContent.FileContent.ContentPath) {
  276. if (ExtractShortcutInfo (
  277. lnkContent.FileContent.ContentPath,
  278. &lnkTarget,
  279. &lnkParams,
  280. &lnkWorkDir,
  281. &lnkIconPath,
  282. &lnkIconNumber,
  283. &lnkHotKey,
  284. &lnkDosApp,
  285. &lnkMsDosMode,
  286. &lnkExtraData,
  287. g_ShellLink,
  288. g_PersistFile
  289. )) {
  290. // let's get all the paths through the hooks and add everything as properties of this shortcut
  291. if (lnkTarget) {
  292. if (*lnkTarget) {
  293. expTmpStr = pSpecialExpandEnvironmentString (lnkTarget, Data->NativeObjectName);
  294. longTmpStr = BfGetLongFileName (expTmpStr);
  295. encodedName = pBuildEncodedNameFromNativeName (longTmpStr);
  296. IsmExecuteHooks (MIG_FILE_TYPE, encodedName);
  297. if (!g_VcmMode) {
  298. migBlob.Type = BLOBTYPE_STRING;
  299. migBlob.String = encodedName;
  300. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_Target, &migBlob);
  301. } else {
  302. // persist the target so we can examine it later
  303. if (!IsmIsPersistentObject (MIG_FILE_TYPE, encodedName)) {
  304. IsmMakePersistentObject (MIG_FILE_TYPE, encodedName);
  305. IsmMakeNonCriticalObject (MIG_FILE_TYPE, encodedName);
  306. }
  307. }
  308. if (encodedName) {
  309. IsmDestroyObjectHandle (encodedName);
  310. }
  311. FreePathString (longTmpStr);
  312. IsmReleaseMemory (expTmpStr);
  313. } else {
  314. if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
  315. IsmClearPersistenceOnObjectId (objectId);
  316. }
  317. }
  318. FreePathString (lnkTarget);
  319. } else {
  320. if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
  321. IsmClearPersistenceOnObjectId (objectId);
  322. }
  323. }
  324. if (lnkParams) {
  325. if (*lnkParams) {
  326. if (!g_VcmMode) {
  327. migBlob.Type = BLOBTYPE_STRING;
  328. migBlob.String = lnkParams;
  329. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_Params, &migBlob);
  330. }
  331. }
  332. FreePathString (lnkParams);
  333. }
  334. if (lnkWorkDir) {
  335. if (*lnkWorkDir) {
  336. expTmpStr = pSpecialExpandEnvironmentString (lnkWorkDir, Data->NativeObjectName);
  337. longTmpStr = BfGetLongFileName (expTmpStr);
  338. encodedName = pBuildEncodedNameFromNativeName (longTmpStr);
  339. IsmExecuteHooks (MIG_FILE_TYPE, encodedName);
  340. if (!g_VcmMode) {
  341. migBlob.Type = BLOBTYPE_STRING;
  342. migBlob.String = encodedName;
  343. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_WorkDir, &migBlob);
  344. } else {
  345. // persist the working directory (it has almost no space impact)
  346. // so we can examine it later
  347. if (!IsmIsPersistentObject (MIG_FILE_TYPE, encodedName)) {
  348. IsmMakePersistentObject (MIG_FILE_TYPE, encodedName);
  349. IsmMakeNonCriticalObject (MIG_FILE_TYPE, encodedName);
  350. }
  351. }
  352. if (encodedName) {
  353. IsmDestroyObjectHandle (encodedName);
  354. }
  355. FreePathString (longTmpStr);
  356. IsmReleaseMemory (expTmpStr);
  357. }
  358. FreePathString (lnkWorkDir);
  359. }
  360. if (lnkIconPath) {
  361. if (*lnkIconPath) {
  362. expTmpStr = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, lnkIconPath, Data->NativeObjectName);
  363. longTmpStr = BfGetLongFileName (expTmpStr);
  364. encodedName = pBuildEncodedNameFromNativeName (longTmpStr);
  365. IsmExecuteHooks (MIG_FILE_TYPE, encodedName);
  366. if (!g_VcmMode) {
  367. migBlob.Type = BLOBTYPE_STRING;
  368. migBlob.String = encodedName;
  369. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconPath, &migBlob);
  370. // one last thing: let's extract the icon and preserve it just in case.
  371. if (IsmAcquireObjectEx (
  372. MIG_FILE_TYPE,
  373. encodedName,
  374. &lnkIconContent,
  375. CONTENTTYPE_FILE,
  376. 0
  377. )) {
  378. if (lnkIconContent.ContentInFile && lnkIconContent.FileContent.ContentPath) {
  379. if (lnkIconNumber >= 0) {
  380. iconGroup = IcoExtractIconGroupByIndexFromFile (
  381. lnkIconContent.FileContent.ContentPath,
  382. lnkIconNumber,
  383. NULL
  384. );
  385. } else {
  386. lnkIconResId = (PCTSTR) (LONG_PTR) (-lnkIconNumber);
  387. iconGroup = IcoExtractIconGroupFromFile (
  388. lnkIconContent.FileContent.ContentPath,
  389. lnkIconResId,
  390. NULL
  391. );
  392. }
  393. if (iconGroup) {
  394. if (IcoSerializeIconGroup (iconGroup, &iconSGroup)) {
  395. migBlob.Type = BLOBTYPE_BINARY;
  396. migBlob.BinaryData = (PCBYTE)(iconSGroup.Data);
  397. migBlob.BinarySize = iconSGroup.DataSize;
  398. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconData, &migBlob);
  399. IcoReleaseIconSGroup (&iconSGroup);
  400. }
  401. IcoReleaseIconGroup (iconGroup);
  402. }
  403. }
  404. IsmReleaseObject (&lnkIconContent);
  405. }
  406. } else {
  407. // persist the icon file so we can examine it later
  408. if (!pIsUncPath (longTmpStr)) {
  409. if (!IsmIsPersistentObject (MIG_FILE_TYPE, encodedName)) {
  410. IsmMakePersistentObject (MIG_FILE_TYPE, encodedName);
  411. IsmMakeNonCriticalObject (MIG_FILE_TYPE, encodedName);
  412. }
  413. }
  414. }
  415. if (encodedName) {
  416. IsmDestroyObjectHandle (encodedName);
  417. }
  418. FreePathString (longTmpStr);
  419. IsmReleaseMemory (expTmpStr);
  420. }
  421. FreePathString (lnkIconPath);
  422. }
  423. if (!g_VcmMode) {
  424. migBlob.Type = BLOBTYPE_BINARY;
  425. migBlob.BinaryData = (PCBYTE)(&lnkIconNumber);
  426. migBlob.BinarySize = sizeof (INT);
  427. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_IconNumber, &migBlob);
  428. migBlob.Type = BLOBTYPE_BINARY;
  429. migBlob.BinaryData = (PCBYTE)(&lnkDosApp);
  430. migBlob.BinarySize = sizeof (BOOL);
  431. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_DosApp, &migBlob);
  432. if (lnkDosApp) {
  433. migBlob.Type = BLOBTYPE_BINARY;
  434. migBlob.BinaryData = (PCBYTE)(&lnkMsDosMode);
  435. migBlob.BinarySize = sizeof (BOOL);
  436. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_MsDosMode, &migBlob);
  437. migBlob.Type = BLOBTYPE_BINARY;
  438. migBlob.BinaryData = (PCBYTE)(&lnkExtraData);
  439. migBlob.BinarySize = sizeof (LNK_EXTRA_DATA);
  440. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_ExtraData, &migBlob);
  441. } else {
  442. migBlob.Type = BLOBTYPE_BINARY;
  443. migBlob.BinaryData = (PCBYTE)(&lnkHotKey);
  444. migBlob.BinarySize = sizeof (WORD);
  445. IsmAddPropertyToObjectId (objectId, g_LnkMigProp_HotKey, &migBlob);
  446. }
  447. IsmSetOperationOnObjectId (
  448. objectId,
  449. g_LnkMigOp_FixContent,
  450. NULL,
  451. NULL
  452. );
  453. }
  454. } else {
  455. if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
  456. IsmClearPersistenceOnObjectId (objectId);
  457. }
  458. }
  459. } else {
  460. if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
  461. IsmClearPersistenceOnObjectId (objectId);
  462. }
  463. }
  464. IsmReleaseObject (&lnkContent);
  465. } else {
  466. if (IsmIsAttributeSetOnObjectId (objectId, g_CopyIfRelevantAttr)) {
  467. IsmClearPersistenceOnObjectId (objectId);
  468. }
  469. }
  470. }
  471. }
  472. return CALLBACK_ENUM_CONTINUE;
  473. }
  474. BOOL
  475. pCommonLnkMigQueueEnumeration (
  476. VOID
  477. )
  478. {
  479. ENCODEDSTRHANDLE pattern;
  480. // hook all LNK files
  481. pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, TEXT("*.lnk"), TRUE);
  482. if (pattern) {
  483. IsmHookEnumeration (MIG_FILE_TYPE, pattern, LinksCallback, (ULONG_PTR) 0, TEXT("Links.Files"));
  484. IsmDestroyObjectHandle (pattern);
  485. }
  486. // hook all PIF files
  487. pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, TEXT("*.pif"), TRUE);
  488. if (pattern) {
  489. IsmHookEnumeration (MIG_FILE_TYPE, pattern, LinksCallback, (ULONG_PTR) 0, TEXT("Links.Files"));
  490. IsmDestroyObjectHandle (pattern);
  491. }
  492. IsmRegisterPreEnumerationCallback (LnkMigPreEnumeration, NULL);
  493. IsmRegisterPostEnumerationCallback (LnkMigPostEnumeration, NULL);
  494. return TRUE;
  495. }
  496. BOOL
  497. WINAPI
  498. LnkMigVcmQueueEnumeration (
  499. IN PVOID Reserved
  500. )
  501. {
  502. return pCommonLnkMigQueueEnumeration ();
  503. }
  504. BOOL
  505. WINAPI
  506. LnkMigSgmQueueEnumeration (
  507. IN PVOID Reserved
  508. )
  509. {
  510. return pCommonLnkMigQueueEnumeration ();
  511. }
  512. BOOL
  513. WINAPI
  514. DoLnkContentFix (
  515. IN MIG_OBJECTTYPEID SrcObjectTypeId,
  516. IN MIG_OBJECTSTRINGHANDLE SrcObjectName,
  517. IN PCMIG_CONTENT OriginalContent,
  518. IN PCMIG_CONTENT CurrentContent,
  519. OUT PMIG_CONTENT NewContent,
  520. IN PCMIG_BLOB SourceOperationData, OPTIONAL
  521. IN PCMIG_BLOB DestinationOperationData OPTIONAL
  522. )
  523. {
  524. MIG_PROPERTYDATAID propDataId;
  525. MIG_BLOBTYPE propDataType;
  526. UINT requiredSize;
  527. BOOL lnkTargetPresent = FALSE;
  528. PCTSTR lnkTargetNode = NULL;
  529. PCTSTR lnkTargetLeaf = NULL;
  530. PCTSTR objectNode = NULL;
  531. PCTSTR objectLeaf = NULL;
  532. MIG_OBJECTSTRINGHANDLE lnkTarget = NULL;
  533. MIG_OBJECTTYPEID lnkTargetDestType = 0;
  534. MIG_OBJECTSTRINGHANDLE lnkTargetDest = NULL;
  535. BOOL lnkTargetDestDel = FALSE;
  536. BOOL lnkTargetDestRepl = FALSE;
  537. PCTSTR lnkTargetDestNative = NULL;
  538. PCTSTR lnkParams = NULL;
  539. MIG_OBJECTSTRINGHANDLE lnkWorkDir = NULL;
  540. MIG_OBJECTTYPEID lnkWorkDirDestType = 0;
  541. MIG_OBJECTSTRINGHANDLE lnkWorkDirDest = NULL;
  542. BOOL lnkWorkDirDestDel = FALSE;
  543. BOOL lnkWorkDirDestRepl = FALSE;
  544. PCTSTR lnkWorkDirDestNative = NULL;
  545. MIG_OBJECTSTRINGHANDLE lnkIconPath = NULL;
  546. MIG_OBJECTTYPEID lnkIconPathDestType = 0;
  547. MIG_OBJECTSTRINGHANDLE lnkIconPathDest = NULL;
  548. BOOL lnkIconPathDestDel = FALSE;
  549. BOOL lnkIconPathDestRepl = FALSE;
  550. PCTSTR lnkIconPathDestNative = NULL;
  551. INT lnkIconNumber = 0;
  552. PICON_GROUP lnkIconGroup = NULL;
  553. ICON_SGROUP lnkIconSGroup = {0, NULL};
  554. WORD lnkHotKey = 0;
  555. BOOL lnkDosApp = FALSE;
  556. BOOL lnkMsDosMode = FALSE;
  557. PLNK_EXTRA_DATA lnkExtraData = NULL;
  558. BOOL comInit = FALSE;
  559. BOOL modifyFile = FALSE;
  560. PTSTR iconLibPath = NULL;
  561. // now it's finally time to fix the LNK file content
  562. if ((g_ShellLink == NULL) || (g_PersistFile == NULL)) {
  563. comInit = TRUE;
  564. if (!InitCOMLink (&g_ShellLink, &g_PersistFile)) {
  565. DEBUGMSG ((DBG_ERROR, "Error initializing COM %d", GetLastError ()));
  566. return TRUE;
  567. }
  568. }
  569. // first, retrieve the properties
  570. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_Target);
  571. if (propDataId) {
  572. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  573. lnkTarget = PmGetMemory (g_LinksPool, requiredSize);
  574. IsmGetPropertyData (propDataId, (PBYTE)lnkTarget, requiredSize, NULL, &propDataType);
  575. }
  576. }
  577. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_Params);
  578. if (propDataId) {
  579. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  580. lnkParams = PmGetMemory (g_LinksPool, requiredSize);
  581. IsmGetPropertyData (propDataId, (PBYTE)lnkParams, requiredSize, NULL, &propDataType);
  582. }
  583. }
  584. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_WorkDir);
  585. if (propDataId) {
  586. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  587. lnkWorkDir = PmGetMemory (g_LinksPool, requiredSize);
  588. IsmGetPropertyData (propDataId, (PBYTE)lnkWorkDir, requiredSize, NULL, &propDataType);
  589. }
  590. }
  591. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconPath);
  592. if (propDataId) {
  593. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  594. lnkIconPath = PmGetMemory (g_LinksPool, requiredSize);
  595. IsmGetPropertyData (propDataId, (PBYTE)lnkIconPath, requiredSize, NULL, &propDataType);
  596. }
  597. }
  598. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconNumber);
  599. if (propDataId) {
  600. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  601. if (requiredSize == sizeof (INT)) {
  602. IsmGetPropertyData (propDataId, (PBYTE)(&lnkIconNumber), requiredSize, NULL, &propDataType);
  603. }
  604. }
  605. }
  606. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_IconData);
  607. if (propDataId) {
  608. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  609. lnkIconSGroup.DataSize = requiredSize;
  610. lnkIconSGroup.Data = PmGetMemory (g_LinksPool, requiredSize);
  611. IsmGetPropertyData (propDataId, (PBYTE)lnkIconSGroup.Data, requiredSize, NULL, &propDataType);
  612. }
  613. }
  614. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_HotKey);
  615. if (propDataId) {
  616. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  617. if (requiredSize == sizeof (WORD)) {
  618. IsmGetPropertyData (propDataId, (PBYTE)(&lnkHotKey), requiredSize, NULL, &propDataType);
  619. }
  620. }
  621. }
  622. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_DosApp);
  623. if (propDataId) {
  624. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  625. if (requiredSize == sizeof (BOOL)) {
  626. IsmGetPropertyData (propDataId, (PBYTE)(&lnkDosApp), requiredSize, NULL, &propDataType);
  627. }
  628. }
  629. }
  630. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_MsDosMode);
  631. if (propDataId) {
  632. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  633. if (requiredSize == sizeof (BOOL)) {
  634. IsmGetPropertyData (propDataId, (PBYTE)(&lnkMsDosMode), requiredSize, NULL, &propDataType);
  635. }
  636. }
  637. }
  638. propDataId = IsmGetPropertyFromObject (SrcObjectTypeId, SrcObjectName, g_LnkMigProp_ExtraData);
  639. if (propDataId) {
  640. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  641. lnkExtraData = PmGetMemory (g_LinksPool, requiredSize);
  642. IsmGetPropertyData (propDataId, (PBYTE)lnkExtraData, requiredSize, NULL, &propDataType);
  643. }
  644. }
  645. // let's examine the target, see if it was migrated
  646. if (lnkTarget) {
  647. lnkTargetDest = IsmFilterObject (
  648. MIG_FILE_TYPE | PLATFORM_SOURCE,
  649. lnkTarget,
  650. &lnkTargetDestType,
  651. &lnkTargetDestDel,
  652. &lnkTargetDestRepl
  653. );
  654. if (((lnkTargetDestDel == FALSE) || (lnkTargetDestRepl == TRUE)) &&
  655. ((lnkTargetDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE)
  656. ) {
  657. if (lnkTargetDest) {
  658. // the target changed location, we need to adjust the link
  659. modifyFile = TRUE;
  660. lnkTargetDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkTargetDest);
  661. }
  662. }
  663. lnkTargetPresent = !lnkTargetDestDel;
  664. }
  665. // let's examine the working directory
  666. if (lnkWorkDir) {
  667. lnkWorkDirDest = IsmFilterObject (
  668. MIG_FILE_TYPE | PLATFORM_SOURCE,
  669. lnkWorkDir,
  670. &lnkWorkDirDestType,
  671. &lnkWorkDirDestDel,
  672. &lnkWorkDirDestRepl
  673. );
  674. if (((lnkWorkDirDestDel == FALSE) || (lnkWorkDirDestRepl == TRUE)) &&
  675. ((lnkWorkDirDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE)
  676. ) {
  677. if (lnkWorkDirDest) {
  678. // the working directory changed location, we need to adjust the link
  679. modifyFile = TRUE;
  680. lnkWorkDirDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkWorkDirDest);
  681. }
  682. } else {
  683. // seems like the working directory is gone. If the target is still present, we will adjust
  684. // the working directory to point where the target is located
  685. if (lnkTargetPresent) {
  686. if (IsmCreateObjectStringsFromHandle (lnkTargetDest?lnkTargetDest:lnkTarget, &lnkTargetNode, &lnkTargetLeaf)) {
  687. lnkWorkDirDest = IsmCreateObjectHandle (lnkTargetNode, NULL);
  688. if (lnkWorkDirDest) {
  689. modifyFile = TRUE;
  690. lnkWorkDirDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkWorkDirDest);
  691. }
  692. IsmDestroyObjectString (lnkTargetNode);
  693. IsmDestroyObjectString (lnkTargetLeaf);
  694. }
  695. }
  696. }
  697. }
  698. // let's examine the icon path
  699. if (lnkIconPath) {
  700. lnkIconPathDest = IsmFilterObject (
  701. MIG_FILE_TYPE | PLATFORM_SOURCE,
  702. lnkIconPath,
  703. &lnkIconPathDestType,
  704. &lnkIconPathDestDel,
  705. &lnkIconPathDestRepl
  706. );
  707. if (((lnkIconPathDestDel == FALSE) || (lnkIconPathDestRepl == TRUE)) &&
  708. ((lnkIconPathDestType & (~PLATFORM_MASK)) == MIG_FILE_TYPE)
  709. ) {
  710. if (lnkIconPathDest) {
  711. // the icon path changed location, we need to adjust the link
  712. modifyFile = TRUE;
  713. lnkIconPathDestNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkIconPathDest);
  714. }
  715. } else {
  716. if (!pIsUncPath (lnkIconPath)) {
  717. // seems like the icon path is gone. If the we have the icon extracted we will try to add it to the
  718. // icon library and adjust this link to point there.
  719. if (lnkIconSGroup.DataSize) {
  720. lnkIconGroup = IcoDeSerializeIconGroup (&lnkIconSGroup);
  721. if (lnkIconGroup) {
  722. if (IsmGetEnvironmentString (
  723. PLATFORM_DESTINATION,
  724. NULL,
  725. S_ENV_ICONLIB,
  726. NULL,
  727. 0,
  728. &requiredSize
  729. )) {
  730. iconLibPath = PmGetMemory (g_LinksPool, requiredSize);
  731. if (IsmGetEnvironmentString (
  732. PLATFORM_DESTINATION,
  733. NULL,
  734. S_ENV_ICONLIB,
  735. iconLibPath,
  736. requiredSize,
  737. NULL
  738. )) {
  739. if (IcoWriteIconGroupToPeFile (iconLibPath, lnkIconGroup, NULL, &lnkIconNumber)) {
  740. modifyFile = TRUE;
  741. lnkIconPathDestNative = IsmGetMemory (SizeOfString (iconLibPath));
  742. StringCopy ((PTSTR)lnkIconPathDestNative, iconLibPath);
  743. IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_ENV_SAVE_ICONLIB);
  744. }
  745. }
  746. PmReleaseMemory (g_LinksPool, iconLibPath);
  747. }
  748. IcoReleaseIconGroup (lnkIconGroup);
  749. }
  750. }
  751. }
  752. }
  753. }
  754. if (modifyFile) {
  755. if (CurrentContent->ContentInFile) {
  756. if (IsmCreateObjectStringsFromHandle (SrcObjectName, &objectNode, &objectLeaf)) {
  757. if (ModifyShortcutFileEx (
  758. (PCTSTR) CurrentContent->FileContent.ContentPath,
  759. GetFileExtensionFromPath (objectLeaf),
  760. lnkTargetDestNative,
  761. NULL,
  762. lnkWorkDirDestNative,
  763. lnkIconPathDestNative,
  764. lnkIconNumber,
  765. lnkHotKey,
  766. NULL,
  767. g_ShellLink,
  768. g_PersistFile
  769. )) {
  770. NewContent->FileContent.ContentPath = CurrentContent->FileContent.ContentPath;
  771. }
  772. IsmDestroyObjectString (objectNode);
  773. IsmDestroyObjectString (objectLeaf);
  774. }
  775. } else {
  776. // something is wrong, the content of this shortcut should be in a file
  777. MYASSERT (FALSE);
  778. }
  779. }
  780. if (lnkIconPathDestNative) {
  781. IsmReleaseMemory (lnkIconPathDestNative);
  782. lnkIconPathDestNative = NULL;
  783. }
  784. if (lnkWorkDirDestNative) {
  785. IsmReleaseMemory (lnkWorkDirDestNative);
  786. lnkWorkDirDestNative = NULL;
  787. }
  788. if (lnkTargetDestNative) {
  789. IsmReleaseMemory (lnkTargetDestNative);
  790. lnkTargetDestNative = NULL;
  791. }
  792. if (lnkIconPathDest) {
  793. IsmDestroyObjectHandle (lnkIconPathDest);
  794. lnkIconPathDest = NULL;
  795. }
  796. if (lnkWorkDirDest) {
  797. IsmDestroyObjectHandle (lnkWorkDirDest);
  798. lnkWorkDirDest = NULL;
  799. }
  800. if (lnkTargetDest) {
  801. IsmDestroyObjectHandle (lnkTargetDest);
  802. lnkTargetDest = NULL;
  803. }
  804. if (lnkExtraData) {
  805. PmReleaseMemory (g_LinksPool, lnkExtraData);
  806. lnkExtraData = NULL;
  807. }
  808. if (lnkIconSGroup.DataSize && lnkIconSGroup.Data) {
  809. PmReleaseMemory (g_LinksPool, lnkIconSGroup.Data);
  810. lnkIconSGroup.DataSize = 0;
  811. lnkIconSGroup.Data = NULL;
  812. }
  813. if (lnkIconPath) {
  814. PmReleaseMemory (g_LinksPool, lnkIconPath);
  815. lnkIconPath = NULL;
  816. }
  817. if (lnkWorkDir) {
  818. PmReleaseMemory (g_LinksPool, lnkWorkDir);
  819. lnkWorkDir = NULL;
  820. }
  821. if (lnkParams) {
  822. PmReleaseMemory (g_LinksPool, lnkParams);
  823. lnkParams = NULL;
  824. }
  825. if (lnkTarget) {
  826. PmReleaseMemory (g_LinksPool, lnkTarget);
  827. lnkTarget = NULL;
  828. }
  829. if (comInit) {
  830. FreeCOMLink (&g_ShellLink, &g_PersistFile);
  831. g_ShellLink = NULL;
  832. g_PersistFile = NULL;
  833. }
  834. return TRUE;
  835. }
  836. BOOL
  837. LinkRestoreCallback (
  838. IN MIG_OBJECTTYPEID ObjectTypeId,
  839. IN MIG_OBJECTID ObjectId,
  840. IN MIG_OBJECTSTRINGHANDLE ObjectName
  841. )
  842. {
  843. MIG_PROPERTYDATAID propDataId;
  844. MIG_BLOBTYPE propDataType;
  845. UINT requiredSize;
  846. MIG_OBJECTSTRINGHANDLE lnkTarget = NULL;
  847. MIG_OBJECTTYPEID lnkTargetDestType = 0;
  848. MIG_OBJECTSTRINGHANDLE lnkTargetDest = NULL;
  849. BOOL lnkTargetDestDel = FALSE;
  850. BOOL lnkTargetDestRepl = FALSE;
  851. PCTSTR lnkTargetNative = NULL;
  852. PCTSTR objectNode = NULL;
  853. PCTSTR objectLeaf = NULL;
  854. PCTSTR extPtr = NULL;
  855. BOOL result = TRUE;
  856. if (IsmIsAttributeSetOnObjectId (ObjectId, g_CopyIfRelevantAttr)) {
  857. if (IsmCreateObjectStringsFromHandle (ObjectName, &objectNode, &objectLeaf)) {
  858. if (objectLeaf) {
  859. extPtr = GetFileExtensionFromPath (objectLeaf);
  860. if (extPtr &&
  861. (StringIMatch (extPtr, TEXT("LNK")) ||
  862. StringIMatch (extPtr, TEXT("PIF"))
  863. )
  864. ) {
  865. propDataId = IsmGetPropertyFromObject (ObjectTypeId, ObjectName, g_LnkMigProp_Target);
  866. if (propDataId) {
  867. if (IsmGetPropertyData (propDataId, NULL, 0, &requiredSize, &propDataType)) {
  868. lnkTarget = PmGetMemory (g_LinksPool, requiredSize);
  869. IsmGetPropertyData (propDataId, (PBYTE)lnkTarget, requiredSize, NULL, &propDataType);
  870. if (IsmIsAttributeSetOnObject (MIG_FILE_TYPE | PLATFORM_SOURCE, lnkTarget, g_OsFileAttribute)) {
  871. // NTRAID#NTBUG9-153265-2000/08/01-jimschm Need to migrate customized OS files links
  872. result = FALSE;
  873. } else {
  874. lnkTargetNative = IsmGetNativeObjectName (MIG_FILE_TYPE, lnkTarget);
  875. if (lnkTargetNative) {
  876. if (pIsUncPath (lnkTargetNative)) {
  877. result = TRUE;
  878. } else {
  879. lnkTargetDest = IsmFilterObject (
  880. MIG_FILE_TYPE | PLATFORM_SOURCE,
  881. lnkTarget,
  882. &lnkTargetDestType,
  883. &lnkTargetDestDel,
  884. &lnkTargetDestRepl
  885. );
  886. result = (lnkTargetDestDel == FALSE) || (lnkTargetDestRepl == TRUE);
  887. if (lnkTargetDest) {
  888. IsmDestroyObjectHandle (lnkTargetDest);
  889. }
  890. }
  891. IsmReleaseMemory (lnkTargetNative);
  892. } else {
  893. result = FALSE;
  894. }
  895. }
  896. PmReleaseMemory (g_LinksPool, lnkTarget);
  897. }
  898. }
  899. }
  900. }
  901. IsmDestroyObjectString (objectNode);
  902. IsmDestroyObjectString (objectLeaf);
  903. }
  904. }
  905. return result;
  906. }
  907. BOOL
  908. WINAPI
  909. LnkMigOpmInitialize (
  910. IN PMIG_LOGCALLBACK LogCallback,
  911. IN PVOID Reserved
  912. )
  913. {
  914. LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
  915. g_LnkMigAttr_Shortcut = IsmRegisterAttribute (S_LNKMIGATTR_SHORTCUT, FALSE);
  916. g_CopyIfRelevantAttr = IsmRegisterAttribute (S_ATTRIBUTE_COPYIFRELEVANT, FALSE);
  917. g_OsFileAttribute = IsmRegisterAttribute (S_ATTRIBUTE_OSFILE, FALSE);
  918. g_LnkMigProp_Target = IsmRegisterProperty (S_LNKMIGPROP_TARGET, FALSE);
  919. g_LnkMigProp_Params = IsmRegisterProperty (S_LNKMIGPROP_PARAMS, FALSE);
  920. g_LnkMigProp_WorkDir = IsmRegisterProperty (S_LNKMIGPROP_WORKDIR, FALSE);
  921. g_LnkMigProp_IconPath = IsmRegisterProperty (S_LNKMIGPROP_ICONPATH, FALSE);
  922. g_LnkMigProp_IconNumber = IsmRegisterProperty (S_LNKMIGPROP_ICONNUMBER, FALSE);
  923. g_LnkMigProp_IconData = IsmRegisterProperty (S_LNKMIGPROP_ICONDATA, FALSE);
  924. g_LnkMigProp_HotKey = IsmRegisterProperty (S_LNKMIGPROP_HOTKEY, FALSE);
  925. g_LnkMigProp_DosApp = IsmRegisterProperty (S_LNKMIGPROP_DOSAPP, FALSE);
  926. g_LnkMigProp_MsDosMode = IsmRegisterProperty (S_LNKMIGPROP_MSDOSMODE, FALSE);
  927. g_LnkMigProp_ExtraData = IsmRegisterProperty (S_LNKMIGPROP_EXTRADATA, FALSE);
  928. g_LnkMigOp_FixContent = IsmRegisterOperation (S_OPERATION_LNKMIG_FIXCONTENT, FALSE);
  929. IsmRegisterRestoreCallback (LinkRestoreCallback);
  930. IsmRegisterOperationApplyCallback (g_LnkMigOp_FixContent, DoLnkContentFix, TRUE);
  931. return TRUE;
  932. }