comctl32: Introduce _PSP structure to store HPROPSHEETPAGE data.
[wine.git] / tools / winedump / lnk.c
blob194b6b40403b57260af1034005a77efadf9a5539
1 /*
2 * Dump a shortcut (lnk) file
4 * Copyright 2005 Mike McCormack
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <fcntl.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winedump.h"
32 #include "pshpack1.h"
34 typedef enum {
35 SLDF_HAS_ID_LIST = 0x00000001,
36 SLDF_HAS_LINK_INFO = 0x00000002,
37 SLDF_HAS_NAME = 0x00000004,
38 SLDF_HAS_RELPATH = 0x00000008,
39 SLDF_HAS_WORKINGDIR = 0x00000010,
40 SLDF_HAS_ARGS = 0x00000020,
41 SLDF_HAS_ICONLOCATION = 0x00000040,
42 SLDF_UNICODE = 0x00000080,
43 SLDF_FORCE_NO_LINKINFO = 0x00000100,
44 SLDF_HAS_EXP_SZ = 0x00000200,
45 SLDF_RUN_IN_SEPARATE = 0x00000400,
46 SLDF_HAS_LOGO3ID = 0x00000800,
47 SLDF_HAS_DARWINID = 0x00001000,
48 SLDF_RUNAS_USER = 0x00002000,
49 SLDF_HAS_EXP_ICON_SZ = 0x00004000,
50 SLDF_NO_PIDL_ALIAS = 0x00008000,
51 SLDF_FORCE_UNCNAME = 0x00010000,
52 SLDF_RUN_WITH_SHIMLAYER = 0x00020000,
53 SLDF_FORCE_NO_LINKTRACK = 0x00040000,
54 SLDF_ENABLE_TARGET_METADATA = 0x00080000,
55 SLDF_DISABLE_KNOWNFOLDER_RELATIVE_TRACKING = 0x00200000,
56 SLDF_RESERVED = 0x80000000,
57 } SHELL_LINK_DATA_FLAGS;
59 #define EXP_SZ_LINK_SIG 0xa0000001
60 #define EXP_SPECIAL_FOLDER_SIG 0xa0000005
61 #define EXP_DARWIN_ID_SIG 0xa0000006
62 #define EXP_SZ_ICON_SIG 0xa0000007
63 #define EXP_PROPERTYSTORAGE_SIG 0xa0000009
65 typedef struct tagDATABLOCKHEADER
67 UINT cbSize;
68 UINT dwSignature;
69 } DATABLOCK_HEADER;
71 typedef struct _LINK_HEADER
73 UINT dwSize; /* 0x00 size of the header - 0x4c */
74 GUID MagicGuid; /* 0x04 is CLSID_ShellLink */
75 UINT dwFlags; /* 0x14 describes elements following */
76 UINT dwFileAttr; /* 0x18 attributes of the target file */
77 FILETIME Time1; /* 0x1c */
78 FILETIME Time2; /* 0x24 */
79 FILETIME Time3; /* 0x2c */
80 UINT dwFileLength; /* 0x34 File length */
81 UINT nIcon; /* 0x38 icon number */
82 UINT fStartup; /* 0x3c startup type */
83 UINT wHotKey; /* 0x40 hotkey */
84 UINT Unknown5; /* 0x44 */
85 UINT Unknown6; /* 0x48 */
86 } LINK_HEADER, * PLINK_HEADER;
88 typedef struct tagLINK_SZ_BLOCK
90 UINT size;
91 UINT magic;
92 CHAR bufA[MAX_PATH];
93 WCHAR bufW[MAX_PATH];
94 } LINK_SZ_BLOCK;
96 typedef struct tagLINK_PROPERTYSTORAGE_GUID
98 UINT size;
99 UINT magic;
100 GUID fmtid;
101 } LINK_PROPERTYSTORAGE_GUID;
103 typedef struct tagLINK_PROPERTYSTORAGE_VALUE
105 UINT size;
106 UINT pid;
107 BYTE unknown8;
108 UINT vt;
109 UINT unknown25;
110 } LINK_PROPERTYSTORAGE_VALUE;
112 typedef struct _LOCATION_INFO
114 UINT dwTotalSize;
115 UINT dwHeaderSize;
116 UINT dwFlags;
117 UINT dwVolTableOfs;
118 UINT dwLocalPathOfs;
119 UINT dwNetworkVolTableOfs;
120 UINT dwFinalPathOfs;
121 } LOCATION_INFO;
123 typedef struct _LOCAL_VOLUME_INFO
125 UINT dwSize;
126 UINT dwType;
127 UINT dwVolSerial;
128 UINT dwVolLabelOfs;
129 } LOCAL_VOLUME_INFO;
131 typedef struct _NETWORK_VOLUME_INFO
133 UINT dwSize;
134 UINT dwUnknown1;
135 UINT dwShareNameOfs;
136 UINT dwReserved;
137 UINT dwUnknown2;
138 } NETWORK_VOLUME_INFO;
140 typedef struct
142 UINT cbSize;
143 UINT dwSignature;
144 UINT idSpecialFolder;
145 UINT cbOffset;
146 } EXP_SPECIAL_FOLDER;
148 typedef struct lnk_string_tag
150 unsigned short size;
151 union {
152 unsigned short w[1];
153 unsigned char a[1];
154 } str;
155 } lnk_string;
157 #include "poppack.h"
159 static unsigned offset;
161 static const void* fetch_block(void)
163 const unsigned* u;
164 const void* ret;
166 if (!(u = PRD(offset, sizeof(*u)))) return 0;
167 if ((ret = PRD(offset, *u))) offset += *u;
168 return ret;
171 static const lnk_string* fetch_string(int unicode)
173 const unsigned short* s;
174 unsigned short len;
175 const void* ret;
177 if (!(s = PRD(offset, sizeof(*s)))) return 0;
178 len = *s * (unicode ? sizeof(WCHAR) : sizeof(char));
179 if ((ret = PRD(offset, sizeof(*s) + len))) offset += sizeof(*s) + len;
180 return ret;
184 static void dump_pidl(void)
186 const lnk_string *pidl;
187 int i, n = 0, sz = 0;
189 pidl = fetch_string(FALSE);
190 if (!pidl)
191 return;
193 printf("PIDL\n");
194 printf("----\n\n");
196 while(sz<pidl->size)
198 const lnk_string *segment = (const lnk_string*) &pidl->str.a[sz];
200 if(!segment->size)
201 break;
202 sz+=segment->size;
203 if(sz>pidl->size)
205 printf("bad pidl\n");
206 break;
208 n++;
209 printf("segment %d (%2d bytes) : ",n,segment->size);
210 for(i=0; i<segment->size; i++)
211 printf("%02x ",segment->str.a[i]);
212 printf("\n");
214 printf("\n");
217 static void dump_string(const char *what, int unicode)
219 const lnk_string *data;
220 unsigned sz;
222 data = fetch_string(unicode);
223 if (!data)
224 return;
225 printf("%s : ", what);
226 sz = data->size;
227 if (unicode)
228 while (sz) printf("%c", data->str.w[data->size - sz--]);
229 else
230 while (sz) printf("%c", data->str.a[data->size - sz--]);
231 printf("\n");
234 static void dump_location(void)
236 const LOCATION_INFO *loc;
237 const char *p;
239 loc = fetch_block();
240 if (!loc)
241 return;
242 p = (const char*)loc;
244 printf("Location\n");
245 printf("--------\n\n");
246 printf("Total size = %d\n", loc->dwTotalSize);
247 printf("Header size = %d\n", loc->dwHeaderSize);
248 printf("Flags = %08x\n", loc->dwFlags);
250 /* dump information about the local volume the link points to */
251 printf("Local volume ofs = %08x ", loc->dwVolTableOfs);
252 if (loc->dwVolTableOfs &&
253 loc->dwVolTableOfs + sizeof(LOCAL_VOLUME_INFO) < loc->dwTotalSize)
255 const LOCAL_VOLUME_INFO *vol = (const LOCAL_VOLUME_INFO *)&p[loc->dwVolTableOfs];
257 printf("size %d type %d serial %08x label %d ",
258 vol->dwSize, vol->dwType, vol->dwVolSerial, vol->dwVolLabelOfs);
259 if(vol->dwVolLabelOfs)
260 printf("(\"%s\")", &p[loc->dwVolTableOfs + vol->dwVolLabelOfs]);
262 printf("\n");
264 /* dump information about the network volume the link points to */
265 printf("Network volume ofs = %08x ", loc->dwNetworkVolTableOfs);
266 if (loc->dwNetworkVolTableOfs &&
267 loc->dwNetworkVolTableOfs + sizeof(NETWORK_VOLUME_INFO) < loc->dwTotalSize)
269 const NETWORK_VOLUME_INFO *vol = (const NETWORK_VOLUME_INFO *)&p[loc->dwNetworkVolTableOfs];
271 printf("size %d name %d ", vol->dwSize, vol->dwShareNameOfs);
272 if(vol->dwShareNameOfs)
273 printf("(\"%s\")", &p[loc->dwNetworkVolTableOfs + vol->dwShareNameOfs]);
275 printf("\n");
277 /* dump out the path the link points to */
278 printf("LocalPath ofs = %08x ", loc->dwLocalPathOfs);
279 if( loc->dwLocalPathOfs && (loc->dwLocalPathOfs < loc->dwTotalSize) )
280 printf("(\"%s\")", &p[loc->dwLocalPathOfs]);
281 printf("\n");
283 printf("Net Path ofs = %08x\n", loc->dwNetworkVolTableOfs);
284 printf("Final Path = %08x ", loc->dwFinalPathOfs);
285 if( loc->dwFinalPathOfs && (loc->dwFinalPathOfs < loc->dwTotalSize) )
286 printf("(\"%s\")", &p[loc->dwFinalPathOfs]);
287 printf("\n");
288 printf("\n");
291 static const unsigned char table_dec85[0x80] = {
292 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
293 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
294 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
295 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
296 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
297 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
298 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
299 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
302 static BOOL base85_to_guid( const char *str, LPGUID guid )
304 DWORD i, val = 0, base = 1, *p;
305 unsigned char ch;
307 p = (DWORD*) guid;
308 for( i=0; i<20; i++ )
310 if( (i%5) == 0 )
312 val = 0;
313 base = 1;
315 ch = str[i];
316 if( ch >= 0x80 )
317 return FALSE;
318 val += table_dec85[ch] * base;
319 if( table_dec85[ch] == 0xff )
320 return FALSE;
321 if( (i%5) == 4 )
322 p[i/5] = val;
323 base *= 85;
325 return TRUE;
328 static void dump_special_folder_block(const DATABLOCK_HEADER* bhdr)
330 const EXP_SPECIAL_FOLDER *sfb = (const EXP_SPECIAL_FOLDER*)bhdr;
331 printf("Special folder block\n");
332 printf("--------------------\n\n");
333 printf("folder = 0x%04x\n", sfb->idSpecialFolder);
334 printf("offset = %d\n", sfb->cbOffset);
335 printf("\n");
338 static void dump_sz_block(const DATABLOCK_HEADER* bhdr, const char* label)
340 const LINK_SZ_BLOCK *szp = (const LINK_SZ_BLOCK*)bhdr;
341 printf("String block\n");
342 printf("-----------\n\n");
343 printf("magic = %x\n", szp->magic);
344 printf("%s = %s\n", label, szp->bufA);
345 printf("\n");
348 static void dump_darwin_id(const DATABLOCK_HEADER* bhdr)
350 const LINK_SZ_BLOCK *szp = (const LINK_SZ_BLOCK*)bhdr;
351 char comp_str[40];
352 const char *feat, *comp, *prod_str, *feat_str;
353 GUID guid;
355 printf("Advertise Info\n");
356 printf("--------------\n\n");
357 printf("msi string = %s\n", szp->bufA);
359 if (base85_to_guid(szp->bufA, &guid))
360 prod_str = get_guid_str(&guid);
361 else
362 prod_str = "?";
364 comp = &szp->bufA[20];
365 feat = strchr(comp, '>');
366 if (!feat)
367 feat = strchr(comp, '<');
368 if (feat)
370 memcpy(comp_str, comp, feat - comp);
371 comp_str[feat-comp] = 0;
373 else
375 strcpy(comp_str, "?");
378 if (feat && feat[0] == '>' && base85_to_guid( &feat[1], &guid ))
379 feat_str = get_guid_str( &guid );
380 else
381 feat_str = "";
383 printf(" product: %s\n", prod_str);
384 printf(" component: %s\n", comp_str );
385 printf(" feature: %s\n", feat_str);
386 printf("\n");
389 static void dump_property_storage_value(const LINK_PROPERTYSTORAGE_VALUE *lnk_value_hdr,
390 DWORD data_size)
392 BOOL got_terminator = FALSE;
393 int i, value_size;
394 const unsigned char *value;
396 while (data_size >= sizeof(DWORD))
398 if (!lnk_value_hdr->size)
400 got_terminator = TRUE;
401 break;
404 if (lnk_value_hdr->size > data_size || lnk_value_hdr->size < sizeof(*lnk_value_hdr))
406 printf(" size: %d (invalid)\n", lnk_value_hdr->size);
407 return;
410 printf(" pid: %d\n", lnk_value_hdr->pid);
411 printf(" unknown8: %d\n", lnk_value_hdr->unknown8);
412 printf(" vartype: %d\n", lnk_value_hdr->vt);
413 printf(" unknown25: %d\n", lnk_value_hdr->unknown25);
415 value_size = lnk_value_hdr->size - sizeof(*lnk_value_hdr);
416 value = (const unsigned char*)(lnk_value_hdr+1);
418 printf(" value (%2d bytes) : ",value_size);
419 for(i=0; i<value_size; i++)
420 printf("%02x ",value[i]);
421 printf("\n\n");
423 data_size -= lnk_value_hdr->size;
424 lnk_value_hdr = (void*)((char*)lnk_value_hdr + lnk_value_hdr->size);
427 if (!got_terminator)
428 printf(" missing terminator!\n");
431 static void dump_property_storage(const DATABLOCK_HEADER* bhdr)
433 int data_size;
434 const LINK_PROPERTYSTORAGE_GUID *lnk_guid_hdr;
435 BOOL got_terminator = FALSE;
437 printf("Property Storage\n");
438 printf("--------------\n\n");
440 data_size=bhdr->cbSize-sizeof(*bhdr);
442 lnk_guid_hdr=(void*)((const char*)bhdr+sizeof(*bhdr));
444 while (data_size >= sizeof(DWORD))
446 if (!lnk_guid_hdr->size)
448 got_terminator = TRUE;
449 break;
452 if (lnk_guid_hdr->size > data_size || lnk_guid_hdr->size < sizeof(*lnk_guid_hdr))
454 printf("size: %d (invalid)\n", lnk_guid_hdr->size);
455 return;
458 if (lnk_guid_hdr->magic != 0x53505331)
459 printf("magic: %x\n", lnk_guid_hdr->magic);
461 printf("fmtid: %s\n", get_guid_str(&lnk_guid_hdr->fmtid));
463 dump_property_storage_value((void*)(lnk_guid_hdr + 1), lnk_guid_hdr->size - sizeof(*lnk_guid_hdr));
465 data_size -= lnk_guid_hdr->size;
467 lnk_guid_hdr = (void*)((char*)lnk_guid_hdr + lnk_guid_hdr->size);
470 if (!got_terminator)
471 printf("missing terminator!\n");
473 printf("\n");
476 static void dump_raw_block(const DATABLOCK_HEADER* bhdr)
478 int data_size;
480 printf("Raw Block\n");
481 printf("---------\n\n");
482 printf("size = %d\n", bhdr->cbSize);
483 printf("magic = %x\n", bhdr->dwSignature);
485 data_size=bhdr->cbSize-sizeof(*bhdr);
486 if (data_size > 0)
488 int i;
489 const unsigned char *data;
491 printf("data = ");
492 data=(const unsigned char*)bhdr+sizeof(*bhdr);
493 while (data_size > 0)
495 for (i=0; i < 16; i++)
497 if (i < data_size)
498 printf("%02x ", data[i]);
499 else
500 printf(" ");
502 for (i=0; i < data_size && i < 16; i++)
503 printf("%c", (data[i] >= 32 && data[i] < 128 ? data[i] : '.'));
504 printf("\n");
505 data_size-=16;
506 if (data_size <= 0)
507 break;
508 data+=16;
509 printf(" ");
512 printf("\n");
515 static const GUID CLSID_ShellLink = {0x00021401L, 0, 0, {0xC0,0,0,0,0,0,0,0x46}};
517 enum FileSig get_kind_lnk(void)
519 const LINK_HEADER* hdr;
521 hdr = PRD(0, sizeof(*hdr));
522 if (hdr && hdr->dwSize == sizeof(LINK_HEADER) &&
523 !memcmp(&hdr->MagicGuid, &CLSID_ShellLink, sizeof(GUID)))
524 return SIG_LNK;
525 return SIG_UNKNOWN;
528 void lnk_dump(void)
530 const LINK_HEADER* hdr;
531 const DATABLOCK_HEADER* bhdr;
532 UINT dwFlags;
534 offset = 0;
535 hdr = fetch_block();
536 if (!hdr)
537 return;
539 printf("Header\n");
540 printf("------\n\n");
541 printf("Size: %04x\n", hdr->dwSize);
542 printf("GUID: %s\n", get_guid_str(&hdr->MagicGuid));
544 printf("FileAttr: %08x\n", hdr->dwFileAttr);
545 printf("FileLength: %08x\n", hdr->dwFileLength);
546 printf("nIcon: %d\n", hdr->nIcon);
547 printf("Startup: %d\n", hdr->fStartup);
548 printf("HotKey: %08x\n", hdr->wHotKey);
549 printf("Unknown5: %08x\n", hdr->Unknown5);
550 printf("Unknown6: %08x\n", hdr->Unknown6);
552 /* dump out all the flags */
553 printf("Flags: %04x ( ", hdr->dwFlags);
554 dwFlags=hdr->dwFlags;
555 #define FLAG(x) do \
557 if (dwFlags & SLDF_##x) \
559 printf("%s ", #x); \
560 dwFlags&=~SLDF_##x; \
562 } while (0)
563 FLAG(HAS_ID_LIST);
564 FLAG(HAS_LINK_INFO);
565 FLAG(HAS_NAME);
566 FLAG(HAS_RELPATH);
567 FLAG(HAS_WORKINGDIR);
568 FLAG(HAS_ARGS);
569 FLAG(HAS_ICONLOCATION);
570 FLAG(UNICODE);
571 FLAG(FORCE_NO_LINKINFO);
572 FLAG(HAS_EXP_SZ);
573 FLAG(RUN_IN_SEPARATE);
574 FLAG(HAS_LOGO3ID);
575 FLAG(HAS_DARWINID);
576 FLAG(RUNAS_USER);
577 FLAG(HAS_EXP_ICON_SZ);
578 FLAG(NO_PIDL_ALIAS);
579 FLAG(FORCE_UNCNAME);
580 FLAG(RUN_WITH_SHIMLAYER);
581 FLAG(FORCE_NO_LINKTRACK);
582 FLAG(ENABLE_TARGET_METADATA);
583 FLAG(DISABLE_KNOWNFOLDER_RELATIVE_TRACKING);
584 FLAG(RESERVED);
585 #undef FLAG
586 if (dwFlags)
587 printf("+%04x", dwFlags);
588 printf(")\n");
590 printf("Length: %04x\n", hdr->dwFileLength);
591 printf("\n");
593 if (hdr->dwFlags & SLDF_HAS_ID_LIST)
594 dump_pidl();
595 if (hdr->dwFlags & SLDF_HAS_LINK_INFO)
596 dump_location();
597 if (hdr->dwFlags & SLDF_HAS_NAME)
598 dump_string("Description", hdr->dwFlags & SLDF_UNICODE);
599 if (hdr->dwFlags & SLDF_HAS_RELPATH)
600 dump_string("Relative path", hdr->dwFlags & SLDF_UNICODE);
601 if (hdr->dwFlags & SLDF_HAS_WORKINGDIR)
602 dump_string("Working directory", hdr->dwFlags & SLDF_UNICODE);
603 if (hdr->dwFlags & SLDF_HAS_ARGS)
604 dump_string("Arguments", hdr->dwFlags & SLDF_UNICODE);
605 if (hdr->dwFlags & SLDF_HAS_ICONLOCATION)
606 dump_string("Icon path", hdr->dwFlags & SLDF_UNICODE);
608 bhdr=fetch_block();
609 while (bhdr)
611 if (!bhdr->cbSize)
612 break;
613 switch (bhdr->dwSignature)
615 case EXP_SZ_LINK_SIG:
616 dump_sz_block(bhdr, "exp.link");
617 break;
618 case EXP_SPECIAL_FOLDER_SIG:
619 dump_special_folder_block(bhdr);
620 break;
621 case EXP_SZ_ICON_SIG:
622 dump_sz_block(bhdr, "icon");
623 break;
624 case EXP_DARWIN_ID_SIG:
625 dump_darwin_id(bhdr);
626 break;
627 case EXP_PROPERTYSTORAGE_SIG:
628 dump_property_storage(bhdr);
629 break;
630 default:
631 dump_raw_block(bhdr);
633 bhdr=fetch_block();