]> cygwin.com Git - cygwin-apps/cygutils.git/blame - src/mkshortcut/mkshortcut.c
version 1.4.15
[cygwin-apps/cygutils.git] / src / mkshortcut / mkshortcut.c
CommitLineData
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>
835dc6f3 38#include <olectl.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 46static const char versionID[] = PACKAGE_VERSION;
0bb67178 47static const char revID[] =
7ab0751f 48 "$Id$";
0bb67178 49static const char copyrightID[] =
7ab0751f 50 "Copyright (c) 2002\nJoshua Daniel Franklin. All rights reserved.\nLicensed under GPL v2.0\n";
5f56ef9c 51
fe3a7d70
CW
52typedef 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 70static int mkshortcut (optvals opts);
fe3a7d70
CW
71static void printTopDescription (FILE * f, char *name);
72static void printBottomDescription (FILE * f, char *name);
73static const char *getVersion ();
a4905427
CW
74static void usage (FILE * f, char *name);
75static void help (FILE * f, char *name);
76static void version (FILE * f, char *name);
77static void license (FILE * f, char *name);
c4453a3d
CW
78
79static char *program_name;
a4905427 80static poptContext optCon;
c4453a3d
CW
81
82int
83main (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;
fe3a7d70 92 const char *arg;
c4453a3d
CW
93
94 struct poptOption helpOptionsTable[] = {
fe3a7d70
CW
95 {"help", 'h', POPT_ARG_NONE, NULL, '?',
96 "Show this help message", NULL},
97 {"usage", '\0', POPT_ARG_NONE, NULL, 'u',
98 "Display brief usage message", NULL},
99 {"version", 'v', POPT_ARG_NONE, NULL, 'v',
100 "Display version information", NULL},
101 {"license", '\0', POPT_ARG_NONE, NULL, 'l',
102 "Display licensing information", NULL},
103 {NULL, '\0', 0, NULL, 0, NULL, NULL}
c4453a3d
CW
104 };
105
106 struct poptOption generalOptionsTable[] = {
fe3a7d70
CW
107 {"arguments", 'a', POPT_ARG_STRING, NULL, 'a',
108 "Use arguments ARGS", "ARGS"},
109 {"desc", 'd', POPT_ARG_STRING, NULL, 'd',
110 "Text for description/tooltip (defaults to POSIX path of TARGET)",
111 "DESC"},
112 {"icon", 'i', POPT_ARG_STRING, NULL, 'i',
113 "Icon file for link to use", "ICONFILE"},
114 {"iconoffset", 'j', POPT_ARG_INT, &(opts.offset), 'j',
115 "Offset of icon in icon file (default is 0)", NULL},
116 {"name", 'n', POPT_ARG_STRING, NULL, 'n',
117 "Name for link (defaults to TARGET)", "NAME"},
118 {"show", 's', POPT_ARG_STRING, NULL, 's',
119 "Window to show: normal, minimized, maximized", "norm|min|max"},
120 {"workingdir", 'w', POPT_ARG_STRING, NULL, 'w',
121 "Set working directory (defaults to directory path of TARGET)", "PATH"},
122 {"allusers", 'A', POPT_ARG_VAL, &(opts.allusers_flag), 1,
123 "Use 'All Users' instead of current user for -D,-P", NULL},
124 {"desktop", 'D', POPT_ARG_VAL, &(opts.desktop_flag), 1,
125 "Create link relative to 'Desktop' directory", NULL},
126 {"smprograms", 'P', POPT_ARG_VAL, &(opts.smprograms_flag), 1,
127 "Create link relative to Start Menu 'Programs' directory", NULL},
128 {NULL, '\0', 0, NULL, 0, NULL, NULL}
c4453a3d 129 };
fe3a7d70 130
c4453a3d 131 struct poptOption opt[] = {
fe3a7d70
CW
132 {NULL, '\0', POPT_ARG_INCLUDE_TABLE, generalOptionsTable, 0,
133 "General options", NULL},
134 {NULL, '\0', POPT_ARG_INCLUDE_TABLE, helpOptionsTable, 0,
135 "Help options", NULL},
136 {NULL, '\0', 0, NULL, 0, NULL, NULL}
c4453a3d
CW
137 };
138
139 tmp_str = strrchr (argv[0], '/');
fe3a7d70
CW
140 if (tmp_str == NULL)
141 {
142 tmp_str = strrchr (argv[0], '\\');
143 }
144 if (tmp_str == NULL)
145 {
146 tmp_str = argv[0];
147 }
148 else
149 {
150 tmp_str++;
151 }
152 if ((program_name = strdup (tmp_str)) == NULL)
153 {
154 fprintf (stderr, "%s: memory allocation error\n", argv[0]);
155 exit (2);
156 }
c4453a3d
CW
157
158 icon_offset_flag = 0;
159
160 opts.offset = 0;
161 opts.icon_flag = 0;
162 opts.unix_flag = 0;
163 opts.windows_flag = 0;
164 opts.allusers_flag = 0;
165 opts.desktop_flag = 0;
166 opts.smprograms_flag = 0;
6d007d60 167 opts.show_flag = SW_SHOWNORMAL;
c4453a3d
CW
168 opts.target_arg = NULL;
169 opts.argument_arg = NULL;
170 opts.name_arg = NULL;
08cb7edc 171 opts.desc_arg = NULL;
b2682e03 172 opts.dir_name_arg = NULL;
c4453a3d
CW
173 opts.icon_name_arg = NULL;
174
175 /* Parse options */
fe3a7d70
CW
176 optCon = poptGetContext (NULL, argc, argv, opt, 0);
177 poptSetOtherOptionHelp (optCon, "[OPTION]* TARGET");
178 while ((rc = poptGetNextOpt (optCon)) > 0)
179 {
180 switch (rc)
181 {
182 case '?':
a4905427 183 help (stdout, program_name);
fe3a7d70
CW
184 goto exit;
185 case 'u':
a4905427 186 usage (stdout, program_name);
fe3a7d70
CW
187 goto exit;
188 case 'v':
a4905427 189 version (stdout, program_name);
fe3a7d70
CW
190 goto exit;
191 case 'l':
a4905427 192 license (stdout, program_name);
fe3a7d70
CW
193 goto exit;
194 case 'd':
195 if (arg = poptGetOptArg (optCon))
196 {
197 if ((opts.desc_arg = strdup (arg)) == NULL)
198 {
199 fprintf (stderr, "%s: memory allocation error\n",
200 program_name);
201 ec = 2;
202 goto exit;
203 }
204 }
205 break;
206 case 'i':
207 opts.icon_flag = 1;
208 if (arg = poptGetOptArg (optCon))
209 {
1ec3acf3
CW
210 opts.icon_name_arg = (char *) cygwin_create_path(
211 CCP_POSIX_TO_WIN_A, arg);
212 if (opts.icon_name_arg == NULL)
fe3a7d70 213 {
1ec3acf3
CW
214 fprintf (stderr, "%s: error converting posix path to win32 (%s)\n",
215 program_name, strerror(errno));
fe3a7d70
CW
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
352exit:
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
1ec3acf3
CW
382static char *
383xstrndup (const char *string, size_t n)
384{
385 char *s = strndup (string, n);
386 if (!s)
387 {
388 fprintf (stderr, "%s: out of memory\n", program_name);
389 exit(2);
390 }
391 return s;
392}
393
394static char *
395xstrncat (char **dest, const char *add, size_t n)
396{
bcf87db2 397 size_t len = strlen (*dest) + n + 1;
1ec3acf3
CW
398 char *s = (char *) realloc (*dest, len * sizeof (char));
399 if (!s)
400 {
401 fprintf (stderr, "%s: out of memory\n", program_name);
402 exit(2);
403 }
404 *dest = s;
405 return strncat (*dest, add, n);
406}
407
fe3a7d70 408int
a4905427 409mkshortcut (optvals opts)
5f56ef9c 410{
1ec3acf3
CW
411 char* link_name = NULL;
412 char* exe_name = NULL;
413 char* dir_name = NULL;
414 char* desc = NULL;
c3bb28d5 415 char *buf_str, *tmp_str, *base_str;
c4453a3d 416 int tmp;
7ab0751f
CW
417
418 /* For OLE interface */
5f56ef9c
CW
419 LPITEMIDLIST id;
420 HRESULT hres;
7ab0751f
CW
421 IShellLink *shell_link;
422 IPersistFile *persist_file;
5f56ef9c 423 WCHAR widepath[MAX_PATH];
c3bb28d5 424 char link_path[MAX_PATH];
5f56ef9c 425
7ab0751f 426 /* If there's a colon in the TARGET, it should be a URL */
c4453a3d 427 if (strchr (opts.target_arg, ':') != NULL)
7ab0751f
CW
428 {
429 /* Nope, somebody's trying a W32 path */
fe3a7d70
CW
430 if (opts.target_arg[1] == ':')
431 {
fe3a7d70
CW
432 fprintf (stderr, "%s: all paths must be in POSIX format\n",
433 program_name);
a4905427 434 usage (stderr, program_name);
fe3a7d70
CW
435 return (1);
436 }
1ec3acf3
CW
437 exe_name = xstrndup (opts.target_arg, strlen(opts.target_arg));
438 dir_name = xstrndup ("", 0); /* No working dir for URL */
7ab0751f
CW
439 }
440 /* Convert TARGET to win32 path */
5f56ef9c 441 else
7ab0751f 442 {
1ec3acf3
CW
443 buf_str = xstrndup (opts.target_arg, strlen(opts.target_arg));
444 exe_name = (char *) cygwin_create_path (CCP_POSIX_TO_WIN_A,
445 opts.target_arg);
446 if (!exe_name)
447 {
448 fprintf (stderr, "%s: error converting posix path to win32 (%s)\n",
449 program_name, strerror(errno));
450 free (buf_str);
451 return 2;
452 }
5f56ef9c 453
b2682e03
CW
454 /* Get a working dir from 'w' option */
455 if (opts.dir_name_arg != NULL)
456 {
457 if (strchr (opts.dir_name_arg, ':') != NULL)
458 {
08cb7edc 459 free (buf_str);
1ec3acf3 460 free (exe_name);
fe3a7d70
CW
461 fprintf (stderr, "%s: all paths must be in POSIX format\n",
462 program_name);
a4905427 463 usage (stderr, program_name);
fe3a7d70 464 return (1);
b2682e03 465 }
1ec3acf3
CW
466 dir_name = (char *) cygwin_create_path (CCP_POSIX_TO_WIN_A,
467 opts.dir_name_arg);
468 if (!dir_name)
469 {
470 fprintf (stderr, "%s: error converting posix path to win32 (%s)\n",
471 program_name, strerror(errno));
472 free (buf_str);
473 free (exe_name);
474 return 2;
475 }
b2682e03 476 }
7ab0751f 477 /* Get a working dir from the exepath */
b2682e03
CW
478 else
479 {
480 tmp_str = strrchr (exe_name, '\\');
481 tmp = strlen (exe_name) - strlen (tmp_str);
1ec3acf3 482 dir_name = xstrndup (exe_name, tmp);
b2682e03
CW
483 dir_name[tmp] = '\0';
484 }
1ec3acf3 485 if (buf_str) free (buf_str);
7ab0751f 486 }
5f56ef9c 487
7ab0751f 488 /* Generate a name for the link if not given */
c4453a3d 489 if (opts.name_arg == NULL)
5f56ef9c 490 {
7ab0751f 491 /* Strip trailing /'s if any */
1ec3acf3 492 buf_str = xstrndup (opts.target_arg, strlen(opts.target_arg));
c3bb28d5 493 base_str = buf_str;
7ab0751f
CW
494 tmp_str = buf_str;
495 tmp = strlen (buf_str) - 1;
496 while (strrchr (buf_str, '/') == (buf_str + tmp))
fe3a7d70
CW
497 {
498 buf_str[tmp] = '\0';
499 tmp--;
500 }
7ab0751f
CW
501 /* Get basename */
502 while (*buf_str)
fe3a7d70
CW
503 {
504 if (*buf_str == '/')
505 tmp_str = buf_str + 1;
506 buf_str++;
507 }
1ec3acf3 508 link_name = xstrndup (tmp_str, strlen (tmp_str));
c3bb28d5 509 free (base_str);
fe3a7d70 510 }
7ab0751f
CW
511 /* User specified a name, so check it and convert */
512 else
5f56ef9c 513 {
c4453a3d 514 if (opts.desktop_flag || opts.smprograms_flag)
fe3a7d70
CW
515 {
516 /* Cannot have absolute path relative to Desktop/SM Programs */
517 if (opts.name_arg[0] == '/')
518 {
fe3a7d70
CW
519 fprintf (stderr,
520 "%s: absolute pathnames not allowed with -D/-P\n",
521 program_name);
a4905427 522 usage (stderr, program_name);
fe3a7d70
CW
523 return (1);
524 }
525 }
7ab0751f 526 /* Sigh. Another W32 path */
fe3a7d70
CW
527 if (strchr (opts.name_arg, ':') != NULL)
528 {
fe3a7d70
CW
529 fprintf (stderr, "%s: all paths must be in POSIX format\n",
530 program_name);
a4905427 531 usage (stderr, program_name);
fe3a7d70
CW
532 return (1);
533 }
1ec3acf3
CW
534 link_name = (char *) cygwin_create_path (
535 CCP_POSIX_TO_WIN_A | CCP_RELATIVE, opts.name_arg);
536 if (!link_name)
537 {
538 fprintf (stderr, "%s: error converting posix path to win32 (%s)\n",
539 program_name, strerror(errno));
540 return 2;
541 }
fe3a7d70 542 }
7ab0751f
CW
543
544 /* Add suffix to link name if necessary */
545 if (strlen (link_name) > 4)
5f56ef9c 546 {
7ab0751f
CW
547 tmp = strlen (link_name) - 4;
548 if (strncmp (link_name + tmp, ".lnk", 4) != 0)
1ec3acf3 549 xstrncat (&link_name, ".lnk", 4);
5f56ef9c 550 }
7ab0751f 551 else
1ec3acf3 552 xstrncat (&link_name, ".lnk", 4);
5f56ef9c 553
7ab0751f 554 /* Prepend relative path if necessary */
c4453a3d 555 if (opts.desktop_flag)
7ab0751f 556 {
1ec3acf3
CW
557 char local_buf[MAX_PATH];
558 buf_str = xstrndup (link_name, strlen (link_name));
559
c4453a3d 560 if (!opts.allusers_flag)
fe3a7d70 561 SHGetSpecialFolderLocation (NULL, CSIDL_DESKTOPDIRECTORY, &id);
7ab0751f 562 else
fe3a7d70 563 SHGetSpecialFolderLocation (NULL, CSIDL_COMMON_DESKTOPDIRECTORY, &id);
1ec3acf3 564 SHGetPathFromIDList (id, local_buf);
7ab0751f 565 /* Make sure Win95 without "All Users" has output */
1ec3acf3 566 if (strlen (local_buf) == 0)
fe3a7d70
CW
567 {
568 SHGetSpecialFolderLocation (NULL, CSIDL_DESKTOPDIRECTORY, &id);
1ec3acf3 569 SHGetPathFromIDList (id, local_buf);
fe3a7d70 570 }
1ec3acf3
CW
571 free (link_name);
572 link_name = xstrndup (local_buf, strlen (local_buf));
573 xstrncat (&link_name, "\\", 1);
574 xstrncat (&link_name, buf_str, strlen (buf_str));
575 free (buf_str);
5f56ef9c 576 }
5f56ef9c 577
c4453a3d 578 if (opts.smprograms_flag)
7ab0751f 579 {
1ec3acf3
CW
580 char local_buf[MAX_PATH];
581 buf_str = xstrndup (link_name, strlen (link_name));
582
c4453a3d 583 if (!opts.allusers_flag)
fe3a7d70 584 SHGetSpecialFolderLocation (NULL, CSIDL_PROGRAMS, &id);
7ab0751f 585 else
fe3a7d70 586 SHGetSpecialFolderLocation (NULL, CSIDL_COMMON_PROGRAMS, &id);
1ec3acf3 587 SHGetPathFromIDList (id, local_buf);
7ab0751f 588 /* Make sure Win95 without "All Users" has output */
1ec3acf3 589 if (strlen (local_buf) == 0)
fe3a7d70
CW
590 {
591 SHGetSpecialFolderLocation (NULL, CSIDL_PROGRAMS, &id);
1ec3acf3 592 SHGetPathFromIDList (id, local_buf);
fe3a7d70 593 }
1ec3acf3
CW
594 free (link_name);
595 link_name = xstrndup (local_buf, strlen (local_buf));
596 xstrncat (&link_name, "\\", 1);
597 xstrncat (&link_name, buf_str, strlen (buf_str));
598 free (buf_str);
5f56ef9c 599 }
5f56ef9c 600
c3bb28d5
MG
601 /* After Windows 7, saving link to relative path fails; work around that */
602 hres = GetFullPathName (link_name, sizeof (link_path), link_path, 0);
603 if (hres == 0)
604 {
605 fprintf (stderr, "%s: Could not qualify link name\n", program_name);
606 return 2;
607 }
608 free (link_name);
609 link_name = xstrndup (link_path, strlen (link_path));
610
08cb7edc
CW
611 /* Setup description text */
612 if (opts.desc_arg != NULL)
613 {
1ec3acf3 614 desc = xstrndup (opts.desc_arg, strlen (opts.desc_arg));
08cb7edc
CW
615 }
616 else
617 {
618 /* Put the POSIX path in the "Description", just to be nice */
1ec3acf3
CW
619 desc = (char *) cygwin_create_path (CCP_WIN_A_TO_POSIX, exe_name);
620 if (!desc)
621 {
622 fprintf (stderr, "%s: error converting win32 path to posix (%s)\n",
623 program_name, strerror(errno));
624 return 2;
625 }
08cb7edc
CW
626 }
627
7ab0751f
CW
628 /* Beginning of Windows interface */
629 hres = OleInitialize (NULL);
630 if (hres != S_FALSE && hres != S_OK)
fe3a7d70 631 {
fe3a7d70
CW
632 fprintf (stderr, "%s: Could not initialize OLE interface\n",
633 program_name);
1ec3acf3
CW
634 free (link_name);
635 free (exe_name);
636 free (dir_name);
637 free (desc);
c4453a3d 638 return (3);
7ab0751f 639 }
5f56ef9c 640
7ab0751f
CW
641 hres =
642 CoCreateInstance (&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
fe3a7d70 643 &IID_IShellLink, (void **) &shell_link);
7ab0751f 644 if (SUCCEEDED (hres))
5f56ef9c 645 {
7ab0751f 646 hres =
fe3a7d70
CW
647 shell_link->lpVtbl->QueryInterface (shell_link, &IID_IPersistFile,
648 (void **) &persist_file);
7ab0751f 649 if (SUCCEEDED (hres))
fe3a7d70
CW
650 {
651 shell_link->lpVtbl->SetPath (shell_link, exe_name);
652 shell_link->lpVtbl->SetDescription (shell_link, desc);
653 shell_link->lpVtbl->SetWorkingDirectory (shell_link, dir_name);
654 if (opts.argument_arg)
655 shell_link->lpVtbl->SetArguments (shell_link, opts.argument_arg);
656 if (opts.icon_flag)
657 shell_link->lpVtbl->SetIconLocation (shell_link,
658 opts.icon_name_arg,
659 opts.offset);
6d007d60 660 if (opts.show_flag != SW_SHOWNORMAL)
fe3a7d70
CW
661 shell_link->lpVtbl->SetShowCmd (shell_link, opts.show_flag);
662
663
664 /* Make link name Unicode-compliant */
665 hres =
666 MultiByteToWideChar (CP_ACP, 0, link_name, -1, widepath,
667 MAX_PATH);
668 if (!SUCCEEDED (hres))
669 {
fe3a7d70
CW
670 fprintf (stderr, "%s: Unicode translation failed%d\n",
671 program_name, hres);
1ec3acf3
CW
672 free (link_name);
673 free (exe_name);
674 free (dir_name);
675 free (desc);
fe3a7d70
CW
676 return (3);
677 }
678 hres = persist_file->lpVtbl->Save (persist_file, widepath, TRUE);
679 if (!SUCCEEDED (hres))
680 {
fe3a7d70
CW
681 fprintf (stderr,
682 "%s: Saving \"%s\" failed; does the target directory exist?\n",
683 program_name, link_name);
1ec3acf3
CW
684 free (link_name);
685 free (exe_name);
686 free (dir_name);
687 free (desc);
fe3a7d70
CW
688 return (3);
689 }
690 persist_file->lpVtbl->Release (persist_file);
691 shell_link->lpVtbl->Release (shell_link);
d2d984ab
CW
692
693 /* If we are creating shortcut for all users, ensure it is readable by all users */
694 if (opts.allusers_flag)
695 {
696 char *posixpath = (char *) cygwin_create_path (
697 CCP_WIN_W_TO_POSIX | CCP_ABSOLUTE, widepath);
698 if (posixpath && *posixpath)
699 {
700 struct stat statbuf;
701 if (stat(posixpath, &statbuf))
702 {
703 fprintf (stderr,
704 "%s: stat \"%s\" failed\n",
705 program_name, posixpath);
706 }
707 else if (chmod(posixpath, statbuf.st_mode|S_IRUSR|S_IRGRP|S_IROTH))
708 {
709 fprintf (stderr,
710 "%s: chmod \"%s\" failed\n",
711 program_name, posixpath);
712 }
713 }
714 free(posixpath);
715 }
1ec3acf3
CW
716 free (link_name);
717 free (exe_name);
718 free (dir_name);
719 free (desc);
3d86489d 720 return (0);
fe3a7d70 721 }
7ab0751f 722 else
fe3a7d70 723 {
fe3a7d70 724 fprintf (stderr, "%s: QueryInterface failed\n", program_name);
1ec3acf3
CW
725 free (link_name);
726 free (exe_name);
727 free (dir_name);
728 free (desc);
fe3a7d70
CW
729 return (3);
730 }
5f56ef9c 731 }
7ab0751f 732 else
b96d6602 733 {
c4453a3d 734 fprintf (stderr, "%s: CoCreateInstance failed\n", program_name);
1ec3acf3
CW
735 free (link_name);
736 free (exe_name);
737 free (dir_name);
738 free (desc);
c4453a3d 739 return (3);
5f56ef9c 740 }
c4453a3d
CW
741}
742
fe3a7d70
CW
743static const char *
744getVersion ()
c4453a3d 745{
b96d6602 746 return versionID;
c4453a3d
CW
747}
748
fe3a7d70
CW
749static void
750printTopDescription (FILE * f, char *name)
c4453a3d
CW
751{
752 char s[20];
fe3a7d70
CW
753 fprintf (f, "%s is part of cygutils version %s\n", name, getVersion ());
754 fprintf (f, " create a Windows shortcut\n\n");
c4453a3d 755}
fe3a7d70
CW
756static void
757printBottomDescription (FILE * f, char *name)
c4453a3d 758{
fe3a7d70
CW
759 fprintf (f,
760 "\nNOTE: All filename arguments must be in unix (POSIX) format\n");
c4453a3d 761}
fe3a7d70
CW
762
763static
764printLicense (FILE * f, char *name)
c4453a3d 765{
fe3a7d70 766 fprintf (f,
3a076f8e
CW
767 "This program is free software: you can redistribute it and/or modify\n"
768 "it under the terms of the GNU General Public License as published by\n"
769 "the Free Software Foundation, either version 3 of the License, or\n"
770 "(at your option) any later version.\n\n"
771 "This program is distributed in the hope that it will be useful,\n"
772 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
773 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
774 "GNU General Public License for more details.\n\n"
775 "You should have received a copy of the GNU General Public License\n"
776 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n"
777 "See the COPYING file for full license information.\n");
c4453a3d 778}
3a076f8e 779
fe3a7d70 780static void
a4905427 781usage (FILE * f, char *name)
c4453a3d 782{
fe3a7d70 783 poptPrintUsage (optCon, f, 0);
c4453a3d 784}
7ab0751f 785
fe3a7d70 786static void
a4905427 787help (FILE * f, char *name)
c4453a3d 788{
fe3a7d70
CW
789 printTopDescription (f, name);
790 poptPrintHelp (optCon, f, 0);
791 printBottomDescription (f, name);
c4453a3d
CW
792}
793
fe3a7d70 794static void
a4905427 795version (FILE * f, char *name)
c4453a3d 796{
fe3a7d70
CW
797 printTopDescription (f, name);
798 fprintf (f, copyrightID);
5f56ef9c 799}
c4453a3d 800
fe3a7d70 801static void
a4905427 802license (FILE * f, char *name)
c4453a3d 803{
fe3a7d70
CW
804 printTopDescription (f, name);
805 printLicense (f, name);
806}
This page took 0.115848 seconds and 5 git commands to generate.