]> cygwin.com Git - cygwin-apps/cygutils.git/blob - src/readshortcut/readshortcut.c
Add readshortcut contribution (Rob Siklos)
[cygwin-apps/cygutils.git] / src / readshortcut / readshortcut.c
1 /*
2 * readshortcut for cygwin/windows
3 *
4 * Copyright (C) 2003 Rob Siklos
5 * http://www.cygwin.com/ml/cygwin/2003-08/msg00640.html
6 *
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.
10 *
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.
15 *
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
19 */
20
21
22
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
25 */
26
27 /* how to compile a standalone version:
28 *
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"
32 *
33 */
34
35
36 #if HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 #include "common.h"
40
41 /* moved to common.h */
42 /*
43 #include <stdio.h>
44 #include <popt.h>
45 */
46
47 #include <shlobj.h>
48 #include <olectlid.h>
49
50 #define PATH_UNIX 0
51 #define PATH_WIN 1
52
53 #define ERR_NONE 0
54 #define ERR_USER 1
55 #define ERR_SYS 2
56 #define ERR_WIN 3
57
58 #define SLGP_RAWPATH 0
59 #define SW_SHOWMINIMIZED_SEVEN 7
60
61 #define BUFF_SIZE 1024
62
63 static const char versionID[] = "1.0";
64
65 typedef struct optvals_s {
66 char * target_fname;
67
68 int show_field_names;
69 int pathType;
70
71 int show_target;
72 int show_working_dir;
73 int show_args;
74 int show_showCmd;
75 int show_icon;
76 int show_icon_offset;
77 int show_desc;
78 int show_all;
79
80 } optvals;
81
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);
84
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);
92
93 void formatPath (char * strPath, int format);
94 int readshortcut(optvals opts, poptContext optContext);
95
96 static char *program_name;
97
98 int main (int argc, const char **argv) {
99 poptContext optContext;
100 const char ** loose_args;
101 int rc;
102 int result = ERR_NONE;
103 optvals opts;
104 const char *tmp_str;
105
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 }
112 };
113
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 }
127 };
128
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 }
133 };
134
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]; }
139 else { tmp_str++; }
140 if ((program_name = strdup(tmp_str)) == NULL ) {
141 fprintf(stderr, "%s: memory allocation error\n", argv[0]);
142 exit(ERR_SYS);
143 }
144
145 /* set default values for options */
146 opts.target_fname = NULL;
147
148 opts.show_field_names = 0;
149 opts.pathType = PATH_UNIX;
150
151 opts.show_target = 0;
152 opts.show_working_dir = 0;
153 opts.show_args = 0;
154 opts.show_showCmd = 0;
155 opts.show_icon = 0;
156 opts.show_icon_offset = 0;
157 opts.show_desc = 0;
158 opts.show_all = 0;
159
160 /* set the pOpt context and help line */
161 optContext = poptGetContext(NULL, argc, argv, opt, 0);
162 poptSetOtherOptionHelp(optContext, "[OPTION]* SHORTCUT");
163
164 while ((rc = poptGetNextOpt(optContext)) > 0) {
165 switch (rc) {
166 case '?':
167 help(optContext, stdout, program_name);
168 goto exit;
169 case 'u':
170 usage(optContext, stdout, program_name);
171 goto exit;
172 case 'v':
173 version(optContext, stdout, program_name);
174 goto exit;
175 case 'l':
176 license(optContext, stdout, program_name);
177 goto exit;
178 }
179 }
180
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; }
185
186 /* get the remaining arguments */
187 loose_args = poptGetArgs(optContext);
188
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);
192 result = ERR_SYS;
193 goto exit;
194 }
195 loose_args++;
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);
201 result = ERR_USER;
202 } else {
203 /************** Main Program ***********/
204 result = readshortcut(opts, optContext);
205 }
206 } else {
207 fprintf(stderr, "%s: SHORTCUT not specified\n", program_name);
208 usage(optContext, stderr, program_name);
209 result = ERR_USER;
210 }
211
212 exit:
213 poptFreeContext(optContext);
214 free(program_name);
215 free(opts.target_fname);
216 return result;
217 }
218
219 int readshortcut(optvals opts, poptContext optContext) {
220 HRESULT hres;
221 IShellLink *shell_link;
222 IPersistFile *persist_file;
223 char strPath[MAX_PATH];
224 char strBuff[BUFF_SIZE];
225 int iBuff;
226
227 int result = ERR_NONE; /* the value to return on exit */
228
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);
236 return (ERR_SYS);
237 }
238 strcat (opts.target_fname, ".lnk");
239 }
240 }
241 else {
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);
245 return (ERR_SYS);
246 }
247 strcat (opts.target_fname, ".lnk");
248 }
249
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);
255 return (ERR_SYS);
256 }
257 cygwin_conv_to_full_win32_path (opts.target_fname, strTmpPath);
258 free (opts.target_fname);
259 opts.target_fname = strTmpPath;
260 }
261
262 hres = OleInitialize (NULL);
263 if (hres != S_FALSE && hres != S_OK) {
264 fprintf (stderr, "%s: Could not initialize OLE interface\n", program_name);
265 return (ERR_WIN);
266 }
267
268 /* Get a pointer to the IShellLink interface. */
269 hres = CoCreateInstance (&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (void **) &shell_link);
270
271 if (!SUCCEEDED(hres)) {
272 fprintf (stderr, "%s: CoCreateInstance failed\n", program_name);
273 return (ERR_WIN);
274 }
275
276 /* Get a pointer to the IPersistFile interface. */
277 hres = shell_link->lpVtbl->QueryInterface(shell_link, &IID_IPersistFile, (void **) &persist_file);
278
279 if (SUCCEEDED(hres)) {
280 WCHAR wsz[MAX_PATH];
281
282 /* Ensure that the string is Unicode. */
283 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)opts.target_fname, -1, wsz, MAX_PATH);
284
285 /* Load the shortcut. */
286 hres = persist_file->lpVtbl->Load(persist_file, wsz, STGM_READ);
287
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);
295 }
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);
301 }
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);
306 }
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: "); }
310
311 switch (iBuff) {
312 case SW_SHOWNORMAL:
313 printf("Normal\n");
314 break;
315 case SW_SHOWMINIMIZED:
316 case SW_SHOWMINIMIZED_SEVEN:
317 printf("Minimized\n");
318 break;
319 case SW_SHOWMAXIMIZED:
320 printf("Maximized\n");
321 break;
322 }
323 }
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);
330 }
331 if (opts.show_all || opts.show_icon_offset) {
332 if (opts.show_field_names) { printf("Icon Library Offset: "); }
333 printf("%d\n", iBuff);
334 }
335 }
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);
340 }
341 }
342 else {
343 fprintf (stderr, "%s: Load failed on %s\n", program_name, opts.target_fname);
344 result = ERR_WIN;
345 }
346
347 /* Release the pointer to the IPersistFile interface. */
348 persist_file->lpVtbl->Release(persist_file);
349 }
350 else {
351 fprintf (stderr, "%s: QueryInterface failed\n", program_name);
352 result = ERR_WIN;
353 }
354
355 /* Release the pointer to the IShellLink interface. */
356 shell_link->lpVtbl->Release(shell_link);
357
358 return(result);
359 }
360
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 */
364 else {
365 // convert to posix path
366 char strTmp[MAX_PATH];
367 strcpy(strTmp, strPath);
368 cygwin_conv_to_full_posix_path(strTmp, strPath);
369 }
370 }
371
372 static const char * getVersion() {
373 return versionID;
374 }
375
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");
379 }
380
381 static void printBottomDescription(FILE * f, char * name) {
382 fprintf(f, "\nNOTE: The SHORTCUT argument may be in Windows or Unix format.\n");
383 }
384
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");
390 fprintf(f, "\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");
395 fprintf(f, "\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");
399 fprintf(f, "\n");
400 fprintf(f, "See the COPYING file for license information.\n");
401 }
402
403 static void usage(poptContext optCon, FILE * f, char * name) {
404 poptPrintUsage(optCon, f, 0);
405 }
406
407 static void help(poptContext optCon, FILE * f, char * name) {
408 printTopDescription(f, name);
409 poptPrintHelp(optCon, f, 0);
410 printBottomDescription(f, name);
411 }
412
413 static void version(poptContext optCon, FILE * f, char * name) {
414 printTopDescription(f, name);
415 }
416
417 static void license(poptContext optCon, FILE * f, char * name) {
418 printTopDescription(f, name);
419 printLicense(f, name);
420 }
This page took 0.057075 seconds and 5 git commands to generate.