]>
Commit | Line | Data |
---|---|---|
c4453a3d | 1 | /* mkshortcut.c -- create a Windows shortcut |
0bb67178 | 2 | * |
0bb67178 CW |
3 | * Copyright (c) 2002 Joshua Daniel Franklin |
4 | * | |
3a076f8e CW |
5 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
0bb67178 CW |
9 | * |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
3a076f8e | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
0bb67178 CW |
13 | * GNU General Public License for more details. |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
3a076f8e | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
0bb67178 | 17 | * |
3a076f8e | 18 | * See the COPYING file for full license information. |
0bb67178 CW |
19 | * |
20 | * Exit values | |
21 | * 1: user error (syntax error) | |
22 | * 2: system error (out of memory, etc.) | |
23 | * 3: windows error (interface failed) | |
c4453a3d CW |
24 | * |
25 | * Compile with: gcc -o prog.exe mkshortcut.c -lpopt -lole32 -luuid | |
7ab0751f | 26 | * (You'd need to uncomment the moved to common.h lines.) |
0bb67178 CW |
27 | * |
28 | */ | |
c4453a3d | 29 | |
0bb67178 | 30 | #if HAVE_CONFIG_H |
fe3a7d70 | 31 | # include "config.h" |
b96d6602 | 32 | #endif |
0bb67178 | 33 | #include "common.h" |
5f56ef9c CW |
34 | |
35 | #define NOCOMATTRIBUTE | |
36 | ||
37 | #include <shlobj.h> | |
38 | #include <olectlid.h> | |
0bb67178 CW |
39 | /* moved to common.h */ |
40 | /* | |
5f56ef9c | 41 | #include <stdio.h> |
c4453a3d | 42 | #include <popt.h> |
0bb67178 | 43 | */ |
d2d984ab | 44 | #include <sys/cygwin.h> |
0bb67178 | 45 | |
b96d6602 | 46 | static const char versionID[] = PACKAGE_VERSION; |
0bb67178 | 47 | static const char revID[] = |
7ab0751f | 48 | "$Id$"; |
0bb67178 | 49 | static const char copyrightID[] = |
7ab0751f | 50 | "Copyright (c) 2002\nJoshua Daniel Franklin. All rights reserved.\nLicensed under GPL v2.0\n"; |
5f56ef9c | 51 | |
fe3a7d70 CW |
52 | typedef struct optvals_s |
53 | { | |
c4453a3d CW |
54 | int icon_flag; |
55 | int unix_flag; | |
56 | int windows_flag; | |
57 | int allusers_flag; | |
58 | int desktop_flag; | |
59 | int smprograms_flag; | |
6d007d60 | 60 | int show_flag; |
c4453a3d | 61 | int offset; |
fe3a7d70 CW |
62 | char *name_arg; |
63 | char *desc_arg; | |
64 | char *dir_name_arg; | |
65 | char *argument_arg; | |
66 | char *target_arg; | |
67 | char *icon_name_arg; | |
c4453a3d | 68 | } optvals; |
5f56ef9c | 69 | |
a4905427 | 70 | static int mkshortcut (optvals opts); |
fe3a7d70 CW |
71 | static void printTopDescription (FILE * f, char *name); |
72 | static void printBottomDescription (FILE * f, char *name); | |
73 | static const char *getVersion (); | |
a4905427 CW |
74 | static void usage (FILE * f, char *name); |
75 | static void help (FILE * f, char *name); | |
76 | static void version (FILE * f, char *name); | |
77 | static void license (FILE * f, char *name); | |
c4453a3d CW |
78 | |
79 | static char *program_name; | |
a4905427 | 80 | static poptContext optCon; |
c4453a3d CW |
81 | |
82 | int | |
83 | main (int argc, const char **argv) | |
7ab0751f | 84 | { |
fe3a7d70 | 85 | const char **rest; |
c4453a3d CW |
86 | int rc; |
87 | int ec = 0; | |
88 | optvals opts; | |
89 | ||
90 | const char *tmp_str; | |
91 | int icon_offset_flag; | |
92 | char icon_name[MAX_PATH]; | |
fe3a7d70 | 93 | const char *arg; |
c4453a3d CW |
94 | |
95 | struct poptOption helpOptionsTable[] = { | |
fe3a7d70 CW |
96 | {"help", 'h', POPT_ARG_NONE, NULL, '?', |
97 | "Show this help message", NULL}, | |
98 | {"usage", '\0', POPT_ARG_NONE, NULL, 'u', | |
99 | "Display brief usage message", NULL}, | |
100 | {"version", 'v', POPT_ARG_NONE, NULL, 'v', | |
101 | "Display version information", NULL}, | |
102 | {"license", '\0', POPT_ARG_NONE, NULL, 'l', | |
103 | "Display licensing information", NULL}, | |
104 | {NULL, '\0', 0, NULL, 0, NULL, NULL} | |
c4453a3d CW |
105 | }; |
106 | ||
107 | struct poptOption generalOptionsTable[] = { | |
fe3a7d70 CW |
108 | {"arguments", 'a', POPT_ARG_STRING, NULL, 'a', |
109 | "Use arguments ARGS", "ARGS"}, | |
110 | {"desc", 'd', POPT_ARG_STRING, NULL, 'd', | |
111 | "Text for description/tooltip (defaults to POSIX path of TARGET)", | |
112 | "DESC"}, | |
113 | {"icon", 'i', POPT_ARG_STRING, NULL, 'i', | |
114 | "Icon file for link to use", "ICONFILE"}, | |
115 | {"iconoffset", 'j', POPT_ARG_INT, &(opts.offset), 'j', | |
116 | "Offset of icon in icon file (default is 0)", NULL}, | |
117 | {"name", 'n', POPT_ARG_STRING, NULL, 'n', | |
118 | "Name for link (defaults to TARGET)", "NAME"}, | |
119 | {"show", 's', POPT_ARG_STRING, NULL, 's', | |
120 | "Window to show: normal, minimized, maximized", "norm|min|max"}, | |
121 | {"workingdir", 'w', POPT_ARG_STRING, NULL, 'w', | |
122 | "Set working directory (defaults to directory path of TARGET)", "PATH"}, | |
123 | {"allusers", 'A', POPT_ARG_VAL, &(opts.allusers_flag), 1, | |
124 | "Use 'All Users' instead of current user for -D,-P", NULL}, | |
125 | {"desktop", 'D', POPT_ARG_VAL, &(opts.desktop_flag), 1, | |
126 | "Create link relative to 'Desktop' directory", NULL}, | |
127 | {"smprograms", 'P', POPT_ARG_VAL, &(opts.smprograms_flag), 1, | |
128 | "Create link relative to Start Menu 'Programs' directory", NULL}, | |
129 | {NULL, '\0', 0, NULL, 0, NULL, NULL} | |
c4453a3d | 130 | }; |
fe3a7d70 | 131 | |
c4453a3d | 132 | struct poptOption opt[] = { |
fe3a7d70 CW |
133 | {NULL, '\0', POPT_ARG_INCLUDE_TABLE, generalOptionsTable, 0, |
134 | "General options", NULL}, | |
135 | {NULL, '\0', POPT_ARG_INCLUDE_TABLE, helpOptionsTable, 0, | |
136 | "Help options", NULL}, | |
137 | {NULL, '\0', 0, NULL, 0, NULL, NULL} | |
c4453a3d CW |
138 | }; |
139 | ||
140 | tmp_str = strrchr (argv[0], '/'); | |
fe3a7d70 CW |
141 | if (tmp_str == NULL) |
142 | { | |
143 | tmp_str = strrchr (argv[0], '\\'); | |
144 | } | |
145 | if (tmp_str == NULL) | |
146 | { | |
147 | tmp_str = argv[0]; | |
148 | } | |
149 | else | |
150 | { | |
151 | tmp_str++; | |
152 | } | |
153 | if ((program_name = strdup (tmp_str)) == NULL) | |
154 | { | |
155 | fprintf (stderr, "%s: memory allocation error\n", argv[0]); | |
156 | exit (2); | |
157 | } | |
c4453a3d CW |
158 | |
159 | icon_offset_flag = 0; | |
160 | ||
161 | opts.offset = 0; | |
162 | opts.icon_flag = 0; | |
163 | opts.unix_flag = 0; | |
164 | opts.windows_flag = 0; | |
165 | opts.allusers_flag = 0; | |
166 | opts.desktop_flag = 0; | |
167 | opts.smprograms_flag = 0; | |
6d007d60 | 168 | opts.show_flag = SW_SHOWNORMAL; |
c4453a3d CW |
169 | opts.target_arg = NULL; |
170 | opts.argument_arg = NULL; | |
171 | opts.name_arg = NULL; | |
08cb7edc | 172 | opts.desc_arg = NULL; |
b2682e03 | 173 | opts.dir_name_arg = NULL; |
c4453a3d CW |
174 | opts.icon_name_arg = NULL; |
175 | ||
176 | /* Parse options */ | |
fe3a7d70 CW |
177 | optCon = poptGetContext (NULL, argc, argv, opt, 0); |
178 | poptSetOtherOptionHelp (optCon, "[OPTION]* TARGET"); | |
179 | while ((rc = poptGetNextOpt (optCon)) > 0) | |
180 | { | |
181 | switch (rc) | |
182 | { | |
183 | case '?': | |
a4905427 | 184 | help (stdout, program_name); |
fe3a7d70 CW |
185 | goto exit; |
186 | case 'u': | |
a4905427 | 187 | usage (stdout, program_name); |
fe3a7d70 CW |
188 | goto exit; |
189 | case 'v': | |
a4905427 | 190 | version (stdout, program_name); |
fe3a7d70 CW |
191 | goto exit; |
192 | case 'l': | |
a4905427 | 193 | license (stdout, program_name); |
fe3a7d70 CW |
194 | goto exit; |
195 | case 'd': | |
196 | if (arg = poptGetOptArg (optCon)) | |
197 | { | |
198 | if ((opts.desc_arg = strdup (arg)) == NULL) | |
199 | { | |
200 | fprintf (stderr, "%s: memory allocation error\n", | |
201 | program_name); | |
202 | ec = 2; | |
203 | goto exit; | |
204 | } | |
205 | } | |
206 | break; | |
207 | case 'i': | |
208 | opts.icon_flag = 1; | |
209 | if (arg = poptGetOptArg (optCon)) | |
210 | { | |
211 | cygwin_conv_to_full_win32_path (arg, icon_name); | |
212 | if ((opts.icon_name_arg = strdup (icon_name)) == NULL) | |
213 | { | |
214 | fprintf (stderr, "%s: memory allocation error\n", | |
215 | program_name); | |
216 | ec = 2; | |
217 | goto exit; | |
218 | } | |
219 | } | |
220 | break; | |
221 | case 'j': | |
222 | icon_offset_flag = 1; | |
223 | break; | |
224 | case 'n': | |
225 | if (arg = poptGetOptArg (optCon)) | |
226 | { | |
227 | if ((opts.name_arg = strdup (arg)) == NULL) | |
228 | { | |
229 | fprintf (stderr, "%s: memory allocation error\n", | |
230 | program_name); | |
231 | ec = 2; | |
232 | goto exit; | |
233 | } | |
234 | } | |
235 | break; | |
236 | case 's': | |
237 | if (arg = poptGetOptArg (optCon)) | |
238 | { | |
239 | if (strcmp (arg, "min") == 0) | |
240 | { | |
241 | opts.show_flag = SW_SHOWMINNOACTIVE; | |
242 | } | |
243 | else if (strcmp (arg, "max") == 0) | |
244 | { | |
245 | opts.show_flag = SW_SHOWMAXIMIZED; | |
246 | } | |
247 | else if (strcmp (arg, "norm") == 0) | |
248 | { | |
249 | opts.show_flag = SW_SHOWNORMAL; | |
250 | } | |
251 | else | |
252 | { | |
253 | fprintf (stderr, "%s: %s not valid for show window\n", | |
254 | program_name, arg); | |
255 | ec = 2; | |
256 | goto exit; | |
257 | } | |
258 | } | |
259 | break; | |
260 | case 'w': | |
261 | if (arg = poptGetOptArg (optCon)) | |
262 | { | |
263 | if ((opts.dir_name_arg = strdup (arg)) == NULL) | |
264 | { | |
265 | fprintf (stderr, "%s: memory allocation error\n", | |
266 | program_name); | |
267 | ec = 2; | |
268 | goto exit; | |
269 | } | |
270 | } | |
271 | break; | |
272 | case 'a': | |
273 | if (arg = poptGetOptArg (optCon)) | |
274 | { | |
275 | if ((opts.argument_arg = strdup (arg)) == NULL) | |
276 | { | |
277 | fprintf (stderr, "%s: memory allocation error\n", | |
278 | program_name); | |
279 | ec = 2; | |
280 | goto exit; | |
281 | } | |
282 | } | |
283 | break; | |
284 | // case 'A' | |
285 | // case 'D' | |
286 | // case 'P' all handled by popt itself | |
287 | } | |
288 | } | |
289 | ||
290 | if (icon_offset_flag & !opts.icon_flag) | |
291 | { | |
292 | fprintf (stderr, | |
293 | "%s: --iconoffset|-j only valid in conjuction with --icon|-i\n", | |
294 | program_name); | |
a4905427 | 295 | usage (stderr, program_name); |
fe3a7d70 | 296 | ec = 1; |
c4453a3d | 297 | goto exit; |
7ab0751f | 298 | } |
fe3a7d70 CW |
299 | |
300 | if (opts.smprograms_flag && opts.desktop_flag) | |
301 | { | |
302 | fprintf (stderr, | |
303 | "%s: --smprograms|-P not valid in conjuction with --desktop|-D\n", | |
304 | program_name); | |
a4905427 | 305 | usage (stderr, program_name); |
fe3a7d70 CW |
306 | ec = 1; |
307 | goto exit; | |
308 | } | |
309 | ||
310 | if (rc < -1) | |
311 | { | |
312 | fprintf (stderr, "%s: bad argument %s: %s\n", | |
313 | program_name, poptBadOption (optCon, POPT_BADOPTION_NOALIAS), | |
314 | poptStrerror (rc)); | |
315 | ec = 1; | |
316 | goto exit; | |
317 | } | |
318 | ||
319 | rest = poptGetArgs (optCon); | |
320 | ||
321 | if (rest && *rest) | |
322 | { | |
323 | if ((opts.target_arg = strdup (*rest)) == NULL) | |
324 | { | |
325 | fprintf (stderr, "%s: memory allocation error\n", program_name); | |
326 | ec = 2; | |
327 | goto exit; | |
328 | } | |
329 | rest++; | |
330 | if (rest && *rest) | |
331 | { | |
332 | fprintf (stderr, "%s: Too many arguments: ", program_name); | |
333 | while (*rest) | |
334 | fprintf (stderr, "%s ", *rest++); | |
335 | fprintf (stderr, "\n"); | |
a4905427 | 336 | usage (stderr, program_name); |
fe3a7d70 CW |
337 | ec = 1; |
338 | } | |
339 | else | |
340 | { | |
341 | // THE MEAT GOES HERE | |
a4905427 | 342 | ec = mkshortcut (opts); |
fe3a7d70 CW |
343 | } |
344 | } | |
345 | else | |
346 | { | |
347 | fprintf (stderr, "%s: TARGET not specified\n", program_name); | |
a4905427 | 348 | usage (stderr, program_name); |
fe3a7d70 | 349 | ec = 1; |
08cb7edc | 350 | } |
c4453a3d CW |
351 | |
352 | exit: | |
fe3a7d70 CW |
353 | poptFreeContext (optCon); |
354 | if (opts.target_arg) | |
355 | { | |
356 | free (opts.target_arg); | |
357 | } | |
358 | if (opts.name_arg) | |
359 | { | |
360 | free (opts.name_arg); | |
361 | } | |
362 | if (opts.desc_arg) | |
363 | { | |
364 | free (opts.desc_arg); | |
365 | } | |
366 | if (opts.dir_name_arg) | |
367 | { | |
368 | free (opts.dir_name_arg); | |
369 | } | |
370 | if (opts.argument_arg) | |
371 | { | |
372 | free (opts.argument_arg); | |
373 | } | |
374 | if (opts.icon_name_arg) | |
375 | { | |
376 | free (opts.icon_name_arg); | |
377 | } | |
378 | free (program_name); | |
379 | return (ec); | |
7ab0751f CW |
380 | } |
381 | ||
fe3a7d70 | 382 | int |
a4905427 | 383 | mkshortcut (optvals opts) |
5f56ef9c | 384 | { |
7ab0751f CW |
385 | char link_name[MAX_PATH]; |
386 | char exe_name[MAX_PATH]; | |
387 | char dir_name[MAX_PATH]; | |
08cb7edc | 388 | char desc[MAX_PATH]; |
c4453a3d CW |
389 | char *buf_str, *tmp_str; |
390 | int tmp; | |
7ab0751f CW |
391 | |
392 | /* For OLE interface */ | |
5f56ef9c CW |
393 | LPITEMIDLIST id; |
394 | HRESULT hres; | |
7ab0751f CW |
395 | IShellLink *shell_link; |
396 | IPersistFile *persist_file; | |
5f56ef9c CW |
397 | WCHAR widepath[MAX_PATH]; |
398 | ||
7ab0751f | 399 | buf_str = (char *) malloc (PATH_MAX); |
fe3a7d70 CW |
400 | if (buf_str == NULL) |
401 | { | |
402 | fprintf (stderr, "%s: out of memory\n", program_name); | |
403 | return (2); | |
404 | } | |
5f56ef9c | 405 | |
7ab0751f | 406 | /* If there's a colon in the TARGET, it should be a URL */ |
c4453a3d | 407 | if (strchr (opts.target_arg, ':') != NULL) |
7ab0751f CW |
408 | { |
409 | /* Nope, somebody's trying a W32 path */ | |
fe3a7d70 CW |
410 | if (opts.target_arg[1] == ':') |
411 | { | |
412 | free (buf_str); | |
413 | fprintf (stderr, "%s: all paths must be in POSIX format\n", | |
414 | program_name); | |
a4905427 | 415 | usage (stderr, program_name); |
fe3a7d70 CW |
416 | return (1); |
417 | } | |
c4453a3d | 418 | strcpy (exe_name, opts.target_arg); |
fe3a7d70 | 419 | dir_name[0] = '\0'; /* No working dir for URL */ |
7ab0751f CW |
420 | } |
421 | /* Convert TARGET to win32 path */ | |
5f56ef9c | 422 | else |
7ab0751f | 423 | { |
c4453a3d | 424 | strcpy (buf_str, opts.target_arg); |
7ab0751f | 425 | cygwin_conv_to_full_win32_path (buf_str, exe_name); |
5f56ef9c | 426 | |
b2682e03 CW |
427 | /* Get a working dir from 'w' option */ |
428 | if (opts.dir_name_arg != NULL) | |
429 | { | |
430 | if (strchr (opts.dir_name_arg, ':') != NULL) | |
431 | { | |
08cb7edc | 432 | free (buf_str); |
fe3a7d70 CW |
433 | fprintf (stderr, "%s: all paths must be in POSIX format\n", |
434 | program_name); | |
a4905427 | 435 | usage (stderr, program_name); |
fe3a7d70 | 436 | return (1); |
b2682e03 CW |
437 | } |
438 | cygwin_conv_to_win32_path (opts.dir_name_arg, dir_name); | |
439 | } | |
7ab0751f | 440 | /* Get a working dir from the exepath */ |
b2682e03 CW |
441 | else |
442 | { | |
443 | tmp_str = strrchr (exe_name, '\\'); | |
444 | tmp = strlen (exe_name) - strlen (tmp_str); | |
445 | strncpy (dir_name, exe_name, tmp); | |
446 | dir_name[tmp] = '\0'; | |
447 | } | |
7ab0751f | 448 | } |
5f56ef9c | 449 | |
7ab0751f | 450 | /* Generate a name for the link if not given */ |
c4453a3d | 451 | if (opts.name_arg == NULL) |
5f56ef9c | 452 | { |
7ab0751f | 453 | /* Strip trailing /'s if any */ |
c4453a3d | 454 | strcpy (buf_str, opts.target_arg); |
7ab0751f CW |
455 | tmp_str = buf_str; |
456 | tmp = strlen (buf_str) - 1; | |
457 | while (strrchr (buf_str, '/') == (buf_str + tmp)) | |
fe3a7d70 CW |
458 | { |
459 | buf_str[tmp] = '\0'; | |
460 | tmp--; | |
461 | } | |
7ab0751f CW |
462 | /* Get basename */ |
463 | while (*buf_str) | |
fe3a7d70 CW |
464 | { |
465 | if (*buf_str == '/') | |
466 | tmp_str = buf_str + 1; | |
467 | buf_str++; | |
468 | } | |
7ab0751f | 469 | strcpy (link_name, tmp_str); |
fe3a7d70 | 470 | } |
7ab0751f CW |
471 | /* User specified a name, so check it and convert */ |
472 | else | |
5f56ef9c | 473 | { |
c4453a3d | 474 | if (opts.desktop_flag || opts.smprograms_flag) |
fe3a7d70 CW |
475 | { |
476 | /* Cannot have absolute path relative to Desktop/SM Programs */ | |
477 | if (opts.name_arg[0] == '/') | |
478 | { | |
479 | free (buf_str); | |
480 | fprintf (stderr, | |
481 | "%s: absolute pathnames not allowed with -D/-P\n", | |
482 | program_name); | |
a4905427 | 483 | usage (stderr, program_name); |
fe3a7d70 CW |
484 | return (1); |
485 | } | |
486 | } | |
7ab0751f | 487 | /* Sigh. Another W32 path */ |
fe3a7d70 CW |
488 | if (strchr (opts.name_arg, ':') != NULL) |
489 | { | |
490 | free (buf_str); | |
491 | fprintf (stderr, "%s: all paths must be in POSIX format\n", | |
492 | program_name); | |
a4905427 | 493 | usage (stderr, program_name); |
fe3a7d70 CW |
494 | return (1); |
495 | } | |
c4453a3d | 496 | cygwin_conv_to_win32_path (opts.name_arg, link_name); |
fe3a7d70 | 497 | } |
7ab0751f CW |
498 | |
499 | /* Add suffix to link name if necessary */ | |
500 | if (strlen (link_name) > 4) | |
5f56ef9c | 501 | { |
7ab0751f CW |
502 | tmp = strlen (link_name) - 4; |
503 | if (strncmp (link_name + tmp, ".lnk", 4) != 0) | |
fe3a7d70 | 504 | strcat (link_name, ".lnk"); |
5f56ef9c | 505 | } |
7ab0751f CW |
506 | else |
507 | strcat (link_name, ".lnk"); | |
5f56ef9c | 508 | |
7ab0751f | 509 | /* Prepend relative path if necessary */ |
c4453a3d | 510 | if (opts.desktop_flag) |
7ab0751f CW |
511 | { |
512 | strcpy (buf_str, link_name); | |
c4453a3d | 513 | if (!opts.allusers_flag) |
fe3a7d70 | 514 | SHGetSpecialFolderLocation (NULL, CSIDL_DESKTOPDIRECTORY, &id); |
7ab0751f | 515 | else |
fe3a7d70 | 516 | SHGetSpecialFolderLocation (NULL, CSIDL_COMMON_DESKTOPDIRECTORY, &id); |
7ab0751f CW |
517 | SHGetPathFromIDList (id, link_name); |
518 | /* Make sure Win95 without "All Users" has output */ | |
519 | if (strlen (link_name) == 0) | |
fe3a7d70 CW |
520 | { |
521 | SHGetSpecialFolderLocation (NULL, CSIDL_DESKTOPDIRECTORY, &id); | |
522 | SHGetPathFromIDList (id, link_name); | |
523 | } | |
7ab0751f CW |
524 | strcat (link_name, "\\"); |
525 | strcat (link_name, buf_str); | |
5f56ef9c | 526 | } |
5f56ef9c | 527 | |
c4453a3d | 528 | if (opts.smprograms_flag) |
7ab0751f CW |
529 | { |
530 | strcpy (buf_str, link_name); | |
c4453a3d | 531 | if (!opts.allusers_flag) |
fe3a7d70 | 532 | SHGetSpecialFolderLocation (NULL, CSIDL_PROGRAMS, &id); |
7ab0751f | 533 | else |
fe3a7d70 | 534 | SHGetSpecialFolderLocation (NULL, CSIDL_COMMON_PROGRAMS, &id); |
7ab0751f CW |
535 | SHGetPathFromIDList (id, link_name); |
536 | /* Make sure Win95 without "All Users" has output */ | |
537 | if (strlen (link_name) == 0) | |
fe3a7d70 CW |
538 | { |
539 | SHGetSpecialFolderLocation (NULL, CSIDL_PROGRAMS, &id); | |
540 | SHGetPathFromIDList (id, link_name); | |
541 | } | |
7ab0751f CW |
542 | strcat (link_name, "\\"); |
543 | strcat (link_name, buf_str); | |
5f56ef9c | 544 | } |
5f56ef9c | 545 | |
08cb7edc CW |
546 | /* Setup description text */ |
547 | if (opts.desc_arg != NULL) | |
548 | { | |
549 | strncpy (desc, opts.desc_arg, MAX_PATH); | |
550 | ||
551 | /* There won't be a null terminated if strlen(desc_arg)>MAX_PATH */ | |
88041160 | 552 | desc[MAX_PATH - 1] = '\0'; |
08cb7edc CW |
553 | } |
554 | else | |
555 | { | |
556 | /* Put the POSIX path in the "Description", just to be nice */ | |
557 | cygwin_conv_to_full_posix_path (exe_name, desc); | |
558 | } | |
559 | ||
7ab0751f CW |
560 | /* Beginning of Windows interface */ |
561 | hres = OleInitialize (NULL); | |
562 | if (hres != S_FALSE && hres != S_OK) | |
fe3a7d70 | 563 | { |
08cb7edc | 564 | free (buf_str); |
fe3a7d70 CW |
565 | fprintf (stderr, "%s: Could not initialize OLE interface\n", |
566 | program_name); | |
c4453a3d | 567 | return (3); |
7ab0751f | 568 | } |
5f56ef9c | 569 | |
7ab0751f CW |
570 | hres = |
571 | CoCreateInstance (&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, | |
fe3a7d70 | 572 | &IID_IShellLink, (void **) &shell_link); |
7ab0751f | 573 | if (SUCCEEDED (hres)) |
5f56ef9c | 574 | { |
7ab0751f | 575 | hres = |
fe3a7d70 CW |
576 | shell_link->lpVtbl->QueryInterface (shell_link, &IID_IPersistFile, |
577 | (void **) &persist_file); | |
7ab0751f | 578 | if (SUCCEEDED (hres)) |
fe3a7d70 CW |
579 | { |
580 | shell_link->lpVtbl->SetPath (shell_link, exe_name); | |
581 | shell_link->lpVtbl->SetDescription (shell_link, desc); | |
582 | shell_link->lpVtbl->SetWorkingDirectory (shell_link, dir_name); | |
583 | if (opts.argument_arg) | |
584 | shell_link->lpVtbl->SetArguments (shell_link, opts.argument_arg); | |
585 | if (opts.icon_flag) | |
586 | shell_link->lpVtbl->SetIconLocation (shell_link, | |
587 | opts.icon_name_arg, | |
588 | opts.offset); | |
6d007d60 | 589 | if (opts.show_flag != SW_SHOWNORMAL) |
fe3a7d70 CW |
590 | shell_link->lpVtbl->SetShowCmd (shell_link, opts.show_flag); |
591 | ||
592 | ||
593 | /* Make link name Unicode-compliant */ | |
594 | hres = | |
595 | MultiByteToWideChar (CP_ACP, 0, link_name, -1, widepath, | |
596 | MAX_PATH); | |
597 | if (!SUCCEEDED (hres)) | |
598 | { | |
599 | free (buf_str); | |
600 | fprintf (stderr, "%s: Unicode translation failed%d\n", | |
601 | program_name, hres); | |
602 | return (3); | |
603 | } | |
604 | hres = persist_file->lpVtbl->Save (persist_file, widepath, TRUE); | |
605 | if (!SUCCEEDED (hres)) | |
606 | { | |
607 | free (buf_str); | |
608 | fprintf (stderr, | |
609 | "%s: Saving \"%s\" failed; does the target directory exist?\n", | |
610 | program_name, link_name); | |
611 | return (3); | |
612 | } | |
613 | persist_file->lpVtbl->Release (persist_file); | |
614 | shell_link->lpVtbl->Release (shell_link); | |
d2d984ab CW |
615 | |
616 | /* If we are creating shortcut for all users, ensure it is readable by all users */ | |
617 | if (opts.allusers_flag) | |
618 | { | |
619 | char *posixpath = (char *) cygwin_create_path ( | |
620 | CCP_WIN_W_TO_POSIX | CCP_ABSOLUTE, widepath); | |
621 | if (posixpath && *posixpath) | |
622 | { | |
623 | struct stat statbuf; | |
624 | if (stat(posixpath, &statbuf)) | |
625 | { | |
626 | fprintf (stderr, | |
627 | "%s: stat \"%s\" failed\n", | |
628 | program_name, posixpath); | |
629 | } | |
630 | else if (chmod(posixpath, statbuf.st_mode|S_IRUSR|S_IRGRP|S_IROTH)) | |
631 | { | |
632 | fprintf (stderr, | |
633 | "%s: chmod \"%s\" failed\n", | |
634 | program_name, posixpath); | |
635 | } | |
636 | } | |
637 | free(posixpath); | |
638 | } | |
639 | ||
3d86489d | 640 | return (0); |
fe3a7d70 | 641 | } |
7ab0751f | 642 | else |
fe3a7d70 CW |
643 | { |
644 | free (buf_str); | |
645 | fprintf (stderr, "%s: QueryInterface failed\n", program_name); | |
646 | return (3); | |
647 | } | |
5f56ef9c | 648 | } |
7ab0751f | 649 | else |
b96d6602 | 650 | { |
08cb7edc | 651 | free (buf_str); |
c4453a3d CW |
652 | fprintf (stderr, "%s: CoCreateInstance failed\n", program_name); |
653 | return (3); | |
5f56ef9c | 654 | } |
c4453a3d CW |
655 | } |
656 | ||
fe3a7d70 CW |
657 | static const char * |
658 | getVersion () | |
c4453a3d | 659 | { |
b96d6602 | 660 | return versionID; |
c4453a3d CW |
661 | } |
662 | ||
fe3a7d70 CW |
663 | static void |
664 | printTopDescription (FILE * f, char *name) | |
c4453a3d CW |
665 | { |
666 | char s[20]; | |
fe3a7d70 CW |
667 | fprintf (f, "%s is part of cygutils version %s\n", name, getVersion ()); |
668 | fprintf (f, " create a Windows shortcut\n\n"); | |
c4453a3d | 669 | } |
fe3a7d70 CW |
670 | static void |
671 | printBottomDescription (FILE * f, char *name) | |
c4453a3d | 672 | { |
fe3a7d70 CW |
673 | fprintf (f, |
674 | "\nNOTE: All filename arguments must be in unix (POSIX) format\n"); | |
c4453a3d | 675 | } |
fe3a7d70 CW |
676 | |
677 | static | |
678 | printLicense (FILE * f, char *name) | |
c4453a3d | 679 | { |
fe3a7d70 | 680 | fprintf (f, |
3a076f8e CW |
681 | "This program is free software: you can redistribute it and/or modify\n" |
682 | "it under the terms of the GNU General Public License as published by\n" | |
683 | "the Free Software Foundation, either version 3 of the License, or\n" | |
684 | "(at your option) any later version.\n\n" | |
685 | "This program is distributed in the hope that it will be useful,\n" | |
686 | "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" | |
687 | "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" | |
688 | "GNU General Public License for more details.\n\n" | |
689 | "You should have received a copy of the GNU General Public License\n" | |
690 | "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n" | |
691 | "See the COPYING file for full license information.\n"); | |
c4453a3d | 692 | } |
3a076f8e | 693 | |
fe3a7d70 | 694 | static void |
a4905427 | 695 | usage (FILE * f, char *name) |
c4453a3d | 696 | { |
fe3a7d70 | 697 | poptPrintUsage (optCon, f, 0); |
c4453a3d | 698 | } |
7ab0751f | 699 | |
fe3a7d70 | 700 | static void |
a4905427 | 701 | help (FILE * f, char *name) |
c4453a3d | 702 | { |
fe3a7d70 CW |
703 | printTopDescription (f, name); |
704 | poptPrintHelp (optCon, f, 0); | |
705 | printBottomDescription (f, name); | |
c4453a3d CW |
706 | } |
707 | ||
fe3a7d70 | 708 | static void |
a4905427 | 709 | version (FILE * f, char *name) |
c4453a3d | 710 | { |
fe3a7d70 CW |
711 | printTopDescription (f, name); |
712 | fprintf (f, copyrightID); | |
5f56ef9c | 713 | } |
c4453a3d | 714 | |
fe3a7d70 | 715 | static void |
a4905427 | 716 | license (FILE * f, char *name) |
c4453a3d | 717 | { |
fe3a7d70 CW |
718 | printTopDescription (f, name); |
719 | printLicense (f, name); | |
720 | } |