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.

1563 lines
49 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. links.c
  5. Abstract:
  6. This source file implements the Win95 side of LNK and PIF processing
  7. Author:
  8. Calin Negreanu (calinn) 09-Feb-1998
  9. Revision History:
  10. calinn 23-Sep-1998 Redesigned several pieces
  11. --*/
  12. #include "pch.h"
  13. #include "migdbp.h"
  14. #include "migappp.h"
  15. POOLHANDLE g_LinksPool = NULL;
  16. INT g_LinkStubSequencer = 0;
  17. typedef struct _LINK_STRUCT {
  18. PCTSTR ReportEntry;
  19. PCTSTR Category;
  20. PCTSTR Context;
  21. PCTSTR Object;
  22. PCTSTR LinkName;
  23. PCTSTR LinkNameNoPath;
  24. PMIGDB_CONTEXT MigDbContext;
  25. } LINK_STRUCT, *PLINK_STRUCT;
  26. BOOL
  27. InitLinkAnnounce (
  28. VOID
  29. )
  30. {
  31. //
  32. // Create PoolMem for keeping all structures during this phase
  33. //
  34. g_LinksPool = PoolMemInitNamedPool ("Links Pool");
  35. return TRUE;
  36. }
  37. BOOL
  38. DoneLinkAnnounce (
  39. VOID
  40. )
  41. {
  42. // Write LinkStub max sequencer data
  43. MemDbSetValue (MEMDB_CATEGORY_LINKSTUB_MAXSEQUENCE, g_LinkStubSequencer);
  44. //
  45. // Free Links Pool.
  46. //
  47. if (g_LinksPool != NULL) {
  48. PoolMemDestroyPool (g_LinksPool);
  49. g_LinksPool = NULL;
  50. }
  51. return TRUE;
  52. }
  53. BOOL
  54. SaveLinkFiles (
  55. IN PFILE_HELPER_PARAMS Params
  56. )
  57. {
  58. PCTSTR Ext;
  59. if (Params->Handled) {
  60. return TRUE;
  61. }
  62. Ext = GetFileExtensionFromPath (Params->FullFileSpec);
  63. // Save LNK and PIF filenames to memdb to enumerate later
  64. if (Ext && (StringIMatch (Ext, TEXT("LNK")) || StringIMatch (Ext, TEXT("PIF")))) {
  65. MemDbSetValueEx (
  66. MEMDB_CATEGORY_SHORTCUTS,
  67. Params->FullFileSpec,
  68. NULL,
  69. NULL,
  70. 0,
  71. NULL
  72. );
  73. }
  74. return TRUE;
  75. }
  76. VOID
  77. RemoveLinkFromSystem (
  78. IN LPCTSTR LinkPath
  79. )
  80. {
  81. //
  82. // Remove any move or copy operation specified for the link, then
  83. // mark it for deletion.
  84. //
  85. RemoveOperationsFromPath (LinkPath, ALL_DEST_CHANGE_OPERATIONS);
  86. MarkFileForDelete (LinkPath);
  87. }
  88. //
  89. // Function to send instruction to MemDb to edit a shell link or pif file.
  90. // It checks to see whether the link involved has been touched yet by any
  91. // MemDb operation. It modifies the target path, if in a relocating directory,
  92. // to one of the relocated copies.
  93. //
  94. VOID
  95. pAddLinkEditToMemDb (
  96. IN PCTSTR LinkPath,
  97. IN PCTSTR NewTarget,
  98. IN PCTSTR NewArgs,
  99. IN PCTSTR NewWorkDir,
  100. IN PCTSTR NewIconPath,
  101. IN INT NewIconNr,
  102. IN PLNK_EXTRA_DATA ExtraData, OPTIONAL
  103. IN BOOL ForceToShowNormal
  104. )
  105. {
  106. UINT sequencer;
  107. TCHAR tmpStr [20];
  108. sequencer = AddOperationToPath (LinkPath, OPERATION_LINK_EDIT);
  109. if (sequencer == INVALID_OFFSET) {
  110. DEBUGMSG ((DBG_ERROR, "Cannot set OPERATION_LINK_EDIT on %s", LinkPath));
  111. return;
  112. }
  113. if (NewTarget) {
  114. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, NewTarget, MEMDB_CATEGORY_LINKEDIT_TARGET);
  115. }
  116. if (NewArgs) {
  117. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, NewArgs, MEMDB_CATEGORY_LINKEDIT_ARGS);
  118. }
  119. if (NewWorkDir) {
  120. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, NewWorkDir, MEMDB_CATEGORY_LINKEDIT_WORKDIR);
  121. }
  122. if (NewIconPath) {
  123. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, NewIconPath, MEMDB_CATEGORY_LINKEDIT_ICONPATH);
  124. }
  125. if (NewIconPath) {
  126. _itoa (NewIconNr, tmpStr, 16);
  127. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_ICONNUMBER);
  128. }
  129. if (ForceToShowNormal) {
  130. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, TEXT("1"), MEMDB_CATEGORY_LINKEDIT_SHOWNORMAL);
  131. }
  132. if (ExtraData) {
  133. _itoa (ExtraData->FullScreen, tmpStr, 10);
  134. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_FULLSCREEN);
  135. _itoa (ExtraData->xSize, tmpStr, 10);
  136. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_XSIZE);
  137. _itoa (ExtraData->ySize, tmpStr, 10);
  138. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_YSIZE);
  139. _itoa (ExtraData->QuickEdit, tmpStr, 10);
  140. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_QUICKEDIT);
  141. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, ExtraData->FontName, MEMDB_CATEGORY_LINKEDIT_FONTNAME);
  142. _itoa (ExtraData->xFontSize, tmpStr, 10);
  143. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_XFONTSIZE);
  144. _itoa (ExtraData->yFontSize, tmpStr, 10);
  145. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_YFONTSIZE);
  146. _itoa (ExtraData->FontWeight, tmpStr, 10);
  147. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_FONTWEIGHT);
  148. _itoa (ExtraData->FontFamily, tmpStr, 10);
  149. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_FONTFAMILY);
  150. _itoa (ExtraData->CurrentCodePage, tmpStr, 10);
  151. AddPropertyToPathEx (sequencer, OPERATION_LINK_EDIT, tmpStr, MEMDB_CATEGORY_LINKEDIT_CODEPAGE);
  152. }
  153. MYASSERT (IsFileMarkedForOperation (LinkPath, OPERATION_LINK_EDIT));
  154. }
  155. //
  156. // Function to send instruction to MemDb to save some data about a link that's going to be edited.
  157. // We do that to be able to restore this link later using lnkstub.exe
  158. //
  159. UINT
  160. pAddLinkStubToMemDb (
  161. IN PCTSTR LinkPath,
  162. IN PCTSTR OldTarget,
  163. IN PCTSTR OldArgs,
  164. IN PCTSTR OldWorkDir,
  165. IN PCTSTR OldIconPath,
  166. IN INT OldIconNr,
  167. IN DWORD OldShowMode,
  168. IN DWORD Announcement,
  169. IN DWORD Availability
  170. )
  171. {
  172. UINT sequencer;
  173. TCHAR tmpStr [20];
  174. MEMDB_ENUM e, e1;
  175. TCHAR key [MEMDB_MAX];
  176. MYASSERT (OldTarget || OldWorkDir || OldIconPath || OldIconNr);
  177. sequencer = AddOperationToPath (LinkPath, OPERATION_LINK_STUB);
  178. if (sequencer == INVALID_OFFSET) {
  179. DEBUGMSG ((DBG_ERROR, "Cannot set OPERATION_LINK_STUB on %s", LinkPath));
  180. return 0;
  181. }
  182. g_LinkStubSequencer++;
  183. if (OldTarget) {
  184. AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, OldTarget, MEMDB_CATEGORY_LINKSTUB_TARGET);
  185. }
  186. if (OldArgs) {
  187. AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, OldArgs, MEMDB_CATEGORY_LINKSTUB_ARGS);
  188. }
  189. if (OldWorkDir) {
  190. AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, OldWorkDir, MEMDB_CATEGORY_LINKSTUB_WORKDIR);
  191. }
  192. if (OldIconPath) {
  193. AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, OldIconPath, MEMDB_CATEGORY_LINKSTUB_ICONPATH);
  194. }
  195. if (OldIconPath) {
  196. _itoa (OldIconNr, tmpStr, 16);
  197. AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, tmpStr, MEMDB_CATEGORY_LINKSTUB_ICONNUMBER);
  198. }
  199. _itoa (OldShowMode, tmpStr, 16);
  200. AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, tmpStr, MEMDB_CATEGORY_LINKSTUB_SHOWMODE);
  201. _itoa (g_LinkStubSequencer, tmpStr, 16);
  202. AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, tmpStr, MEMDB_CATEGORY_LINKSTUB_SEQUENCER);
  203. _itoa (Announcement, tmpStr, 16);
  204. AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, tmpStr, MEMDB_CATEGORY_LINKSTUB_ANNOUNCEMENT);
  205. _itoa (Availability, tmpStr, 16);
  206. AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, tmpStr, MEMDB_CATEGORY_LINKSTUB_REPORTAVAIL);
  207. MemDbBuildKey (key, MEMDB_CATEGORY_REQFILES_MAIN, OldTarget, TEXT("*"), NULL);
  208. if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  209. do {
  210. MemDbBuildKey (key, MEMDB_CATEGORY_REQFILES_ADDNL, e.szName, TEXT("*"), NULL);
  211. if (MemDbEnumFirstValue (&e1, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  212. AddPropertyToPathEx (sequencer, OPERATION_LINK_STUB, e1.szName, MEMDB_CATEGORY_LINKSTUB_REQFILE);
  213. }
  214. } while (MemDbEnumNextValue (&e));
  215. }
  216. MYASSERT (IsFileMarkedForOperation (LinkPath, OPERATION_LINK_STUB));
  217. return g_LinkStubSequencer;
  218. }
  219. BOOL
  220. pReportEntry (
  221. IN PCTSTR ReportEntry,
  222. IN PCTSTR Category,
  223. IN PCTSTR Message,
  224. IN PCTSTR Context,
  225. IN PCTSTR Object
  226. )
  227. {
  228. PCTSTR component;
  229. component = JoinPaths (ReportEntry, Category);
  230. MsgMgr_ContextMsg_Add (Context, component, Message);
  231. MsgMgr_LinkObjectWithContext (Context, Object);
  232. FreePathString (component);
  233. return TRUE;
  234. }
  235. PTSTR
  236. GetLastDirFromPath (
  237. IN PCTSTR FileName
  238. )
  239. {
  240. PTSTR result = NULL;
  241. PTSTR temp = NULL;
  242. PTSTR ptr;
  243. temp = DuplicatePathString (FileName, 0);
  244. __try {
  245. ptr = (PTSTR)GetFileNameFromPath (temp);
  246. if (ptr == temp) {
  247. __leave;
  248. }
  249. ptr = _tcsdec (temp, ptr);
  250. if (!ptr) {
  251. __leave;
  252. }
  253. *ptr = 0;
  254. ptr = (PTSTR)GetFileNameFromPath (temp);
  255. if (ptr == temp) {
  256. __leave;
  257. }
  258. result = DuplicatePathString (ptr, 0);
  259. }
  260. __finally {
  261. FreePathString (temp);
  262. }
  263. return result;
  264. }
  265. PTSTR
  266. GetDriveFromPath (
  267. IN PCTSTR FileName
  268. )
  269. {
  270. PTSTR result;
  271. PTSTR ptr;
  272. result = DuplicatePathString (FileName, 0);
  273. ptr = _tcschr (result, TEXT(':'));
  274. if (!ptr) {
  275. FreePathString (result);
  276. result = NULL;
  277. }
  278. else {
  279. *ptr = 0;
  280. }
  281. return result;
  282. }
  283. #define MAX_PRIORITY 0xFFFF
  284. BOOL
  285. HandleDeferredAnnounce (
  286. IN PCTSTR LinkName,
  287. IN PCTSTR ModuleName,
  288. IN BOOL DosApp
  289. )
  290. {
  291. TCHAR key [MEMDB_MAX];
  292. PMIGDB_CONTEXT migDbContext;
  293. DWORD actType;
  294. PLINK_STRUCT linkStruct;
  295. PCTSTR reportEntry = NULL;
  296. DWORD priority;
  297. PCTSTR newLinkName = NULL;
  298. PCTSTR linkName = NULL;
  299. PCTSTR extPtr;
  300. MEMDB_ENUM eNicePaths;
  301. DWORD messageId = 0;
  302. PTSTR pattern = NULL;
  303. PTSTR category = NULL;
  304. PTSTR tempParse = NULL;
  305. PTSTR lastDir;
  306. PTSTR drive;
  307. DWORD oldValue;
  308. DWORD oldPrior;
  309. PTSTR argArray[3];
  310. PCTSTR p;
  311. PTSTR q;
  312. BOOL reportEntryIsResource = TRUE;
  313. PCTSTR temp1, temp2;
  314. MYASSERT(ModuleName);
  315. MemDbBuildKey (key, MEMDB_CATEGORY_DEFERREDANNOUNCE, ModuleName, NULL, NULL);
  316. if (!MemDbGetValueAndFlags (key, (PDWORD)(&migDbContext), &actType)) {
  317. actType = ACT_UNKNOWN;
  318. migDbContext = NULL;
  319. }
  320. //
  321. // we need to set the following variables:
  322. // - ReportEntry - is going to be either "Software Incompatible with NT",
  323. // "Software with minor problems" or
  324. // "Software that require reinstallation"
  325. // - Category - is one of the following: - Localized section name
  326. // - link name (with friendly addition)
  327. // - Unlocalized section name
  328. // - Message - this is in migdb context
  329. //
  330. // - Object - this is module name
  331. //
  332. linkStruct = (PLINK_STRUCT) PoolMemGetMemory (g_LinksPool, sizeof (LINK_STRUCT));
  333. ZeroMemory (linkStruct, sizeof (LINK_STRUCT));
  334. linkStruct->MigDbContext = migDbContext;
  335. linkStruct->Object = PoolMemDuplicateString (g_LinksPool, ModuleName);
  336. switch (actType) {
  337. case ACT_REINSTALL:
  338. #if 0
  339. if ((linkStruct->MigDbContext) &&
  340. (linkStruct->MigDbContext->Message)
  341. ) {
  342. reportEntry = GetStringResource (MSG_MINOR_PROBLEM_ROOT);
  343. } else {
  344. reportEntry = GetStringResource (MSG_REINSTALL_ROOT);
  345. }
  346. #endif
  347. temp1 = GetStringResource (MSG_REINSTALL_ROOT);
  348. if (!temp1) {
  349. break;
  350. }
  351. temp2 = GetStringResource (
  352. linkStruct->MigDbContext && linkStruct->MigDbContext->Message ?
  353. MSG_REINSTALL_DETAIL_SUBGROUP :
  354. MSG_REINSTALL_LIST_SUBGROUP
  355. );
  356. if (!temp2) {
  357. break;
  358. }
  359. reportEntry = JoinPaths (temp1, temp2);
  360. reportEntryIsResource = FALSE;
  361. FreeStringResource (temp1);
  362. FreeStringResource (temp2);
  363. break;
  364. case ACT_REINSTALL_BLOCK:
  365. temp1 = GetStringResource (MSG_BLOCKING_ITEMS_ROOT);
  366. if (!temp1) {
  367. break;
  368. }
  369. temp2 = GetStringResource (MSG_REINSTALL_BLOCK_ROOT);
  370. if (!temp2) {
  371. break;
  372. }
  373. reportEntry = JoinPaths (temp1, temp2);
  374. reportEntryIsResource = FALSE;
  375. FreeStringResource (temp1);
  376. FreeStringResource (temp2);
  377. break;
  378. case ACT_MINORPROBLEMS:
  379. reportEntry = GetStringResource (MSG_MINOR_PROBLEM_ROOT);
  380. break;
  381. case ACT_INCOMPATIBLE:
  382. case ACT_INC_NOBADAPPS:
  383. case ACT_INC_IHVUTIL:
  384. case ACT_INC_PREINSTUTIL:
  385. case ACT_INC_SIMILAROSFUNC:
  386. if (DosApp && (*g_Boot16 != BOOT16_NO)) {
  387. reportEntry = GetStringResource (MSG_DOS_DESIGNED_ROOT);
  388. }
  389. else {
  390. temp1 = GetStringResource (MSG_INCOMPATIBLE_ROOT);
  391. switch (actType) {
  392. case ACT_INC_SIMILAROSFUNC:
  393. temp2 = GetStringResource (MSG_INCOMPATIBLE_UTIL_SIMILAR_FEATURE_SUBGROUP);
  394. break;
  395. case ACT_INC_PREINSTUTIL:
  396. temp2 = GetStringResource (MSG_INCOMPATIBLE_PREINSTALLED_UTIL_SUBGROUP);
  397. break;
  398. case ACT_INC_IHVUTIL:
  399. temp2 = GetStringResource (MSG_INCOMPATIBLE_HW_UTIL_SUBGROUP);
  400. break;
  401. default:
  402. temp2 = GetStringResource (
  403. linkStruct->MigDbContext && linkStruct->MigDbContext->Message ?
  404. MSG_INCOMPATIBLE_DETAIL_SUBGROUP:
  405. MSG_TOTALLY_INCOMPATIBLE_SUBGROUP
  406. );
  407. break;
  408. }
  409. MYASSERT (temp1 && temp2);
  410. reportEntry = JoinPaths (temp1, temp2);
  411. reportEntryIsResource = FALSE;
  412. FreeStringResource (temp1);
  413. FreeStringResource (temp2);
  414. }
  415. break;
  416. case ACT_INC_SAFETY:
  417. MYASSERT (LinkName);
  418. temp1 = GetStringResource (MSG_INCOMPATIBLE_ROOT);
  419. temp2 = GetStringResource (MSG_REMOVED_FOR_SAFETY_SUBGROUP);
  420. MYASSERT (temp1 && temp2);
  421. reportEntry = JoinPaths (temp1, temp2);
  422. reportEntryIsResource = FALSE;
  423. FreeStringResource (temp1);
  424. FreeStringResource (temp2);
  425. newLinkName = JoinPaths (S_RUNKEYFOLDER, GetFileNameFromPath (LinkName));
  426. break;
  427. case ACT_UNKNOWN:
  428. reportEntry = GetStringResource (MSG_UNKNOWN_ROOT);
  429. break;
  430. default:
  431. LOG((LOG_ERROR, "Unknown action for deferred announcement."));
  432. return FALSE;
  433. }
  434. if (!newLinkName) {
  435. newLinkName = LinkName;
  436. }
  437. if (reportEntry != NULL) {
  438. linkStruct->ReportEntry = PoolMemDuplicateString (g_LinksPool, reportEntry);
  439. if (reportEntryIsResource) {
  440. FreeStringResource (reportEntry);
  441. } else {
  442. FreePathString (reportEntry);
  443. }
  444. }
  445. linkStruct->LinkName = newLinkName?PoolMemDuplicateString (g_LinksPool, newLinkName):NULL;
  446. //
  447. // all we need to set now is the category
  448. //
  449. // if we have a migdb context with a Localized name section
  450. //
  451. if ((migDbContext != NULL) &&
  452. (migDbContext->SectLocalizedName != NULL)
  453. ) {
  454. linkStruct->Context = PoolMemDuplicateString (g_LinksPool, migDbContext->SectLocalizedName);
  455. linkStruct->Category = PoolMemDuplicateString (g_LinksPool, migDbContext->SectLocalizedName);
  456. priority = 0;
  457. }
  458. else {
  459. linkStruct->Context = PoolMemDuplicateString (g_LinksPool, newLinkName?newLinkName:ModuleName);
  460. if (newLinkName == NULL) {
  461. MYASSERT (migDbContext);
  462. if (migDbContext->SectName) {
  463. linkStruct->Category = PoolMemDuplicateString (g_LinksPool, migDbContext->SectName);
  464. }
  465. else {
  466. linkStruct->Category = NULL;
  467. }
  468. priority = 0;
  469. }
  470. else {
  471. linkName = GetFileNameFromPath (newLinkName);
  472. extPtr = GetFileExtensionFromPath (linkName);
  473. if (extPtr != NULL) {
  474. extPtr = _tcsdec (linkName, extPtr);
  475. }
  476. if (extPtr == NULL) {
  477. extPtr = GetEndOfString (linkName);
  478. }
  479. messageId = 0;
  480. priority = MAX_PRIORITY;
  481. if (MemDbEnumFirstValue (&eNicePaths, MEMDB_CATEGORY_NICE_PATHS"\\*", MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  482. do {
  483. pattern = JoinPaths (eNicePaths.szName, "\\*");
  484. if (IsPatternMatch (pattern, newLinkName)) {
  485. if (priority > eNicePaths.UserFlags) {
  486. messageId = eNicePaths.dwValue;
  487. priority = eNicePaths.UserFlags;
  488. }
  489. }
  490. FreePathString (pattern);
  491. }
  492. while (MemDbEnumNextValue (&eNicePaths));
  493. }
  494. category = AllocText ((PBYTE) extPtr - (PBYTE) linkName + sizeof (TCHAR));
  495. p = linkName;
  496. q = category;
  497. while (p < extPtr) {
  498. if (_tcsnextc (p) == TEXT(' ')) {
  499. do {
  500. p++;
  501. } while (_tcsnextc (p) == TEXT(' '));
  502. if (q > category && *p) {
  503. *q++ = TEXT(' ');
  504. }
  505. } else if (IsLeadByte (*p)) {
  506. *q++ = *p++;
  507. *q++ = *p++;
  508. } else {
  509. *q++ = *p++;
  510. }
  511. }
  512. *q = 0;
  513. if (messageId == 0) {
  514. lastDir = GetLastDirFromPath (newLinkName);
  515. drive = GetDriveFromPath (newLinkName);
  516. if (drive != NULL) {
  517. drive[0] = (TCHAR)toupper (drive[0]);
  518. if (lastDir != NULL) {
  519. argArray [0] = category;
  520. argArray [1] = lastDir;
  521. argArray [2] = drive;
  522. tempParse = (PTSTR)ParseMessageID (MSG_NICE_PATH_DRIVE_AND_FOLDER, argArray);
  523. }
  524. else {
  525. argArray [0] = category;
  526. argArray [1] = drive;
  527. tempParse = (PTSTR)ParseMessageID (MSG_NICE_PATH_DRIVE, argArray);
  528. }
  529. }
  530. else {
  531. if (lastDir != NULL) {
  532. argArray [0] = category;
  533. argArray [1] = lastDir;
  534. tempParse = (PTSTR)ParseMessageID (MSG_NICE_PATH_FOLDER, argArray);
  535. }
  536. else {
  537. argArray [0] = category;
  538. tempParse = (PTSTR)ParseMessageID (MSG_NICE_PATH_LINK, argArray);
  539. }
  540. }
  541. linkStruct->Category = PoolMemDuplicateString (g_LinksPool, tempParse);
  542. FreeStringResourcePtrA (&tempParse);
  543. priority = MAX_PRIORITY;
  544. } else {
  545. tempParse = (PTSTR)ParseMessageID (messageId, &category);
  546. StringCopy (category, tempParse);
  547. linkStruct->Category = PoolMemDuplicateString (g_LinksPool, tempParse);
  548. FreeStringResourcePtrA (&tempParse);
  549. }
  550. FreeText (category);
  551. }
  552. }
  553. linkStruct->LinkNameNoPath = linkName?PoolMemDuplicateString (g_LinksPool, linkName):linkStruct->Context;
  554. MemDbBuildKey (
  555. key,
  556. MEMDB_CATEGORY_REPORT_LINKS,
  557. linkStruct->ReportEntry,
  558. linkName?linkName:linkStruct->Context,
  559. ModuleName);
  560. if ((!MemDbGetValueAndFlags (key, &oldValue, &oldPrior)) ||
  561. (oldPrior > priority)
  562. ) {
  563. MemDbSetValueAndFlags (key, (DWORD)linkStruct, priority, 0);
  564. }
  565. if (newLinkName != LinkName) {
  566. FreePathString (newLinkName);
  567. }
  568. return TRUE;
  569. }
  570. BOOL
  571. pIsGUIDLauncherApproved (
  572. IN PCTSTR FileName
  573. )
  574. {
  575. INFCONTEXT context;
  576. MYASSERT (g_Win95UpgInf != INVALID_HANDLE_VALUE);
  577. return (SetupFindFirstLine (g_Win95UpgInf, S_APPROVED_GUID_LAUNCHER, FileName, &context));
  578. }
  579. #define GUID_LEN (sizeof ("{00000000-0000-0000-0000-000000000000}") - 1)
  580. #define GUID_DASH_1 (sizeof ("{00000000") - 1)
  581. #define GUID_DASH_2 (sizeof ("{00000000-0000") - 1)
  582. #define GUID_DASH_3 (sizeof ("{00000000-0000-0000") - 1)
  583. #define GUID_DASH_4 (sizeof ("{00000000-0000-0000-0000") - 1)
  584. BOOL
  585. pSendCmdLineGuidsToMemdb (
  586. IN PCTSTR File,
  587. IN PCTSTR Target,
  588. IN PCTSTR Arguments
  589. )
  590. /*++
  591. Routine Description:
  592. pSendCmdLineGuidsToMemdb saves any GUIDs contained in a command line to
  593. memdb, along with the file name. Later, OLEREG resolves the GUIDs and
  594. deletes the file if a GUID is incompatible.
  595. Arguments:
  596. File - Specifies the file to delete if the command line arguments contain
  597. an invalid GUID.
  598. Target - Specifies the Target (needs to be one of the approved targets for the
  599. LNK file to go away in an incompatible case).
  600. Arguments - Specifies a command line that may contain one or more GUIDs in
  601. the {a-b-c-d-e} format.
  602. Return value:
  603. TRUE - the operation was successful
  604. FALSE - the operation failed
  605. --*/
  606. {
  607. LPCTSTR p, q;
  608. DWORD Offset;
  609. BOOL b;
  610. static DWORD Seq = 0;
  611. TCHAR TextSeq[16];
  612. TCHAR Guid[GUID_LEN + 1];
  613. PCTSTR namePtr;
  614. namePtr = GetFileNameFromPath (Target);
  615. if (namePtr && pIsGUIDLauncherApproved (namePtr)) {
  616. p = _tcschr (Arguments, TEXT('{'));
  617. while (p) {
  618. q = _tcschr (p, TEXT('}'));
  619. if (q && ((q - p) == (GUID_LEN - 1))) {
  620. if (p[GUID_DASH_1] == TEXT('-') &&
  621. p[GUID_DASH_2] == TEXT('-') &&
  622. p[GUID_DASH_3] == TEXT('-') &&
  623. p[GUID_DASH_4] == TEXT('-')
  624. ) {
  625. //
  626. // Extract the GUID
  627. //
  628. q = _tcsinc (q);
  629. StringCopyAB (Guid, p, q);
  630. //
  631. // Add the file name
  632. //
  633. b = MemDbSetValueEx (
  634. MEMDB_CATEGORY_LINK_STRINGS,
  635. File,
  636. NULL,
  637. NULL,
  638. 0,
  639. &Offset
  640. );
  641. if (b) {
  642. //
  643. // Now add an entry for the GUID
  644. //
  645. Seq++;
  646. wsprintf (TextSeq, TEXT("%u"), Seq);
  647. b = MemDbSetValueEx (
  648. MEMDB_CATEGORY_LINK_GUIDS,
  649. Guid,
  650. TextSeq,
  651. NULL,
  652. Offset,
  653. NULL
  654. );
  655. }
  656. if (!b) {
  657. LOG ((LOG_ERROR, "Failed to store command line guids."));
  658. }
  659. }
  660. }
  661. p = _tcschr (p + 1, TEXT('{'));
  662. }
  663. }
  664. return TRUE;
  665. }
  666. BOOL
  667. pIsFileInStartup (
  668. IN PCTSTR FileName
  669. )
  670. {
  671. TCHAR key [MEMDB_MAX];
  672. MemDbBuildKey (key, MEMDB_CATEGORY_SF_STARTUP, FileName, NULL, NULL);
  673. return (MemDbGetPatternValue (key, NULL));
  674. }
  675. BOOL
  676. pProcessShortcut (
  677. IN PCTSTR FileName,
  678. IN IShellLink *ShellLink,
  679. IN IPersistFile *PersistFile
  680. )
  681. {
  682. TCHAR shortcutTarget [MEMDB_MAX];
  683. TCHAR shortcutArgs [MEMDB_MAX];
  684. TCHAR shortcutWorkDir [MEMDB_MAX];
  685. TCHAR shortcutIconPath [MEMDB_MAX];
  686. PTSTR shortcutNewTarget = NULL;
  687. PTSTR shortcutNewArgs = NULL;
  688. PTSTR shortcutNewIconPath = NULL;
  689. PTSTR shortcutNewWorkDir = NULL;
  690. PTSTR commandPath = NULL;
  691. PTSTR fullPath = NULL;
  692. PCTSTR extPtr;
  693. INT shortcutIcon;
  694. INT newShortcutIcon;
  695. DWORD shortcutShowMode;
  696. WORD shortcutHotKey;
  697. DWORD fileStatus;
  698. BOOL msDosMode;
  699. BOOL dosApp;
  700. DWORD attrib;
  701. LNK_EXTRA_DATA ExtraData;
  702. INT lnkIdx;
  703. TCHAR lnkIdxStr [10];
  704. BOOL toBeModified = FALSE;
  705. BOOL ConvertedLnk = FALSE;
  706. DWORD announcement;
  707. DWORD availability;
  708. __try {
  709. fileStatus = GetFileStatusOnNt (FileName);
  710. if (((fileStatus & FILESTATUS_DELETED ) == FILESTATUS_DELETED ) ||
  711. ((fileStatus & FILESTATUS_REPLACED) == FILESTATUS_REPLACED)
  712. ) {
  713. __leave;
  714. }
  715. if (!ExtractShortcutInfo (
  716. shortcutTarget,
  717. shortcutArgs,
  718. shortcutWorkDir,
  719. shortcutIconPath,
  720. &shortcutIcon,
  721. &shortcutHotKey,
  722. &dosApp,
  723. &msDosMode,
  724. &shortcutShowMode,
  725. &ExtraData,
  726. FileName,
  727. ShellLink,
  728. PersistFile
  729. )) {
  730. __leave;
  731. }
  732. if (msDosMode) {
  733. //
  734. // we want to modify this PIF file so it doesn't have MSDOS mode set
  735. // we will only add it to the modify list. The NT side will know what
  736. // to do when a PIF is marked for beeing modify
  737. //
  738. toBeModified = TRUE;
  739. }
  740. if (IsFileMarkedForAnnounce (shortcutTarget)) {
  741. announcement = GetFileAnnouncement (shortcutTarget);
  742. if (g_ConfigOptions.ShowAllReport ||
  743. ((announcement != ACT_INC_IHVUTIL) &&
  744. (announcement != ACT_INC_PREINSTUTIL) &&
  745. (announcement != ACT_INC_SIMILAROSFUNC)
  746. )
  747. ) {
  748. HandleDeferredAnnounce (FileName, shortcutTarget, dosApp);
  749. }
  750. }
  751. fileStatus = GetFileStatusOnNt (shortcutTarget);
  752. if ((fileStatus & FILESTATUS_DELETED) == FILESTATUS_DELETED) {
  753. if (IsFileMarkedForAnnounce (shortcutTarget)) {
  754. if (!pIsFileInStartup (FileName)) {
  755. if (!g_ConfigOptions.KeepBadLinks) {
  756. RemoveLinkFromSystem (FileName);
  757. } else {
  758. // we only care about LNK files
  759. if (StringIMatch (GetFileExtensionFromPath (FileName), TEXT("LNK"))) {
  760. // let's see what kind of announcement we have here.
  761. // We want to leave the LNK as is if the app was announced
  762. // using MigDb. However, if the app was announced using
  763. // dynamic checking (module checking) then we want to point
  764. // this shortcut to our stub EXE
  765. announcement = GetFileAnnouncement (shortcutTarget);
  766. if ((announcement == ACT_INC_NOBADAPPS) ||
  767. (announcement == ACT_REINSTALL) ||
  768. (announcement == ACT_REINSTALL_BLOCK) ||
  769. (announcement == ACT_INC_IHVUTIL) ||
  770. (announcement == ACT_INC_PREINSTUTIL) ||
  771. (announcement == ACT_INC_SIMILAROSFUNC)
  772. ) {
  773. //
  774. // This is the case when we want to redirect this LNK to point
  775. // to our lnk stub. Extract will fail if the icon is known-good.
  776. // In that case, keep using the target icon.
  777. //
  778. if (ExtractIconIntoDatFile (
  779. (*shortcutIconPath)?shortcutIconPath:shortcutTarget,
  780. shortcutIcon,
  781. &g_IconContext,
  782. &newShortcutIcon
  783. )) {
  784. shortcutNewIconPath = JoinPaths (g_System32Dir, TEXT("migicons.exe"));
  785. shortcutIcon = newShortcutIcon;
  786. } else {
  787. shortcutNewIconPath = GetPathStringOnNt (
  788. (*shortcutIconPath) ?
  789. shortcutIconPath : shortcutTarget
  790. );
  791. }
  792. availability = g_ConfigOptions.ShowAllReport ||
  793. ((announcement != ACT_INC_IHVUTIL) &&
  794. (announcement != ACT_INC_PREINSTUTIL) &&
  795. (announcement != ACT_INC_SIMILAROSFUNC)
  796. );
  797. lnkIdx = pAddLinkStubToMemDb (
  798. FileName,
  799. shortcutTarget,
  800. shortcutArgs,
  801. shortcutWorkDir,
  802. shortcutNewIconPath,
  803. shortcutIcon + 1, // Add 1 because lnkstub.exe is one-based, but we are zero based
  804. shortcutShowMode,
  805. announcement,
  806. availability
  807. );
  808. wsprintf (lnkIdxStr, TEXT("%d"), lnkIdx);
  809. shortcutNewTarget = JoinPaths (g_System32Dir, S_LNKSTUB_EXE);
  810. shortcutNewArgs = DuplicatePathString (lnkIdxStr, 0);
  811. pAddLinkEditToMemDb (
  812. FileName,
  813. shortcutNewTarget,
  814. shortcutNewArgs,
  815. shortcutNewWorkDir,
  816. shortcutNewIconPath,
  817. shortcutIcon, // don't add one -- shortcuts are zero based
  818. NULL,
  819. TRUE
  820. );
  821. }
  822. } else {
  823. RemoveLinkFromSystem (FileName);
  824. }
  825. }
  826. } else {
  827. //
  828. // This is a startup item
  829. //
  830. RemoveLinkFromSystem (FileName);
  831. }
  832. } else {
  833. RemoveLinkFromSystem (FileName);
  834. }
  835. __leave;
  836. }
  837. if ((fileStatus & FILESTATUS_REPLACED) != FILESTATUS_REPLACED) {
  838. //
  839. // this target is not replaced by a migration DLL or by NT. We need
  840. // to know if this is a "known good" target. If not, we will announce
  841. // this link as beeing "unknown"
  842. //
  843. if (!IsFileMarkedAsKnownGood (shortcutTarget)) {
  844. fullPath = JoinPaths (shortcutWorkDir, shortcutTarget);
  845. if (!IsFileMarkedAsKnownGood (fullPath)) {
  846. extPtr = GetFileExtensionFromPath (shortcutTarget);
  847. if (extPtr) {
  848. if (StringIMatch (extPtr, TEXT("EXE"))) {
  849. //
  850. // This one statement controls our
  851. // "unknown" category. We have the
  852. // ability to list the things we don't
  853. // recognize.
  854. //
  855. // It is currently "off".
  856. //
  857. //HandleDeferredAnnounce (FileName, shortcutTarget, dosApp);
  858. }
  859. }
  860. }
  861. FreePathString (fullPath);
  862. }
  863. }
  864. //
  865. // If this LNK points to a target that will change, back up the
  866. // original LNK, because we might change it.
  867. //
  868. if (fileStatus & ALL_CHANGE_OPERATIONS) {
  869. MarkFileForBackup (FileName);
  870. }
  871. //
  872. // If target points to an OLE object, remove any links to incompatible OLE objects
  873. //
  874. pSendCmdLineGuidsToMemdb (FileName, shortcutTarget, shortcutArgs);
  875. //all we try to do now is to see if this lnk or pif file is going to be edited
  876. //on NT side. That is if target or icon should change.
  877. shortcutNewTarget = GetPathStringOnNt (shortcutTarget);
  878. if (!StringIMatch (shortcutNewTarget, shortcutTarget)) {
  879. toBeModified = TRUE;
  880. //
  881. // special case for COMMAND.COM
  882. //
  883. if (shortcutArgs [0] == 0) {
  884. commandPath = JoinPaths (g_System32Dir, S_COMMAND_COM);
  885. if (StringIMatch (commandPath, shortcutNewTarget)) {
  886. if (msDosMode) {
  887. //
  888. // remove MS-DOS mode PIF files that point to command.com
  889. //
  890. RemoveLinkFromSystem (FileName);
  891. //
  892. // If msdosmode was on, we need to determine how we are going to handle
  893. // boot16. We will turn on boot16 mode if:
  894. // (a) The .pif points to something besides command.com
  895. // (b) The .pif is in a shell folder.
  896. //
  897. // Note that the check for b simply entails seeing if the PIF file has
  898. // OPERATION_FILE_MOVE_SHELL_FOLDER associated with it.
  899. //
  900. //
  901. if (msDosMode && *g_Boot16 == BOOT16_AUTOMATIC) {
  902. if (!StringIMatch(GetFileNameFromPath (shortcutNewTarget?shortcutNewTarget:shortcutTarget), S_COMMAND_COM) ||
  903. IsFileMarkedForOperation (FileName, OPERATION_FILE_MOVE_SHELL_FOLDER)) {
  904. *g_Boot16 = BOOT16_YES;
  905. }
  906. }
  907. __leave;
  908. } else {
  909. ConvertedLnk = TRUE;
  910. FreePathString (shortcutNewTarget);
  911. shortcutNewTarget = JoinPaths (g_System32Dir, S_CMD_EXE);
  912. }
  913. }
  914. FreePathString (commandPath);
  915. shortcutNewArgs = NULL;
  916. }
  917. else {
  918. shortcutNewArgs = DuplicatePathString (shortcutArgs, 0);
  919. }
  920. }
  921. else {
  922. FreePathString (shortcutNewTarget);
  923. shortcutNewTarget = NULL;
  924. }
  925. //
  926. // If msdosmode was on, we need to determine how we are going to handle
  927. // boot16. We will turn on boot16 mode if:
  928. // (a) The .pif points to something besides command.com
  929. // (b) The .pif is in a shell folder.
  930. //
  931. // Note that the check for b simply entails seeing if the PIF file has
  932. // OPERATION_FILE_MOVE_SHELL_FOLDER associated with it.
  933. //
  934. //
  935. if (msDosMode && *g_Boot16 == BOOT16_AUTOMATIC) {
  936. if (!StringIMatch(GetFileNameFromPath (shortcutNewTarget?shortcutNewTarget:shortcutTarget), S_COMMAND_COM) ||
  937. IsFileMarkedForOperation (FileName, OPERATION_FILE_MOVE_SHELL_FOLDER)) {
  938. *g_Boot16 = BOOT16_YES;
  939. }
  940. }
  941. //
  942. // If the link points to a directory, see that the directory survives on NT.
  943. // Potentially this directory can be cleaned up if it's in a shell folder and
  944. // becomes empty after our ObsoleteLinks check
  945. //
  946. attrib = QuietGetFileAttributes (shortcutTarget);
  947. if ((attrib != INVALID_ATTRIBUTES) &&
  948. (attrib & FILE_ATTRIBUTE_DIRECTORY)
  949. ){
  950. MarkDirectoryAsPreserved (shortcutNewTarget?shortcutNewTarget:shortcutTarget);
  951. }
  952. //OK, so much with target, let's see what's with the work dir
  953. shortcutNewWorkDir = GetPathStringOnNt (shortcutWorkDir);
  954. if (!StringIMatch (shortcutNewWorkDir, shortcutWorkDir)) {
  955. toBeModified = TRUE;
  956. }
  957. else {
  958. FreePathString (shortcutNewWorkDir);
  959. shortcutNewWorkDir = NULL;
  960. }
  961. //
  962. // If the working dir for this link is a directory, see that the directory survives on NT.
  963. // Potentially this directory can be cleaned up if it's in a shell folder and
  964. // becomes empty after our ObsoleteLinks check
  965. //
  966. attrib = QuietGetFileAttributes (shortcutWorkDir);
  967. if ((attrib != INVALID_ATTRIBUTES) &&
  968. (attrib & FILE_ATTRIBUTE_DIRECTORY)
  969. ){
  970. MarkDirectoryAsPreserved (shortcutNewWorkDir?shortcutNewWorkDir:shortcutWorkDir);
  971. }
  972. //OK, so much with workdir, let's see what's with icon
  973. fileStatus = GetFileStatusOnNt (shortcutIconPath);
  974. if ((fileStatus & FILESTATUS_DELETED) ||
  975. ((fileStatus & FILESTATUS_REPLACED) && (fileStatus & FILESTATUS_NTINSTALLED)) ||
  976. (IsFileMarkedForOperation (shortcutIconPath, OPERATION_FILE_MOVE_SHELL_FOLDER))
  977. ) {
  978. //
  979. // Our icon will go away, because our file is getting deleted or
  980. // replaced. Let's try to preserve it. Extract will fail only if
  981. // the icon is known-good.
  982. //
  983. if (ExtractIconIntoDatFile (
  984. shortcutIconPath,
  985. shortcutIcon,
  986. &g_IconContext,
  987. &newShortcutIcon
  988. )) {
  989. shortcutNewIconPath = JoinPaths (g_System32Dir, TEXT("migicons.exe"));
  990. shortcutIcon = newShortcutIcon;
  991. toBeModified = TRUE;
  992. }
  993. }
  994. if (!shortcutNewIconPath) {
  995. shortcutNewIconPath = GetPathStringOnNt (shortcutIconPath);
  996. if (!StringIMatch (shortcutNewIconPath, shortcutIconPath)) {
  997. toBeModified = TRUE;
  998. }
  999. else {
  1000. FreePathString (shortcutNewIconPath);
  1001. shortcutNewIconPath = NULL;
  1002. }
  1003. }
  1004. if (toBeModified) {
  1005. if (ConvertedLnk) {
  1006. //
  1007. // Set this for modifying PIF to LNK
  1008. //
  1009. pAddLinkEditToMemDb (
  1010. FileName,
  1011. shortcutNewTarget?shortcutNewTarget:shortcutTarget,
  1012. shortcutNewArgs?shortcutNewArgs:shortcutArgs,
  1013. shortcutNewWorkDir?shortcutNewWorkDir:shortcutWorkDir,
  1014. shortcutNewIconPath?shortcutNewIconPath:shortcutIconPath,
  1015. shortcutIcon,
  1016. &ExtraData,
  1017. FALSE
  1018. );
  1019. } else {
  1020. pAddLinkEditToMemDb (
  1021. FileName,
  1022. shortcutNewTarget,
  1023. shortcutNewArgs,
  1024. shortcutNewWorkDir,
  1025. shortcutNewIconPath,
  1026. shortcutIcon,
  1027. NULL,
  1028. FALSE
  1029. );
  1030. }
  1031. }
  1032. }
  1033. __finally {
  1034. if (shortcutNewWorkDir != NULL) {
  1035. FreePathString (shortcutNewWorkDir);
  1036. }
  1037. if (shortcutNewIconPath != NULL) {
  1038. FreePathString (shortcutNewIconPath);
  1039. }
  1040. if (shortcutNewArgs != NULL) {
  1041. FreePathString (shortcutNewArgs);
  1042. }
  1043. if (shortcutNewTarget != NULL) {
  1044. FreePathString (shortcutNewTarget);
  1045. }
  1046. }
  1047. return TRUE;
  1048. }
  1049. PCTSTR
  1050. pBuildNewCategory (
  1051. IN PCTSTR LinkName,
  1052. IN PCTSTR Category,
  1053. IN UINT Levels
  1054. )
  1055. {
  1056. PCTSTR *levPtrs = NULL;
  1057. PCTSTR wackPtr = NULL;
  1058. PCTSTR result = NULL;
  1059. PCTSTR resultTmp = NULL;
  1060. UINT index = 0;
  1061. UINT indexLnk = 0;
  1062. MYASSERT (Levels);
  1063. levPtrs = (PCTSTR *) PoolMemGetMemory (g_LinksPool, (Levels + 1) * sizeof (PCTSTR));
  1064. wackPtr = LinkName;
  1065. while (wackPtr) {
  1066. levPtrs[index] = wackPtr;
  1067. wackPtr = _tcschr (wackPtr, TEXT('\\'));
  1068. if (wackPtr) {
  1069. wackPtr = _tcsinc (wackPtr);
  1070. index ++;
  1071. if (index > Levels) {
  1072. index = 0;
  1073. }
  1074. }
  1075. }
  1076. indexLnk = index;
  1077. if (index == Levels) {
  1078. index = 0;
  1079. } else {
  1080. index ++;
  1081. }
  1082. resultTmp = StringSearchAndReplace (levPtrs [index], levPtrs [indexLnk], Category);
  1083. if (resultTmp) {
  1084. result = StringSearchAndReplace (resultTmp, TEXT("\\"), TEXT("->"));
  1085. } else {
  1086. result = NULL;
  1087. }
  1088. FreePathString (resultTmp);
  1089. PoolMemReleaseMemory (g_LinksPool, (PVOID) levPtrs);
  1090. return result;
  1091. }
  1092. VOID
  1093. pGatherInfoFromDefaultPif (
  1094. VOID
  1095. )
  1096. {
  1097. PCTSTR defaultPifPath = NULL;
  1098. TCHAR tmpStr [20];
  1099. TCHAR pifTarget [MEMDB_MAX];
  1100. TCHAR pifArgs [MEMDB_MAX];
  1101. TCHAR pifWorkDir [MEMDB_MAX];
  1102. TCHAR pifIconPath [MEMDB_MAX];
  1103. INT pifIcon;
  1104. BOOL pifMsDosMode;
  1105. LNK_EXTRA_DATA pifExtraData;
  1106. defaultPifPath = JoinPaths (g_WinDir, S_COMMAND_PIF);
  1107. if (ExtractPifInfo (
  1108. pifTarget,
  1109. pifArgs,
  1110. pifWorkDir,
  1111. pifIconPath,
  1112. &pifIcon,
  1113. &pifMsDosMode,
  1114. &pifExtraData,
  1115. defaultPifPath
  1116. )) {
  1117. _itoa (pifExtraData.FullScreen, tmpStr, 10);
  1118. MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FULLSCREEN, tmpStr, NULL, 0, NULL);
  1119. _itoa (pifExtraData.xSize, tmpStr, 10);
  1120. MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_XSIZE, tmpStr, NULL, 0, NULL);
  1121. _itoa (pifExtraData.ySize, tmpStr, 10);
  1122. MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_YSIZE, tmpStr, NULL, 0, NULL);
  1123. _itoa (pifExtraData.QuickEdit, tmpStr, 10);
  1124. MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_QUICKEDIT, tmpStr, NULL, 0, NULL);
  1125. MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FONTNAME, pifExtraData.FontName, NULL, 0, NULL);
  1126. _itoa (pifExtraData.xFontSize, tmpStr, 10);
  1127. MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_XFONTSIZE, tmpStr, NULL, 0, NULL);
  1128. _itoa (pifExtraData.yFontSize, tmpStr, 10);
  1129. MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_YFONTSIZE, tmpStr, NULL, 0, NULL);
  1130. _itoa (pifExtraData.FontWeight, tmpStr, 10);
  1131. MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FONTWEIGHT, tmpStr, NULL, 0, NULL);
  1132. _itoa (pifExtraData.FontFamily, tmpStr, 10);
  1133. MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_FONTFAMILY, tmpStr, NULL, 0, NULL);
  1134. _itoa (pifExtraData.CurrentCodePage, tmpStr, 10);
  1135. MemDbSetValueEx (MEMDB_CATEGORY_DEFAULT_PIF, MEMDB_CATEGORY_LINKEDIT_CODEPAGE, tmpStr, NULL, 0, NULL);
  1136. }
  1137. FreePathString (defaultPifPath);
  1138. }
  1139. BOOL
  1140. pProcessLinks (
  1141. VOID
  1142. )
  1143. {
  1144. MEMDB_ENUM enumItems;
  1145. MEMDB_ENUM enumDups;
  1146. TCHAR pattern[MEMDB_MAX];
  1147. IShellLink *shellLink;
  1148. IPersistFile *persistFile;
  1149. PLINK_STRUCT linkStruct, linkDup;
  1150. BOOL resolved;
  1151. PCTSTR newCategory = NULL;
  1152. PCTSTR dupCategory = NULL;
  1153. UINT levels = 0;
  1154. DWORD count = 0;
  1155. MYASSERT (g_LinksPool);
  1156. if (InitCOMLink (&shellLink, &persistFile)) {
  1157. wsprintf (pattern, TEXT("%s\\*"), MEMDB_CATEGORY_SHORTCUTS);
  1158. if (MemDbEnumFirstValue (
  1159. &enumItems,
  1160. pattern,
  1161. MEMDB_ALL_SUBLEVELS,
  1162. MEMDB_ENDPOINTS_ONLY
  1163. )) {
  1164. do {
  1165. if (!SafeModeActionCrashed (SAFEMODEID_LNK9X, enumItems.szName)) {
  1166. SafeModeRegisterAction(SAFEMODEID_LNK9X, enumItems.szName);
  1167. if (!pProcessShortcut (enumItems.szName, shellLink, persistFile)) {
  1168. LOG((LOG_ERROR, "Error processing shortcut %s", enumItems.szName));
  1169. }
  1170. count++;
  1171. if (!(count % 4)) {
  1172. TickProgressBar ();
  1173. }
  1174. SafeModeUnregisterAction();
  1175. }
  1176. }
  1177. while (MemDbEnumNextValue (&enumItems));
  1178. }
  1179. FreeCOMLink (&shellLink, &persistFile);
  1180. }
  1181. if (MemDbEnumFirstValue (&enumItems, MEMDB_CATEGORY_REPORT_LINKS"\\*", MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  1182. do {
  1183. newCategory = NULL;
  1184. levels = 0;
  1185. linkStruct = (PLINK_STRUCT)enumItems.dwValue;
  1186. if (linkStruct->LinkName) {
  1187. resolved = !(StringIMatch (linkStruct->LinkNameNoPath, GetFileNameFromPath (linkStruct->LinkName)));
  1188. }
  1189. else {
  1190. resolved = TRUE;
  1191. }
  1192. while (!resolved) {
  1193. resolved = TRUE;
  1194. MemDbBuildKey (
  1195. pattern,
  1196. MEMDB_CATEGORY_REPORT_LINKS,
  1197. TEXT("*"),
  1198. linkStruct->LinkNameNoPath,
  1199. TEXT("*")
  1200. );
  1201. if (MemDbEnumFirstValue (&enumDups, pattern, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  1202. do {
  1203. linkDup = (PLINK_STRUCT)enumDups.dwValue;
  1204. if ((enumItems.Offset != enumDups.Offset) &&
  1205. (enumItems.UserFlags == enumDups.UserFlags) &&
  1206. (StringIMatch (linkStruct->Category, linkDup->Category))
  1207. ) {
  1208. if (newCategory) {
  1209. dupCategory = pBuildNewCategory (linkDup->LinkName, linkDup->Category, levels);
  1210. if (!dupCategory) {
  1211. MYASSERT (FALSE);
  1212. continue;
  1213. }
  1214. if (!StringIMatch (dupCategory, newCategory)) {
  1215. FreePathString (dupCategory);
  1216. continue;
  1217. }
  1218. FreePathString (newCategory);
  1219. }
  1220. levels++;
  1221. newCategory = pBuildNewCategory (linkStruct->LinkName, linkStruct->Category, levels);
  1222. resolved = FALSE;
  1223. break;
  1224. }
  1225. } while (MemDbEnumNextValue (&enumDups));
  1226. }
  1227. }
  1228. pReportEntry (
  1229. linkStruct->ReportEntry,
  1230. newCategory?newCategory:linkStruct->Category,
  1231. linkStruct->MigDbContext?linkStruct->MigDbContext->Message:NULL,
  1232. linkStruct->Context,
  1233. linkStruct->Object
  1234. );
  1235. if (newCategory) {
  1236. newCategory = NULL;
  1237. }
  1238. } while (MemDbEnumNextValue (&enumItems));
  1239. }
  1240. TickProgressBar ();
  1241. // gather default command prompt attributes
  1242. pGatherInfoFromDefaultPif ();
  1243. DoneLinkAnnounce ();
  1244. //
  1245. // Delete MemDb tree used for this phase
  1246. //
  1247. MemDbDeleteTree (MEMDB_CATEGORY_REPORT_LINKS);
  1248. return TRUE;
  1249. }
  1250. DWORD
  1251. ProcessLinks (
  1252. IN DWORD Request
  1253. )
  1254. {
  1255. switch (Request) {
  1256. case REQUEST_QUERYTICKS:
  1257. return TICKS_PROCESS_LINKS;
  1258. case REQUEST_RUN:
  1259. if (!pProcessLinks ()) {
  1260. return GetLastError ();
  1261. }
  1262. else {
  1263. return ERROR_SUCCESS;
  1264. }
  1265. default:
  1266. DEBUGMSG ((DBG_ERROR, "Bad parameter in ProcessLinks"));
  1267. }
  1268. return 0;
  1269. }
  1270. BOOL
  1271. pProcessCPLs (
  1272. VOID
  1273. )
  1274. {
  1275. CHAR pattern[MEMDB_MAX];
  1276. MEMDB_ENUM enumItems;
  1277. DWORD announcement;
  1278. PMIGDB_CONTEXT context;
  1279. MemDbBuildKey (pattern, MEMDB_CATEGORY_CPLS, TEXT("*"), NULL, NULL);
  1280. if (MemDbEnumFirstValue (&enumItems, pattern, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
  1281. do {
  1282. if ((IsFileMarkedForAnnounce (enumItems.szName)) &&
  1283. (IsDisplayableCPL (enumItems.szName))
  1284. ) {
  1285. announcement = GetFileAnnouncement (enumItems.szName);
  1286. context = (PMIGDB_CONTEXT) GetFileAnnouncementContext (enumItems.szName);
  1287. ReportControlPanelApplet (
  1288. enumItems.szName,
  1289. context,
  1290. announcement
  1291. );
  1292. }
  1293. }
  1294. while (MemDbEnumNextValue (&enumItems));
  1295. }
  1296. return TRUE;
  1297. }
  1298. DWORD
  1299. ProcessCPLs (
  1300. IN DWORD Request
  1301. )
  1302. {
  1303. switch (Request) {
  1304. case REQUEST_QUERYTICKS:
  1305. return TICKS_PROCESS_CPLS;
  1306. case REQUEST_RUN:
  1307. if (!pProcessCPLs ()) {
  1308. return GetLastError ();
  1309. }
  1310. else {
  1311. return ERROR_SUCCESS;
  1312. }
  1313. default:
  1314. DEBUGMSG ((DBG_ERROR, "Bad parameter in ProcessCPLs"));
  1315. }
  1316. return 0;
  1317. }