icon: Convert windows stub into launcher program
authorKeith Packard <keithp@keithp.com>
Sun, 29 Mar 2015 19:08:42 +0000 (12:08 -0700)
committerKeith Packard <keithp@keithp.com>
Sun, 29 Mar 2015 19:08:42 +0000 (12:08 -0700)
Instead of an empty windows stub that exists only to hold icons, add
useful code that allows it to find and run the related java
application. This also adds more resources to that application to
provide more information to Windows too.

Signed-off-by: Keith Packard <keithp@keithp.com>
icon/Makefile.am
icon/make-rc [new file with mode: 0755]
icon/windows-stub.c

index c08e9236e91ac75392edd300dea1f9440d1af2e4..af238ac42527da025ff403481c046ba58146b0b7 100644 (file)
@@ -150,14 +150,21 @@ SUFFIXES=.svg .build .icns .ico .rc .o .exe
        icotool -c -o $@ $(shell for i in $(WIN_RES); do echo $*-$$i.png; done)
 
 .ico.rc:
-       echo '101 ICON "$*.ico"' > $@
+       ./make-rc "$*" $(VERSION) > $@
 
 
 MINGCC32=i686-w64-mingw32-gcc
 MINGWINDRES=i686-w64-mingw32-windres
+MINGFLAGS=-Wall -DWINDOWS -mwindows
+MINGLIBS=-lshlwapi
 
 .rc.o:
        $(MINGWINDRES) $*.rc $@
 
 .o.exe:
-       $(MINGCC32) -o $@ windows-stub.c $*.o
+       $(MINGCC32) -o $@ $(MINGFLAGS) windows-stub.o $*.o $(MINGLIBS)
+
+$(EXE_FILES): windows-stub.o make-rc
+
+windows-stub.o: windows-stub.c
+       $(MINGCC32) -c $(MINGFLAGS) windows-stub.c
diff --git a/icon/make-rc b/icon/make-rc
new file mode 100755 (executable)
index 0000000..de64727
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+COMPANY="Altus Metrum, LLC"
+PRODUCT="Altus Metrum"
+
+case "$1" in
+    *altosui*)
+       PRODUCT="AltosUI"
+       ;;
+    *telegps*)
+       PRODUCT="TeleGPS"
+       ;;
+    *micropeak*)
+       PRODUCT="MicroPeak"
+       ;;
+esac
+
+VERSION="$2"
+VERSION_COMMA=`echo "$VERSION" | sed 's/\./,/g'`
+INTERNAL_NAME=`basename $1`
+EXE_NAME="$INTERNAL_NAME".exe
+YEAR=`date +%Y`
+
+cat <<EOF
+101 ICON "$1.ico"
+1 VERSIONINFO
+FILEVERSION $VERSION_COMMA
+PRODUCTVERSION $VERSION_COMMA
+FILEFLAGSMASK 0
+FILEOS 0x40004
+FILETYPE 1
+{
+ BLOCK "StringFileInfo"
+ {
+  BLOCK "040904E4"
+  {
+   VALUE "Comments", "$COMPANY $PRODUCT"
+   VALUE "CompanyName", "$COMPANY"
+   VALUE "FileDescription", "$PRODUCT"
+   VALUE "FileVersion", "$VERSION"
+   VALUE "InternalName", "$INTERNAL_NAME"
+   VALUE "LegalCopyright", "Copyright $YEAR, $COMPANY"
+   VALUE "OriginalFilename", "$EXE_NAME"
+   VALUE "ProductName", "$PRODUCT"
+   VALUE "ProductVersion", "$VERSION"
+  }
+ }
+ BLOCK "VarFileInfo"
+ {
+  VALUE "Translation", 0x409, 1252
+ }
+}
+EOF
index 8df3e0aafc215dc2b81dae1a8191843960c936f6..e075a02d9dff4f91b41f2b0a2aac00da7c685c20 100644 (file)
@@ -1,2 +1,201 @@
-__stdcall
-WinMain(int a, int b, int c, int d) { return 0; }
+/*
+ * Copyright © 2015 Keith Packard <keithp@keithp.com>
+ *
+ * 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; 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.
+ */
+
+/* A windows stub program to launch a java program with suitable parameters
+ *
+ * Given that the name of this exe is altusmetrum-foo.exe living in directory bar, and
+ * that it was run with 'args' extra command line parameters, run:
+ *
+ *     javaw.exe -Djava.library.path="bar" -jar "bar/foo-fat.jar" args
+ */
+
+#define _UNICODE
+#define UNICODE
+#include <stdlib.h>
+#include <windows.h>
+#include <setupapi.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <shlwapi.h>
+
+/* Concatenate a list of strings together
+ */
+static LPTSTR
+wcsbuild(LPTSTR first, ...)
+{
+       va_list args;
+       int     len;
+       LPTSTR  buf;
+       LPTSTR  arg;
+
+       buf = wcsdup(first);
+       va_start(args, first);
+       while ((arg = va_arg(args, LPTSTR)) != NULL) {
+               len = wcslen(buf) + wcslen(arg) + 1;
+               buf = realloc(buf, len * sizeof (wchar_t));
+               wcscat(buf, arg);
+       }
+       va_end(args);
+       return buf;
+}
+
+/* Quote a single string, taking care to escape embedded quote and
+ * backslashes within
+ */
+static LPTSTR
+quote_arg(LPTSTR arg)
+{
+       LPTSTR  result;
+       LPTSTR  in, out;
+       int     out_len = 3;    /* quotes and terminating null */
+
+       /* Find quote and backslashes */
+       for (in = arg; *in; in++) {
+               switch (*in) {
+               case '"':
+               case '\\':
+                       out_len += 2;
+                       break;
+               default:
+                       out_len++;
+                       break;
+               }
+       }
+
+       result = malloc ((out_len + 1) * sizeof (wchar_t));
+       out = result;
+       *out++ = '"';
+       for (in = arg; *in; in++) {
+               switch (*in) {
+               case '"':
+               case '\\':
+                       *out++ = '\\';
+                       break;
+               }
+               *out++ = *in;
+       }
+       *out++ = '"';
+       *out++ = '\0';
+       return result;
+}
+
+/* Construct a single string from a list of arguments
+ */
+static LPTSTR
+quote_args(LPTSTR *argv, int argc)
+{
+       LPTSTR  result = NULL, arg;
+       int     i;
+
+       result = malloc(1 * sizeof (wchar_t));
+       result[0] = '\0';
+       for (i = 0; i < argc; i++) {
+               arg = quote_arg(argv[i]);
+               result = realloc(result, (wcslen(result) + 1 + wcslen(arg) + 1) * sizeof (wchar_t));
+               wcscat(result, L" ");
+               wcscat(result, arg);
+               free(arg);
+       }
+       return result;
+}
+
+/* Return the directory portion of the provided file
+ */
+static LPTSTR
+get_dir(LPTSTR file)
+{
+       DWORD   len = GetFullPathName(file, 0, NULL, NULL);
+       LPTSTR  full = malloc (len * sizeof (wchar_t));
+       GetFullPathName(file, len, full, NULL);
+       PathRemoveFileSpec(full);
+       return full;
+}
+
+/* Convert a .exe name into a -fat.jar name, starting
+ * by computing the complete path name of the source filename
+ */
+static LPTSTR
+make_jar(LPTSTR file)
+{
+       DWORD   len = GetFullPathName(file, 0, NULL, NULL);
+       LPTSTR  full = malloc (len * sizeof (wchar_t));
+       LPTSTR  base_part;
+       LPTSTR  jar;
+       LPTSTR  dot;
+       GetFullPathName(file, len, full, &base_part);
+       static const wchar_t head[] = L"altusmetrum-";
+
+       if (wcsncmp(base_part, head, wcslen(head)) == 0)
+               base_part += wcslen(head);
+       dot = wcsrchr(base_part, '.');
+       if (dot)
+               *dot = '\0';
+       jar = wcsdup(base_part);
+       PathRemoveFileSpec(full);
+       return wcsbuild(full, L"\\", jar, L"-fat.jar", NULL);
+}
+
+/* Build the complete command line from the pieces
+ */
+static LPTSTR
+make_cmd(LPTSTR dir, LPTSTR jar, LPTSTR quote_args)
+{
+       LPTSTR  quote_dir = quote_arg(dir);
+       LPTSTR  quote_jar = quote_arg(jar);
+       LPTSTR  cmd;
+
+       cmd = wcsbuild(L"javaw.exe -Djava.library.path=", quote_dir, L" -jar ", quote_jar, quote_args, NULL);
+       free(quote_jar);
+       free(jar);
+       free(quote_dir);
+       return cmd;
+}
+
+int WINAPI
+WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line_a, int cmd_show)
+{
+       STARTUPINFO             startup_info;
+       PROCESS_INFORMATION     process_information;
+       BOOL                    result;
+       wchar_t                 *command_line;
+       int                     argc;
+       LPTSTR                  *argv = CommandLineToArgvW(GetCommandLine(), &argc);
+       LPTSTR                  my_dir;
+       LPTSTR                  my_jar;
+       LPTSTR                  args = quote_args(argv + 1, argc - 1);
+
+       my_dir = get_dir(argv[0]);
+       my_jar = make_jar(argv[0]);
+       command_line = make_cmd(my_dir, my_jar, args);
+       memset(&startup_info, '\0', sizeof startup_info);
+       startup_info.cb = sizeof startup_info;
+       result = CreateProcess(NULL,
+                              command_line,
+                              NULL,
+                              NULL,
+                              FALSE,
+                              CREATE_NO_WINDOW,
+                              NULL,
+                              NULL,
+                              &startup_info,
+                              &process_information);
+       if (result) {
+               CloseHandle(process_information.hProcess);
+               CloseHandle(process_information.hThread);
+       }
+       exit(0);
+}