From c56f3b40d4650a8d86304b12bc6ef4b71f5cd873 Mon Sep 17 00:00:00 2001 From: Charles Wilson Date: Fri, 5 Sep 2003 04:07:57 +0000 Subject: [PATCH] Add readshortcut contribution (Rob Siklos) --- AUTHORS | 4 + ChangeLog | 14 ++ Makefile.am | 7 +- NEWS | 6 + PROGLIST | 5 + README | 4 +- src/readshortcut/readshortcut.1 | 112 +++++++++ src/readshortcut/readshortcut.c | 420 ++++++++++++++++++++++++++++++++ 8 files changed, 568 insertions(+), 4 deletions(-) create mode 100644 src/readshortcut/readshortcut.1 create mode 100644 src/readshortcut/readshortcut.c diff --git a/AUTHORS b/AUTHORS index cae3a15..05e54fc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -26,6 +26,10 @@ Joshua Danial Franklin mkshortcut.c, mkshortcut.1 (GPL) +Rob Siklos + readshortcut.c, readshortcut.1 + (GPL) + Michael Schaap cygstart.c, cygstart.1 diff --git a/ChangeLog b/ChangeLog index 44390f8..506ce54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2003-09-04 Chalres Wilson + + * NEWS: update + +2003-09-04 Rob Siklos + + * src/readshortcut: new directory + * src/readshortcut/readshortcut.c: new file + * src/readshortcut/readshortcut.1: new file + * Makefile.am: add program 'readshortcut' + * AUTHORS: add Rob Siklos for readshortcut + * PROGLIST: add readshortcut + * README: add readshortcut + 2003-08-02 Charles Wilson tag and release v1_2_1 diff --git a/Makefile.am b/Makefile.am index f49b5e8..c6d1dfc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,8 @@ INCLUDES = -I$(top_builddir) -I$(top_srcdir) if WITH_WINDOWS_PROGRAMS windows_progs = src/banner/banner src/clip/getclip src/clip/putclip \ - src/cygstart/cygstart src/lpr/lpr src/mkshortcut/mkshortcut + src/cygstart/cygstart src/lpr/lpr src/mkshortcut/mkshortcut \ + src/readshortcut/readshortcut endif if WITH_IPC_PROGRAMS @@ -35,6 +36,7 @@ noinst_HEADERS = src/cal/errs.h src/cal/widechar.h \ man_MANS = src/cal/cal.1 src/cygstart/cygstart.1 src/ddate/ddate.1 \ src/mkshortcut/mkshortcut.1 \ + src/readshortcut/readshortcut.1 \ src/namei/namei.1 src/col/col.1 src/getopt/getopt.1 \ src/readlink/readlink.1 src/rev/rev.1 src/column/column.1 \ src/colcrt/colcrt.1 src/colrm/colrm.1 src/mcookie/mcookie.1 \ @@ -43,7 +45,7 @@ man_MANS = src/cal/cal.1 src/cygstart/cygstart.1 src/ddate/ddate.1 \ EXTRA_PROGRAMS = src/banner/banner src/clip/getclip src/clip/putclip \ src/cygstart/cygstart src/ipc/semtool src/ipc/shmtool \ src/ipc/msgtool src/ipc/semstat src/ipc/ipcrm src/ipc/ipcs \ - src/lpr/lpr src/mkshortcut/mkshortcut + src/lpr/lpr src/mkshortcut/mkshortcut src/readshortcut/readshortcut EXTRA_SCRIPTS = src/ipc/ipck @@ -70,6 +72,7 @@ EXTRA_DIST = config.rpath PROGLIST bootstrap common.h \ src_banner_banner_LDADD = -lkernel32 -lgdi32 src_lpr_lpr_LDADD = -lwinspool src_mkshortcut_mkshortcut_LDADD = -lole32 -luuid +src_readshortcut_readshortcut_LDADD = -lole32 -luuid src_cal_cal_LDADD = @LIBINTL@ src_ddate_ddate_LDADD = @LIBINTL@ src_namei_namei_LDADD = @LIBINTL@ diff --git a/NEWS b/NEWS index d7cc470..0d96448 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +1.2.2: + Add readshortcut (Rob Siklos) + +1.2.1: + Fix some configury errors, update documenation + 1.2.0: Added ipcs, ipcrm, and ipck programs from cygipc. diff --git a/PROGLIST b/PROGLIST index 686d60d..910fae5 100644 --- a/PROGLIST +++ b/PROGLIST @@ -83,6 +83,11 @@ mkshortcut.exe using .lnk files, which aren't really "full-featured") (GPL) +readshortcut.exe + can be used to read information from windows shortcuts (such + as target, icon, window state, etc) + (GPL) + cygstart.exe A command-line tool which allows you to let Windows start a program or open a file or URL in its associated application. It is similar to the Windows diff --git a/README b/README index 188357c..669db97 100644 --- a/README +++ b/README @@ -37,8 +37,8 @@ What's in this package: GPL: ascii banner conv cygstart dump getclip getopt ipck ipcrm ipcs - lpr mkshortcut msgtool putclip realpath - semstat semtool shmtool + lpr mkshortcut msgtool putclip readshortcut + realpath semstat semtool shmtool d2u dos2unix u2d unix2dos diff --git a/src/readshortcut/readshortcut.1 b/src/readshortcut/readshortcut.1 new file mode 100644 index 0000000..213e885 --- /dev/null +++ b/src/readshortcut/readshortcut.1 @@ -0,0 +1,112 @@ +.TH "READSHORTCUT" 1 "4 September 2003" "readshortcut 1.00 (cygutils)" "Cygutils" +.SH NAME +readshortcut \- read data from a windows shortcut (.lnk) file +.\"{{{ Synopsis +.SH SYNOPSIS +.B readshortcut +.RB [OPTION]* +.RB "SHORTCUT" +.BR +.\"}}} +.SH DESCRIPTION +.B readshortcut +is a command-line tool for reading Windows shortcut files (also known as +OLE links). The most practical use is to resolve the target that a shortcut +points to. It can be easily run from a script or batch file for non-interactive +use. + +.SH OPTIONS + +.TP +\fB\-h\fR, \fB\-\-help\fR +Output detailed usage information and exit. + +.TP +\fB\-\-usage\fR +Output basic usage information and exit. + +.TP +\fB\-v\fR, \fB\-\-version\fR +Display the program version and exit. + +.TP +\fB\-\-license\fR +Display the license agreement and exit. + +.TP +\fB\-f\fR, \fB\-\-fields\fR +Show field names (Target, Working Directory, Arguments, Show Command, Icon Library, Icon Library Offset, Description). + +.TP +\fB\-u\fR, \fB\-\-unix\fR +Use Unix path format for display (default). + +.TP +\fB\-w\fR, \fB\-\-windows\fR +Use Windows path format for display. + +.TP +\fB\-t\fR, \fB\-\-target\fR +Display shortcut target (default). + +.TP +\fB\-g\fR, \fB\-\-working\fR +Display shortcut working directory. + +.TP +\fB\-r\fR, \fB\-\-args\fR +Display shortcut arguments + +.TP +\fB\-s\fR, \fB\-\-showcmd\fR +Display shortcut "show" command value (Normal, Minimized, or Maximized). + +.TP +\fB\-i\fR, \fB\-\-icon\fR +Display icon library location. + +.TP +\fB\-j\fR, \fB\-\-offset\fR +Display icon library offset. + +.TP +\fB\-d\fR, \fB\-\-desc\fR +Display shortcut description. + +.TP +\fB\-a\fR, \fB\-\-all\fR +Display all information. + +.SH NOTES +The filename (shortcut) argument may be unix (POSIX) format or Windows (C:\\) format. +.PP +Information extracted from the shortcut is always displayed in the following order: Target, Working Directory, Arguments, Show Command, Icon Library, Icon Library Offset, Description. Each element appears on a separate line. + +.SH BUGS +There may be problems if the SHORTCUT argument is longer than 256 characters + +.SH COPYRIGHT +Copyright (C) 2003 Rob Siklos +.PP +\fBreadshortcut\fP is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) any +later version. +.PP +\fBreadshortcut\fP is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. +.PP +You should have received a copy of the GNU General Public License; +see the file COPYING. If not, write to the +Free Software Foundation, +59 Temple Place, +Suite 330, Boston, MA 02111-1307, USA. + +.SH AUTHOR +Rob Siklos, (r o b 3 @ s i k l o s . c a), Toronto, Canada + +.SH "SEE ALSO" +.BR mkshortcut (1) +.BR readlink (1) diff --git a/src/readshortcut/readshortcut.c b/src/readshortcut/readshortcut.c new file mode 100644 index 0000000..3dba643 --- /dev/null +++ b/src/readshortcut/readshortcut.c @@ -0,0 +1,420 @@ +/* + * readshortcut for cygwin/windows + * + * Copyright (C) 2003 Rob Siklos + * http://www.cygwin.com/ml/cygwin/2003-08/msg00640.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation in version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + + /* http://www.rpm.org/dark_corners/popt/ + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_int/shell_int_programming/shortcuts/shortcut.asp + */ + +/* how to compile a standalone version: + * + * - comment the config.h and common.h includes + * - uncomment the stdio and popt.h includes + * - run "gcc readshortcut.c -o readshortcut.exe -lpopt -luuid -lole32" + * + */ + + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include "common.h" + +/* moved to common.h */ +/* +#include +#include +*/ + +#include +#include + +#define PATH_UNIX 0 +#define PATH_WIN 1 + +#define ERR_NONE 0 +#define ERR_USER 1 +#define ERR_SYS 2 +#define ERR_WIN 3 + +#define SLGP_RAWPATH 0 +#define SW_SHOWMINIMIZED_SEVEN 7 + +#define BUFF_SIZE 1024 + +static const char versionID[] = "1.0"; + +typedef struct optvals_s { + char * target_fname; + + int show_field_names; + int pathType; + + int show_target; + int show_working_dir; + int show_args; + int show_showCmd; + int show_icon; + int show_icon_offset; + int show_desc; + int show_all; + +} optvals; + +void cygwin_conv_to_full_win32_path(const char *path, char *win32_path); +void cygwin_conv_to_full_posix_path(const char *path, char *posix_path); + +static void printTopDescription(FILE * f, char * name); +static void printBottomDescription(FILE * f, char * name); +static const char * getVersion(void); +static void usage(poptContext optCon, FILE * f, char * name); +static void help(poptContext optCon, FILE * f, char * name); +static void version(poptContext optCon, FILE * f, char * name); +static void license(poptContext optCon, FILE * f, char * name); + +void formatPath (char * strPath, int format); +int readshortcut(optvals opts, poptContext optContext); + +static char *program_name; + +int main (int argc, const char **argv) { + poptContext optContext; + const char ** loose_args; + int rc; + int result = ERR_NONE; + optvals opts; + const char *tmp_str; + + struct poptOption infoOptionsTable[] = { + { "help", 'h', POPT_ARG_NONE, NULL, '?', "This message", NULL}, + { "usage", '\0', POPT_ARG_NONE, NULL, 'u', "Program usage", NULL}, + { "version", 'v', POPT_ARG_NONE, NULL, 'v', "Version information", NULL}, + { "license", '\0', POPT_ARG_NONE, NULL, 'l', "License information", NULL}, + { NULL, '\0', 0, NULL, 0, NULL, NULL } + }; + + struct poptOption outputOptionsTable[] = { + { "fields", 'f', POPT_ARG_VAL, &(opts.show_field_names), 1, "Show field names", NULL}, + { "unix", 'u', POPT_ARG_VAL, &(opts.pathType), PATH_UNIX, "Use Unix path format for display (default)", NULL}, + { "windows", 'w', POPT_ARG_VAL, &(opts.pathType), PATH_WIN, "Use Windows path format for display ", NULL}, + { "target", 't', POPT_ARG_VAL, &(opts.show_target), 1, "Display shortcut target", NULL}, + { "working", 'g', POPT_ARG_VAL, &(opts.show_working_dir), 1, "Display shortcut working directory", NULL}, + { "args", 'r', POPT_ARG_VAL, &(opts.show_args), 1, "Display shortcut arguments", NULL}, + { "showcmd", 's', POPT_ARG_VAL, &(opts.show_showCmd), 1, "Display shortcut \"show\" command value", NULL}, + { "icon", 'i', POPT_ARG_VAL, &(opts.show_icon), 1, "Display icon library location", NULL}, + { "offset", 'j', POPT_ARG_VAL, &(opts.show_icon_offset), 1, "Display icon library offset", NULL}, + { "desc", 'd', POPT_ARG_VAL, &(opts.show_desc), 1, "Display shortcut description", NULL}, + { "all", 'a', POPT_ARG_VAL, &(opts.show_all), 1, "Display all information", NULL}, + { NULL, '\0', 0, NULL, 0, NULL, NULL } + }; + + struct poptOption opt[] = { + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, outputOptionsTable, 0, "Output options", NULL }, + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, infoOptionsTable, 0, "Information options (display a message and exit)", NULL }, + { NULL, '\0', 0, NULL, 0, NULL, NULL } + }; + + /* get the program name */ + tmp_str = strrchr (argv[0], '/'); + if (tmp_str == NULL) { tmp_str = strrchr (argv[0], '\\'); } + if (tmp_str == NULL) { tmp_str = argv[0]; } + else { tmp_str++; } + if ((program_name = strdup(tmp_str)) == NULL ) { + fprintf(stderr, "%s: memory allocation error\n", argv[0]); + exit(ERR_SYS); + } + + /* set default values for options */ + opts.target_fname = NULL; + + opts.show_field_names = 0; + opts.pathType = PATH_UNIX; + + opts.show_target = 0; + opts.show_working_dir = 0; + opts.show_args = 0; + opts.show_showCmd = 0; + opts.show_icon = 0; + opts.show_icon_offset = 0; + opts.show_desc = 0; + opts.show_all = 0; + + /* set the pOpt context and help line */ + optContext = poptGetContext(NULL, argc, argv, opt, 0); + poptSetOtherOptionHelp(optContext, "[OPTION]* SHORTCUT"); + + while ((rc = poptGetNextOpt(optContext)) > 0) { + switch (rc) { + case '?': + help(optContext, stdout, program_name); + goto exit; + case 'u': + usage(optContext, stdout, program_name); + goto exit; + case 'v': + version(optContext, stdout, program_name); + goto exit; + case 'l': + license(optContext, stdout, program_name); + goto exit; + } + } + + // set show_target by default + if (!(opts.show_all + opts.show_target + opts.show_working_dir + opts.show_args + + opts.show_showCmd + opts.show_icon + opts.show_icon_offset + + opts.show_desc)) { opts.show_target = 1; } + + /* get the remaining arguments */ + loose_args = poptGetArgs(optContext); + + if (loose_args && *loose_args) { + if ((opts.target_fname = strdup(*loose_args)) == NULL) { + fprintf(stderr, "%s: memory allocation error\n", program_name); + result = ERR_SYS; + goto exit; + } + loose_args++; + if (loose_args && *loose_args) { + fprintf(stderr, "%s: Too many arguments: ", program_name); + while (*loose_args) { fprintf(stderr, "%s ", *loose_args++); } + fprintf(stderr, "\n"); + usage(optContext, stderr, program_name); + result = ERR_USER; + } else { + /************** Main Program ***********/ + result = readshortcut(opts, optContext); + } + } else { + fprintf(stderr, "%s: SHORTCUT not specified\n", program_name); + usage(optContext, stderr, program_name); + result = ERR_USER; + } + +exit: + poptFreeContext(optContext); + free(program_name); + free(opts.target_fname); + return result; +} + +int readshortcut(optvals opts, poptContext optContext) { + HRESULT hres; + IShellLink *shell_link; + IPersistFile *persist_file; + char strPath[MAX_PATH]; + char strBuff[BUFF_SIZE]; + int iBuff; + + int result = ERR_NONE; /* the value to return on exit */ + + /* Add suffix to link name if necessary */ + if (strlen (opts.target_fname) > 4) { + int tmp = strlen (opts.target_fname) - 4; + if (strncmp (opts.target_fname + tmp, ".lnk", 4) != 0) { + opts.target_fname = (char *)realloc(opts.target_fname, strlen(opts.target_fname) + 1 + 4); + if (opts.target_fname == NULL) { + fprintf(stderr, "%s: memory allocation error\n", program_name); + return (ERR_SYS); + } + strcat (opts.target_fname, ".lnk"); + } + } + else { + opts.target_fname = (char *)realloc(opts.target_fname, strlen(opts.target_fname) + 1 + 4); + if (opts.target_fname == NULL) { + fprintf(stderr, "%s: memory allocation error\n", program_name); + return (ERR_SYS); + } + strcat (opts.target_fname, ".lnk"); + } + + /* if there's no colon in the path, it's POSIX and we should convert to win32 */ + if (strchr (opts.target_fname, ':') == NULL) { + char *strTmpPath = (char*)malloc(MAX_PATH); + if (strTmpPath == NULL) { + fprintf(stderr, "%s: memory allocation error\n", program_name); + return (ERR_SYS); + } + cygwin_conv_to_full_win32_path (opts.target_fname, strTmpPath); + free (opts.target_fname); + opts.target_fname = strTmpPath; + } + + hres = OleInitialize (NULL); + if (hres != S_FALSE && hres != S_OK) { + fprintf (stderr, "%s: Could not initialize OLE interface\n", program_name); + return (ERR_WIN); + } + + /* Get a pointer to the IShellLink interface. */ + hres = CoCreateInstance (&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (void **) &shell_link); + + if (!SUCCEEDED(hres)) { + fprintf (stderr, "%s: CoCreateInstance failed\n", program_name); + return (ERR_WIN); + } + + /* Get a pointer to the IPersistFile interface. */ + hres = shell_link->lpVtbl->QueryInterface(shell_link, &IID_IPersistFile, (void **) &persist_file); + + if (SUCCEEDED(hres)) { + WCHAR wsz[MAX_PATH]; + + /* Ensure that the string is Unicode. */ + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)opts.target_fname, -1, wsz, MAX_PATH); + + /* Load the shortcut. */ + hres = persist_file->lpVtbl->Load(persist_file, wsz, STGM_READ); + + if (SUCCEEDED(hres)) { + /* read stuff from the link object and print it to the screen */ + if (opts.show_all || opts.show_target) { + shell_link->lpVtbl->GetPath(shell_link, strPath, MAX_PATH, NULL, SLGP_RAWPATH); + if (opts.show_field_names) { printf("Target: "); } + formatPath(strPath, opts.pathType); + printf("%s\n", strPath); + } + if (opts.show_all || opts.show_working_dir) { + shell_link->lpVtbl->GetWorkingDirectory(shell_link, strPath, MAX_PATH); + if (opts.show_field_names) { printf("Working Directory: "); } + formatPath(strPath, opts.pathType); + printf("%s\n", strPath); + } + if (opts.show_all || opts.show_args) { + shell_link->lpVtbl->GetArguments(shell_link, strBuff, BUFF_SIZE); + if (opts.show_field_names) { printf("Arguments: "); } + printf("%s\n", strBuff); + } + if (opts.show_all || opts.show_showCmd) { + shell_link->lpVtbl->GetShowCmd(shell_link, &iBuff); + if (opts.show_field_names) { printf("Show Command: "); } + + switch (iBuff) { + case SW_SHOWNORMAL: + printf("Normal\n"); + break; + case SW_SHOWMINIMIZED: + case SW_SHOWMINIMIZED_SEVEN: + printf("Minimized\n"); + break; + case SW_SHOWMAXIMIZED: + printf("Maximized\n"); + break; + } + } + if (opts.show_all || opts.show_icon || opts.show_icon_offset) { + shell_link->lpVtbl->GetIconLocation(shell_link, strPath, MAX_PATH, &iBuff); + if (opts.show_all || opts.show_icon) { + if (opts.show_field_names) { printf("Icon Library: "); } + formatPath(strPath, opts.pathType); + printf("%s\n", strPath); + } + if (opts.show_all || opts.show_icon_offset) { + if (opts.show_field_names) { printf("Icon Library Offset: "); } + printf("%d\n", iBuff); + } + } + if (opts.show_all || opts.show_desc) { + shell_link->lpVtbl->GetDescription(shell_link, strBuff, BUFF_SIZE); + if (opts.show_field_names) { printf("Description: "); } + printf("%s\n", strBuff); + } + } + else { + fprintf (stderr, "%s: Load failed on %s\n", program_name, opts.target_fname); + result = ERR_WIN; + } + + /* Release the pointer to the IPersistFile interface. */ + persist_file->lpVtbl->Release(persist_file); + } + else { + fprintf (stderr, "%s: QueryInterface failed\n", program_name); + result = ERR_WIN; + } + + /* Release the pointer to the IShellLink interface. */ + shell_link->lpVtbl->Release(shell_link); + + return(result); +} + +/* change the path to the proper format */ +void formatPath (char * strPath, int format) { + if (format == PATH_WIN) { return; } /* windows is the default */ + else { + // convert to posix path + char strTmp[MAX_PATH]; + strcpy(strTmp, strPath); + cygwin_conv_to_full_posix_path(strTmp, strPath); + } +} + +static const char * getVersion() { + return versionID; +} + +static void printTopDescription(FILE * f, char * name) { + fprintf(f, "%s version %s\n", name, getVersion()); + fprintf(f, " Reads and outputs data from a Windows shortcut (.lnk) file.\n\n"); +} + +static void printBottomDescription(FILE * f, char * name) { + fprintf(f, "\nNOTE: The SHORTCUT argument may be in Windows or Unix format.\n"); +} + +static void printLicense(FILE * f, char * name) { + fprintf(f, "This program is free software; you can redistribute it and/or\n"); + fprintf(f, "modify it under the terms of the GNU General Public License\n"); + fprintf(f, "as published by the Free Software Foundation; either version 2\n"); + fprintf(f, "of the License, or (at your option) any later version.\n"); + fprintf(f, "\n"); + fprintf(f, "This program is distributed in the hope that it will be useful,\n"); + fprintf(f, "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); + fprintf(f, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); + fprintf(f, "GNU General Public License for more details.\n"); + fprintf(f, "\n"); + fprintf(f, "You should have received a copy of the GNU General Public License\n"); + fprintf(f, "along with this program; if not, write to the Free Software\n"); + fprintf(f, "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"); + fprintf(f, "\n"); + fprintf(f, "See the COPYING file for license information.\n"); +} + +static void usage(poptContext optCon, FILE * f, char * name) { + poptPrintUsage(optCon, f, 0); +} + +static void help(poptContext optCon, FILE * f, char * name) { + printTopDescription(f, name); + poptPrintHelp(optCon, f, 0); + printBottomDescription(f, name); +} + +static void version(poptContext optCon, FILE * f, char * name) { + printTopDescription(f, name); +} + +static void license(poptContext optCon, FILE * f, char * name) { + printTopDescription(f, name); + printLicense(f, name); +} -- 2.43.5