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.

400 lines
12 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. shllink.c
  5. Abstract:
  6. Functions to modify shell links (LNKs) and PIFs.
  7. Author:
  8. Mike Condra (mikeco) (Date unknown)
  9. Revision History:
  10. calinn 23-Sep-1998 Substantial redesign
  11. calinn 15-May-1998 added GetLnkTarget and GetPifTarget
  12. --*/
  13. #include "pch.h"
  14. #include "migmainp.h"
  15. #include <shlobjp.h>
  16. #include <shlguidp.h>
  17. #ifndef UNICODE
  18. #error UNICODE required for shllink.c
  19. #endif
  20. //
  21. // Static prototypes
  22. //
  23. BOOL
  24. pModifyLnkFile (
  25. IN PCTSTR ShortcutName,
  26. IN PCTSTR ShortcutTarget,
  27. IN PCTSTR ShortcutArgs,
  28. IN PCTSTR ShortcutWorkDir,
  29. IN PCTSTR ShortcutIconPath,
  30. IN INT ShortcutIconNr,
  31. IN PLNK_EXTRA_DATA ExtraData, OPTIONAL
  32. IN BOOL ForceToShowNormal
  33. )
  34. {
  35. PTSTR NewShortcutName;
  36. PTSTR fileExt;
  37. IShellLink *psl = NULL;
  38. IPersistFile *ppf = NULL;
  39. HRESULT comResult;
  40. if (FAILED (CoInitialize (NULL))) {
  41. return FALSE;
  42. }
  43. __try {
  44. if (!DoesFileExist (ShortcutName)) {
  45. __leave;
  46. }
  47. if (((ShortcutTarget == NULL) || (ShortcutTarget [0] == 0)) &&
  48. ((ShortcutWorkDir == NULL) || (ShortcutWorkDir [0] == 0)) &&
  49. ((ShortcutIconPath == NULL) || (ShortcutIconPath [0] == 0)) &&
  50. (ShortcutIconNr == 0) &&
  51. (ExtraData == NULL)
  52. ) {
  53. __leave;
  54. }
  55. if (ExtraData) {
  56. NewShortcutName = DuplicatePathString (ShortcutName, 0);
  57. fileExt = (PTSTR)GetFileExtensionFromPath (NewShortcutName);
  58. MYASSERT (fileExt);
  59. //
  60. // We know for sure that this had PIF as extension so this copy is safe
  61. //
  62. StringCopy (fileExt, TEXT("LNK"));
  63. } else {
  64. NewShortcutName = (PTSTR)ShortcutName;
  65. }
  66. comResult = CoCreateInstance (
  67. &CLSID_ShellLink,
  68. NULL,
  69. CLSCTX_INPROC_SERVER,
  70. &IID_IShellLink,
  71. (void **) &psl);
  72. if (comResult != S_OK) {
  73. LOG ((LOG_ERROR, "LINKEDIT: CoCreateInstance failed for %s", NewShortcutName));
  74. __leave;
  75. }
  76. comResult = psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile, (void **) &ppf);
  77. if (comResult != S_OK) {
  78. LOG ((LOG_ERROR, "LINKEDIT: QueryInterface failed for %s", NewShortcutName));
  79. __leave;
  80. }
  81. //
  82. // We only load if the file was really a LNK
  83. //
  84. if (!ExtraData) {
  85. comResult = ppf->lpVtbl->Load(ppf, NewShortcutName, STGM_READ);
  86. if (comResult != S_OK) {
  87. LOG ((LOG_ERROR, "LINKEDIT: Load failed for %s", NewShortcutName));
  88. __leave;
  89. }
  90. }
  91. if (ShortcutTarget != NULL) {
  92. comResult = psl->lpVtbl->SetPath (psl, ShortcutTarget);
  93. if (comResult != S_OK) {
  94. DEBUGMSG ((DBG_WARNING, "LINKEDIT: SetPath failed for %s", NewShortcutName));
  95. }
  96. }
  97. if (ShortcutArgs != NULL) {
  98. comResult = psl->lpVtbl->SetArguments (psl, ShortcutArgs);
  99. if (comResult != S_OK) {
  100. DEBUGMSG ((DBG_WARNING, "LINKEDIT: SetArguments failed for %s", ShortcutArgs));
  101. }
  102. }
  103. if (ShortcutWorkDir != NULL) {
  104. comResult = psl->lpVtbl->SetWorkingDirectory (psl, ShortcutWorkDir);
  105. if (comResult != S_OK) {
  106. DEBUGMSG ((DBG_WARNING, "LINKEDIT: SetWorkingDirectory failed for %s", NewShortcutName));
  107. }
  108. }
  109. if (ShortcutIconPath != NULL) {
  110. comResult = psl->lpVtbl->SetIconLocation (psl, ShortcutIconPath, ShortcutIconNr);
  111. if (comResult != S_OK) {
  112. DEBUGMSG ((DBG_WARNING, "LINKEDIT: SetIconLocation failed for %s", NewShortcutName));
  113. }
  114. }
  115. if (ForceToShowNormal) {
  116. comResult = psl->lpVtbl->SetShowCmd (psl, SW_SHOWNORMAL);
  117. if (comResult != S_OK) {
  118. DEBUGMSG ((DBG_WARNING, "LINKEDIT: SetShowCmd failed for %s", NewShortcutName));
  119. }
  120. }
  121. //
  122. // add NT_CONSOLE_PROPS here
  123. //
  124. if (ExtraData) {
  125. HRESULT hres;
  126. NT_CONSOLE_PROPS props;
  127. IShellLinkDataList *psldl;
  128. //
  129. // Get a pointer to the IShellLinkDataList interface.
  130. //
  131. hres = psl->lpVtbl->QueryInterface (psl, &IID_IShellLinkDataList, &psldl);
  132. if (!SUCCEEDED (hres)) {
  133. DEBUGMSG ((DBG_WARNING, "Cannot get IShellLinkDataList interface"));
  134. __leave;
  135. }
  136. ZeroMemory (&props, sizeof (NT_CONSOLE_PROPS));
  137. props.cbSize = sizeof (NT_CONSOLE_PROPS);
  138. props.dwSignature = NT_CONSOLE_PROPS_SIG;
  139. //
  140. // We know that no extra data exists in this LNK because we just created it.
  141. // We need to fill some good data for this console
  142. //
  143. props.wFillAttribute = 0x0007;
  144. props.wPopupFillAttribute = 0x00f5;
  145. props.dwScreenBufferSize.X = (SHORT)ExtraData->xSize;
  146. props.dwScreenBufferSize.Y = (SHORT)ExtraData->ySize;
  147. props.dwWindowSize.X = (SHORT)ExtraData->xSize;
  148. props.dwWindowSize.Y = (SHORT)ExtraData->ySize;
  149. props.dwWindowOrigin.X = 0;
  150. props.dwWindowOrigin.Y = 0;
  151. props.nFont = 0;
  152. props.nInputBufferSize = 0;
  153. props.dwFontSize.X = (UINT)ExtraData->xFontSize;
  154. props.dwFontSize.Y = (UINT)ExtraData->yFontSize;
  155. props.uFontFamily = ExtraData->FontFamily;
  156. props.uFontWeight = ExtraData->FontWeight;
  157. StringCopy (props.FaceName, ExtraData->FontName);
  158. props.uCursorSize = 0x0019;
  159. props.bFullScreen = ExtraData->FullScreen;
  160. props.bQuickEdit = ExtraData->QuickEdit;
  161. props.bInsertMode = FALSE;
  162. props.bAutoPosition = TRUE;
  163. props.uHistoryBufferSize = 0x0032;
  164. props.uNumberOfHistoryBuffers = 0x0004;
  165. props.bHistoryNoDup = FALSE;
  166. props.ColorTable [0] = 0x00000000;
  167. props.ColorTable [1] = 0x00800000;
  168. props.ColorTable [2] = 0x00008000;
  169. props.ColorTable [3] = 0x00808000;
  170. props.ColorTable [4] = 0x00000080;
  171. props.ColorTable [5] = 0x00800080;
  172. props.ColorTable [6] = 0x00008080;
  173. props.ColorTable [7] = 0x00c0c0c0;
  174. props.ColorTable [8] = 0x00808080;
  175. props.ColorTable [9] = 0x00ff0000;
  176. props.ColorTable [10] = 0x0000ff00;
  177. props.ColorTable [11] = 0x00ffff00;
  178. props.ColorTable [12] = 0x000000ff;
  179. props.ColorTable [13] = 0x00ff00ff;
  180. props.ColorTable [14] = 0x0000ffff;
  181. props.ColorTable [15] = 0x00ffffff;
  182. comResult = psldl->lpVtbl->AddDataBlock (psldl, &props);
  183. if (comResult != S_OK) {
  184. DEBUGMSG ((DBG_WARNING, "LINKEDIT: AddDataBlock failed for %s", NewShortcutName));
  185. }
  186. }
  187. comResult = ppf->lpVtbl->Save (ppf, NewShortcutName, FALSE);
  188. if (comResult != S_OK) {
  189. DEBUGMSG ((DBG_WARNING, "LINKEDIT: Save failed for %s", NewShortcutName));
  190. }
  191. if (ExtraData) {
  192. ForceOperationOnPath (ShortcutName, OPERATION_CLEANUP);
  193. }
  194. comResult = ppf->lpVtbl->SaveCompleted (ppf, NewShortcutName);
  195. if (comResult != S_OK) {
  196. DEBUGMSG ((DBG_WARNING, "LINKEDIT: SaveCompleted failed for %s", NewShortcutName));
  197. }
  198. }
  199. __finally {
  200. if (ppf != NULL) {
  201. ppf->lpVtbl->Release (ppf);
  202. ppf = NULL;
  203. }
  204. if (psl != NULL) {
  205. psl->lpVtbl->Release (psl);
  206. psl = NULL;
  207. }
  208. CoUninitialize ();
  209. }
  210. return TRUE;
  211. }
  212. BOOL
  213. pModifyPifFile (
  214. IN PCTSTR ShortcutName,
  215. IN PCTSTR ShortcutTarget,
  216. IN PCTSTR ShortcutArgs,
  217. IN PCTSTR ShortcutWorkDir,
  218. IN PCTSTR ShortcutIconPath,
  219. IN INT ShortcutIconNr
  220. )
  221. {
  222. PCSTR fileImage = NULL;
  223. HANDLE mapHandle = NULL;
  224. HANDLE fileHandle = INVALID_HANDLE_VALUE;
  225. PCSTR AnsiStr = NULL;
  226. PSTDPIF stdPif;
  227. PWENHPIF40 wenhPif40;
  228. PW386PIF30 w386ext30;
  229. __try {
  230. fileImage = MapFileIntoMemoryEx (ShortcutName, &fileHandle, &mapHandle, TRUE);
  231. if (fileImage == NULL) {
  232. __leave;
  233. }
  234. __try {
  235. stdPif = (PSTDPIF) fileImage;
  236. if (ShortcutTarget != NULL) {
  237. AnsiStr = CreateDbcs (ShortcutTarget);
  238. strncpy (stdPif->startfile, AnsiStr, PIFSTARTLOCSIZE);
  239. DestroyDbcs (AnsiStr);
  240. }
  241. if (ShortcutArgs != NULL) {
  242. AnsiStr = CreateDbcs (ShortcutArgs);
  243. strncpy (stdPif->params, AnsiStr, PIFPARAMSSIZE);
  244. DestroyDbcs (AnsiStr);
  245. }
  246. if (ShortcutWorkDir != NULL) {
  247. AnsiStr = CreateDbcs (ShortcutWorkDir);
  248. strncpy (stdPif->defpath, AnsiStr, PIFDEFPATHSIZE);
  249. DestroyDbcs (AnsiStr);
  250. }
  251. if (ShortcutIconPath != NULL) {
  252. wenhPif40 = (PWENHPIF40) FindEnhPifSignature ((PVOID)fileImage, WENHHDRSIG40);
  253. if (wenhPif40 != NULL) {
  254. AnsiStr = CreateDbcs (ShortcutIconPath);
  255. strncpy (wenhPif40->achIconFileProp, AnsiStr, PIFDEFFILESIZE);
  256. DestroyDbcs (AnsiStr);
  257. wenhPif40->wIconIndexProp = (WORD)ShortcutIconNr;
  258. }
  259. }
  260. // in all cases we want to take off MSDOS mode otherwise NT won't start these PIFs
  261. w386ext30 = FindEnhPifSignature ((PVOID)fileImage, W386HDRSIG30);
  262. if (w386ext30) {
  263. w386ext30->PfW386Flags = w386ext30->PfW386Flags & (~fRealMode);
  264. w386ext30->PfW386Flags = w386ext30->PfW386Flags & (~fRealModeSilent);
  265. }
  266. }
  267. __except (1) {
  268. // something went wrong when we tried to read or write PIF file,
  269. // let's just do nothing and exit from here
  270. DEBUGMSG ((DBG_WARNING, "Exception thrown when processing %s", ShortcutName));
  271. }
  272. }
  273. __finally {
  274. UnmapFile ((PVOID) fileImage, mapHandle, fileHandle);
  275. }
  276. return TRUE;
  277. }
  278. BOOL
  279. ModifyShellLink(
  280. IN PCWSTR ShortcutName,
  281. IN PCWSTR ShortcutTarget,
  282. IN PCWSTR ShortcutArgs,
  283. IN PCWSTR ShortcutWorkDir,
  284. IN PCWSTR ShortcutIconPath,
  285. IN INT ShortcutIconNr,
  286. IN BOOL ConvertToLnk,
  287. IN PLNK_EXTRA_DATA ExtraData, OPTIONAL
  288. IN BOOL ForceToShowNormal
  289. )
  290. {
  291. PCTSTR shortcutExt;
  292. __try {
  293. shortcutExt = GetFileExtensionFromPath (ShortcutName);
  294. MYASSERT (shortcutExt);
  295. if (StringIMatch (shortcutExt, TEXT("LNK"))) {
  296. return pModifyLnkFile (
  297. ShortcutName,
  298. ShortcutTarget,
  299. ShortcutArgs,
  300. ShortcutWorkDir,
  301. ShortcutIconPath,
  302. ShortcutIconNr,
  303. NULL,
  304. ForceToShowNormal
  305. );
  306. } else if (StringIMatch (shortcutExt, TEXT("PIF"))) {
  307. if (ConvertToLnk) {
  308. MYASSERT (ExtraData);
  309. return pModifyLnkFile (
  310. ShortcutName,
  311. ShortcutTarget,
  312. ShortcutArgs,
  313. ShortcutWorkDir,
  314. ShortcutIconPath,
  315. ShortcutIconNr,
  316. ExtraData,
  317. ForceToShowNormal
  318. );
  319. } else {
  320. return pModifyPifFile (
  321. ShortcutName,
  322. ShortcutTarget,
  323. ShortcutArgs,
  324. ShortcutWorkDir,
  325. ShortcutIconPath,
  326. ShortcutIconNr
  327. );
  328. }
  329. }
  330. }
  331. __except (1) {
  332. LOG ((LOG_ERROR, "Cannot process shortcut %s", ShortcutName));
  333. }
  334. return TRUE;
  335. }