2 * readshortcut for cygwin/windows
4 * Copyright (C) 2003 Rob Siklos
5 * http://www.cygwin.com/ml/cygwin/2003-08/msg00640.html
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation in version 2 of the License.
11 * This program 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 /* http://www.rpm.org/dark_corners/popt/
24 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_int/shell_int_programming/shortcuts/shortcut.asp
27 /* how to compile a standalone version:
29 * - comment the config.h and common.h includes
30 * - uncomment the stdio and popt.h includes
31 * - run "gcc readshortcut.c -o readshortcut.exe -lpopt -luuid -lole32"
41 /* moved to common.h */
58 #define SLGP_RAWPATH 0
59 #define SW_SHOWMINIMIZED_SEVEN 7
61 #define BUFF_SIZE 1024
63 static const char versionID
[] = "1.0";
65 typedef struct optvals_s
{
82 void cygwin_conv_to_full_win32_path(const char *path
, char *win32_path
);
83 void cygwin_conv_to_full_posix_path(const char *path
, char *posix_path
);
85 static void printTopDescription(FILE * f
, char * name
);
86 static void printBottomDescription(FILE * f
, char * name
);
87 static const char * getVersion(void);
88 static void usage(poptContext optCon
, FILE * f
, char * name
);
89 static void help(poptContext optCon
, FILE * f
, char * name
);
90 static void version(poptContext optCon
, FILE * f
, char * name
);
91 static void license(poptContext optCon
, FILE * f
, char * name
);
93 void formatPath (char * strPath
, int format
);
94 int readshortcut(optvals opts
, poptContext optContext
);
96 static char *program_name
;
98 int main (int argc
, const char **argv
) {
99 poptContext optContext
;
100 const char ** loose_args
;
102 int result
= ERR_NONE
;
106 struct poptOption infoOptionsTable
[] = {
107 { "help", 'h', POPT_ARG_NONE
, NULL
, '?', "This message", NULL
},
108 { "usage", '\0', POPT_ARG_NONE
, NULL
, 'u', "Program usage", NULL
},
109 { "version", 'v', POPT_ARG_NONE
, NULL
, 'v', "Version information", NULL
},
110 { "license", '\0', POPT_ARG_NONE
, NULL
, 'l', "License information", NULL
},
111 { NULL
, '\0', 0, NULL
, 0, NULL
, NULL
}
114 struct poptOption outputOptionsTable
[] = {
115 { "fields", 'f', POPT_ARG_VAL
, &(opts
.show_field_names
), 1, "Show field names", NULL
},
116 { "unix", 'u', POPT_ARG_VAL
, &(opts
.pathType
), PATH_UNIX
, "Use Unix path format for display (default)", NULL
},
117 { "windows", 'w', POPT_ARG_VAL
, &(opts
.pathType
), PATH_WIN
, "Use Windows path format for display ", NULL
},
118 { "target", 't', POPT_ARG_VAL
, &(opts
.show_target
), 1, "Display shortcut target", NULL
},
119 { "working", 'g', POPT_ARG_VAL
, &(opts
.show_working_dir
), 1, "Display shortcut working directory", NULL
},
120 { "args", 'r', POPT_ARG_VAL
, &(opts
.show_args
), 1, "Display shortcut arguments", NULL
},
121 { "showcmd", 's', POPT_ARG_VAL
, &(opts
.show_showCmd
), 1, "Display shortcut \"show\" command value", NULL
},
122 { "icon", 'i', POPT_ARG_VAL
, &(opts
.show_icon
), 1, "Display icon library location", NULL
},
123 { "offset", 'j', POPT_ARG_VAL
, &(opts
.show_icon_offset
), 1, "Display icon library offset", NULL
},
124 { "desc", 'd', POPT_ARG_VAL
, &(opts
.show_desc
), 1, "Display shortcut description", NULL
},
125 { "all", 'a', POPT_ARG_VAL
, &(opts
.show_all
), 1, "Display all information", NULL
},
126 { NULL
, '\0', 0, NULL
, 0, NULL
, NULL
}
129 struct poptOption opt
[] = {
130 { NULL
, '\0', POPT_ARG_INCLUDE_TABLE
, outputOptionsTable
, 0, "Output options", NULL
},
131 { NULL
, '\0', POPT_ARG_INCLUDE_TABLE
, infoOptionsTable
, 0, "Information options (display a message and exit)", NULL
},
132 { NULL
, '\0', 0, NULL
, 0, NULL
, NULL
}
135 /* get the program name */
136 tmp_str
= strrchr (argv
[0], '/');
137 if (tmp_str
== NULL
) { tmp_str
= strrchr (argv
[0], '\\'); }
138 if (tmp_str
== NULL
) { tmp_str
= argv
[0]; }
140 if ((program_name
= strdup(tmp_str
)) == NULL
) {
141 fprintf(stderr
, "%s: memory allocation error\n", argv
[0]);
145 /* set default values for options */
146 opts
.target_fname
= NULL
;
148 opts
.show_field_names
= 0;
149 opts
.pathType
= PATH_UNIX
;
151 opts
.show_target
= 0;
152 opts
.show_working_dir
= 0;
154 opts
.show_showCmd
= 0;
156 opts
.show_icon_offset
= 0;
160 /* set the pOpt context and help line */
161 optContext
= poptGetContext(NULL
, argc
, argv
, opt
, 0);
162 poptSetOtherOptionHelp(optContext
, "[OPTION]* SHORTCUT");
164 while ((rc
= poptGetNextOpt(optContext
)) > 0) {
167 help(optContext
, stdout
, program_name
);
170 usage(optContext
, stdout
, program_name
);
173 version(optContext
, stdout
, program_name
);
176 license(optContext
, stdout
, program_name
);
181 // set show_target by default
182 if (!(opts
.show_all
+ opts
.show_target
+ opts
.show_working_dir
+ opts
.show_args
+
183 opts
.show_showCmd
+ opts
.show_icon
+ opts
.show_icon_offset
+
184 opts
.show_desc
)) { opts
.show_target
= 1; }
186 /* get the remaining arguments */
187 loose_args
= poptGetArgs(optContext
);
189 if (loose_args
&& *loose_args
) {
190 if ((opts
.target_fname
= strdup(*loose_args
)) == NULL
) {
191 fprintf(stderr
, "%s: memory allocation error\n", program_name
);
196 if (loose_args
&& *loose_args
) {
197 fprintf(stderr
, "%s: Too many arguments: ", program_name
);
198 while (*loose_args
) { fprintf(stderr
, "%s ", *loose_args
++); }
199 fprintf(stderr
, "\n");
200 usage(optContext
, stderr
, program_name
);
203 /************** Main Program ***********/
204 result
= readshortcut(opts
, optContext
);
207 fprintf(stderr
, "%s: SHORTCUT not specified\n", program_name
);
208 usage(optContext
, stderr
, program_name
);
213 poptFreeContext(optContext
);
215 free(opts
.target_fname
);
219 int readshortcut(optvals opts
, poptContext optContext
) {
221 IShellLink
*shell_link
;
222 IPersistFile
*persist_file
;
223 char strPath
[MAX_PATH
];
224 char strBuff
[BUFF_SIZE
];
227 int result
= ERR_NONE
; /* the value to return on exit */
229 /* Add suffix to link name if necessary */
230 if (strlen (opts
.target_fname
) > 4) {
231 int tmp
= strlen (opts
.target_fname
) - 4;
232 if (strncmp (opts
.target_fname
+ tmp
, ".lnk", 4) != 0) {
233 opts
.target_fname
= (char *)realloc(opts
.target_fname
, strlen(opts
.target_fname
) + 1 + 4);
234 if (opts
.target_fname
== NULL
) {
235 fprintf(stderr
, "%s: memory allocation error\n", program_name
);
238 strcat (opts
.target_fname
, ".lnk");
242 opts
.target_fname
= (char *)realloc(opts
.target_fname
, strlen(opts
.target_fname
) + 1 + 4);
243 if (opts
.target_fname
== NULL
) {
244 fprintf(stderr
, "%s: memory allocation error\n", program_name
);
247 strcat (opts
.target_fname
, ".lnk");
250 /* if there's no colon in the path, it's POSIX and we should convert to win32 */
251 if (strchr (opts
.target_fname
, ':') == NULL
) {
252 char *strTmpPath
= (char*)malloc(MAX_PATH
);
253 if (strTmpPath
== NULL
) {
254 fprintf(stderr
, "%s: memory allocation error\n", program_name
);
257 cygwin_conv_to_full_win32_path (opts
.target_fname
, strTmpPath
);
258 free (opts
.target_fname
);
259 opts
.target_fname
= strTmpPath
;
262 hres
= OleInitialize (NULL
);
263 if (hres
!= S_FALSE
&& hres
!= S_OK
) {
264 fprintf (stderr
, "%s: Could not initialize OLE interface\n", program_name
);
268 /* Get a pointer to the IShellLink interface. */
269 hres
= CoCreateInstance (&CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IShellLink
, (void **) &shell_link
);
271 if (!SUCCEEDED(hres
)) {
272 fprintf (stderr
, "%s: CoCreateInstance failed\n", program_name
);
276 /* Get a pointer to the IPersistFile interface. */
277 hres
= shell_link
->lpVtbl
->QueryInterface(shell_link
, &IID_IPersistFile
, (void **) &persist_file
);
279 if (SUCCEEDED(hres
)) {
282 /* Ensure that the string is Unicode. */
283 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)opts
.target_fname
, -1, wsz
, MAX_PATH
);
285 /* Load the shortcut. */
286 hres
= persist_file
->lpVtbl
->Load(persist_file
, wsz
, STGM_READ
);
288 if (SUCCEEDED(hres
)) {
289 /* read stuff from the link object and print it to the screen */
290 if (opts
.show_all
|| opts
.show_target
) {
291 shell_link
->lpVtbl
->GetPath(shell_link
, strPath
, MAX_PATH
, NULL
, SLGP_RAWPATH
);
292 if (opts
.show_field_names
) { printf("Target: "); }
293 formatPath(strPath
, opts
.pathType
);
294 printf("%s\n", strPath
);
296 if (opts
.show_all
|| opts
.show_working_dir
) {
297 shell_link
->lpVtbl
->GetWorkingDirectory(shell_link
, strPath
, MAX_PATH
);
298 if (opts
.show_field_names
) { printf("Working Directory: "); }
299 formatPath(strPath
, opts
.pathType
);
300 printf("%s\n", strPath
);
302 if (opts
.show_all
|| opts
.show_args
) {
303 shell_link
->lpVtbl
->GetArguments(shell_link
, strBuff
, BUFF_SIZE
);
304 if (opts
.show_field_names
) { printf("Arguments: "); }
305 printf("%s\n", strBuff
);
307 if (opts
.show_all
|| opts
.show_showCmd
) {
308 shell_link
->lpVtbl
->GetShowCmd(shell_link
, &iBuff
);
309 if (opts
.show_field_names
) { printf("Show Command: "); }
315 case SW_SHOWMINIMIZED
:
316 case SW_SHOWMINIMIZED_SEVEN
:
317 printf("Minimized\n");
319 case SW_SHOWMAXIMIZED
:
320 printf("Maximized\n");
324 if (opts
.show_all
|| opts
.show_icon
|| opts
.show_icon_offset
) {
325 shell_link
->lpVtbl
->GetIconLocation(shell_link
, strPath
, MAX_PATH
, &iBuff
);
326 if (opts
.show_all
|| opts
.show_icon
) {
327 if (opts
.show_field_names
) { printf("Icon Library: "); }
328 formatPath(strPath
, opts
.pathType
);
329 printf("%s\n", strPath
);
331 if (opts
.show_all
|| opts
.show_icon_offset
) {
332 if (opts
.show_field_names
) { printf("Icon Library Offset: "); }
333 printf("%d\n", iBuff
);
336 if (opts
.show_all
|| opts
.show_desc
) {
337 shell_link
->lpVtbl
->GetDescription(shell_link
, strBuff
, BUFF_SIZE
);
338 if (opts
.show_field_names
) { printf("Description: "); }
339 printf("%s\n", strBuff
);
343 fprintf (stderr
, "%s: Load failed on %s\n", program_name
, opts
.target_fname
);
347 /* Release the pointer to the IPersistFile interface. */
348 persist_file
->lpVtbl
->Release(persist_file
);
351 fprintf (stderr
, "%s: QueryInterface failed\n", program_name
);
355 /* Release the pointer to the IShellLink interface. */
356 shell_link
->lpVtbl
->Release(shell_link
);
361 /* change the path to the proper format */
362 void formatPath (char * strPath
, int format
) {
363 if (format
== PATH_WIN
) { return; } /* windows is the default */
365 // convert to posix path
366 char strTmp
[MAX_PATH
];
367 strcpy(strTmp
, strPath
);
368 cygwin_conv_to_full_posix_path(strTmp
, strPath
);
372 static const char * getVersion() {
376 static void printTopDescription(FILE * f
, char * name
) {
377 fprintf(f
, "%s version %s\n", name
, getVersion());
378 fprintf(f
, " Reads and outputs data from a Windows shortcut (.lnk) file.\n\n");
381 static void printBottomDescription(FILE * f
, char * name
) {
382 fprintf(f
, "\nNOTE: The SHORTCUT argument may be in Windows or Unix format.\n");
385 static void printLicense(FILE * f
, char * name
) {
386 fprintf(f
, "This program is free software; you can redistribute it and/or\n");
387 fprintf(f
, "modify it under the terms of the GNU General Public License\n");
388 fprintf(f
, "as published by the Free Software Foundation; either version 2\n");
389 fprintf(f
, "of the License, or (at your option) any later version.\n");
391 fprintf(f
, "This program is distributed in the hope that it will be useful,\n");
392 fprintf(f
, "but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
393 fprintf(f
, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
394 fprintf(f
, "GNU General Public License for more details.\n");
396 fprintf(f
, "You should have received a copy of the GNU General Public License\n");
397 fprintf(f
, "along with this program; if not, write to the Free Software\n");
398 fprintf(f
, "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n");
400 fprintf(f
, "See the COPYING file for license information.\n");
403 static void usage(poptContext optCon
, FILE * f
, char * name
) {
404 poptPrintUsage(optCon
, f
, 0);
407 static void help(poptContext optCon
, FILE * f
, char * name
) {
408 printTopDescription(f
, name
);
409 poptPrintHelp(optCon
, f
, 0);
410 printBottomDescription(f
, name
);
413 static void version(poptContext optCon
, FILE * f
, char * name
) {
414 printTopDescription(f
, name
);
417 static void license(poptContext optCon
, FILE * f
, char * name
) {
418 printTopDescription(f
, name
);
419 printLicense(f
, name
);