Implementation of 'start', take 2
I had a look at cygstart, but it doesn't even try to be commandline-compatible with Microsoft's start.exe. Oh, well. I've verified that this implementation of start can do both start notepad and start foo.txt and that it obeys all the options obeyed by WindowsMe's start.exe. It also implements the /L option to print out the LGPL. (Do we have a convention for what this option, required by the LGPL, should be?) I'd rather compile it as a .exe rather than a winelib app - is there a way to do that in the Wine tree? Also, what do I have to do to cause the resulting .exe to end up as %windir%/command/start.exe, so it's in the same place as it is in real Microsoft Windows? BTW, to make 'start foo.txt' work, you need the registry entries [HKEY_CLASSES_ROOT\.txt] @="txtfile" "Content Type"="text/plain" [HKEY_CLASSES_ROOT\txtfile\shell\open\command] @="C:\\WINDOWS\\NOTEPAD.EXE %1" I verified that removing either of these on WinMe caused 'start foo.txt' to fail. I did not verify that, when you use the /w flag, the exit status of the subprocess is returned in the same way as it's done in Windows. Thanks, Dan -- Dan Kegel http://www.kegel.com http://counter.li.org/cgi-bin/runscript/display-person.cgi?user=78045 Index: configure.ac =================================================================== RCS file: /home/wine/wine/configure.ac,v retrieving revision 1.116 diff -u -r1.116 configure.ac --- configure.ac 4 Jan 2003 02:52:05 -0000 1.116 +++ configure.ac 18 Jan 2003 02:41:32 -0000 @@ -1497,6 +1497,7 @@ programs/regtest/Makefile programs/rpcss/Makefile programs/rundll32/Makefile +programs/start/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile Index: programs/Makefile.in =================================================================== RCS file: /home/wine/wine/programs/Makefile.in,v retrieving revision 1.33 diff -u -r1.33 Makefile.in --- programs/Makefile.in 4 Jan 2003 02:52:05 -0000 1.33 +++ programs/Makefile.in 18 Jan 2003 02:41:32 -0000 @@ -19,6 +19,7 @@ regtest \ rpcss \ rundll32 \ + start \ uninstaller \ view \ wcmd \ @@ -43,6 +44,7 @@ regsvr32 \ rpcss \ rundll32 \ + start \ uninstaller \ wcmd \ wineboot \ @@ -73,6 +75,7 @@ # Symlinks to apps that we want to run from inside the source tree SYMLINKS = \ + start.exe \ rpcss.exe \ wcmd.exe \ wineconsole.exe \ @@ -136,6 +139,9 @@ winhelp.exe$(DLLEXT): winhelp/winhelp.exe$(DLLEXT) $(RM) $@ && $(LN_S) winhelp/winhelp.exe$(DLLEXT) $@ + +start.exe$(DLLEXT): start/start.exe$(DLLEXT) + $(RM) $@ && $(LN_S) start/start.exe$(DLLEXT) $@ wcmd/wcmd.exe$(DLLEXT): wcmd wineconsole/wineconsole.exe$(DLLEXT): wineconsole --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ programs/start/Makefile.in 2003-01-16 08:20:35.000000000 -0800 @@ -0,0 +1,13 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = start.exe +APPMODE = cui +IMPORTS = shell32 + +C_SRCS = start.c + +(a)MAKE_PROG_RULES@ + +### Dependencies: --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ programs/start/start.c 2003-01-17 17:34:36.000000000 -0800 @@ -0,0 +1,199 @@ +/* + * Start a program using ShellExecuteEx, optionally wait for it to finish + * Compatible with Microsoft's "c:\windows\command\start.exe" + * + * Copyright 2003 Dan Kegel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 + */ + +#include "config.h" +#include "wine/debug.h" + +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <shlobj.h> + +#define VERSIONMSG "start.exe version 0.1 Copyright (C) 2003, Dan Kegel" + +/** + Output given message to stdout without formatting. +*/ +static void output(const char *message) +{ + DWORD count; + WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), message, strlen(message), &count, NULL); +} + +/** + Output given message, + followed by ": ", + followed by description of given GetLastError() value to stdout, + followed by a trailing newline, + then terminate. +*/ +static void fatal_error(const char *msg, DWORD error_code) +{ + LPVOID lpMsgBuf; + int status; + + output(msg); + output(": "); + status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, 0, (LPTSTR) & lpMsgBuf, 0, NULL); + if (!status) { + output("FormatMessage failed\n"); + } else { + output(lpMsgBuf); + LocalFree((HLOCAL) lpMsgBuf); + output("\n"); + } + ExitProcess(1); +} + +static void usage() +{ + output("\ +Start a program, or open a document in the program normally used for files with that suffix.\n\ +Usage:\n\ +start [options] program_filename [...]\n\ +start [options] document_filename\n\ +\n\ +Options:\n\ +/M[inimized] Start the program minimized.\n\ +/MAX[imized] Start the program maximized.\n\ +/R[estored] Start the program normally (neither minimized nor maximized).\n\ +/W[ait] Wait for started program to finish, then exit with its exit code.\n\ +/L Show end-user license.\n\ +\n\ +" VERSIONMSG "\n\ +Start comes with ABSOLUTELY NO WARRANTY; for details run with /L option.\n\ +This is free software, and you are welcome to redistribute it\n\ +under certain conditions; run 'start /L' for details.\n\ +"); + ExitProcess(1); +} + +static void license() +{ + output("\ +" VERSIONMSG "\n\n\ +This program is free software; you can redistribute it and/or\n\ +modify it under the terms of the GNU Lesser Public License\n\ +as published by the Free Software Foundation; either version 2.1\n\ +of the License, or (at your option) any later version.\n\ +\n\ +This program is distributed in the hope that it will be useful,\n\ +but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ +GNU Lesser Public License for more details.\n\ +\n\ +You should have received a copy of the GNU Lesser Public License\n\ +along with this program; if not, write to the Free Software\n\ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\ +\n\ +See the COPYING.LIB file for license information.\n\ +"); + ExitProcess(1); +} + +int main(int argc, char *argv[]) +{ + char arguments[MAX_PATH]; + char *p; + SHELLEXECUTEINFO sei; + int argi; + + memset(&sei, 0, sizeof(sei)); + sei.cbSize = sizeof(sei); + sei.lpVerb = "open"; + sei.nShow = SW_SHOWNORMAL; + /* Dunno what these mean, but it looks like winMe's start uses them */ + sei.fMask = SEE_MASK_FLAG_DDEWAIT|SEE_MASK_FLAG_NO_UI; + + /* Canonical Microsoft commandline flag processing: + * flags start with /, are case insensitive, + * and may be run together in same word. + */ + for (argi=1; argi<argc; argi++) { + int ci; + + if (argv[argi][0] != '/') + break; + + /* Handle all options in this word */ + for (ci=0; argv[argi][ci]; ) { + /* Skip slash */ + ci++; + switch(argv[argi][ci]) { + case 'l': + case 'L': + license(); + break; /* notreached */ + case 'm': + case 'M': + if (argv[argi][ci+1] == 'a' || argv[argi][ci+1] == 'A') + sei.nShow = SW_SHOWMAXIMIZED; + else + sei.nShow = SW_SHOWMINIMIZED; + break; + case 'r': + case 'R': + /* sei.nShow = SW_SHOWNORMAL; */ + break; + case 'w': + case 'W': + sei.fMask |= SEE_MASK_NOCLOSEPROCESS; + break; + default: + printf("Option '%s' not recognized\n", argv[argi]+ci-1); + usage(); + } + /* Skip to next slash */ + while (argv[argi][ci] && (argv[argi][ci] != '/')) + ci++; + } + } + + if (argi == argc) + usage(); + + sei.lpFile = argv[argi++]; + + /* FIXME - prone to overflow */ + arguments[0] = 0; + for (p = arguments; argi < argc; argi++) + p += sprintf(p, " %s", argv[argi]); + + sei.lpParameters = arguments; + + if (!ShellExecuteEx(&sei)) { + fatal_error("Application could not be started, or no application associated with the specified file. ShellExecuteEx failed", GetLastError()); + } + + if (sei.fMask & SEE_MASK_NOCLOSEPROCESS) { + DWORD exitcode; + DWORD waitcode; + waitcode = WaitForSingleObject(sei.hProcess, INFINITE); + if (waitcode) + fatal_error("WaitForSingleObject", GetLastError()); + if (!GetExitCodeProcess(sei.hProcess, &exitcode)) + fatal_error("GetExitCodeProcess", GetLastError()); + /* fixme: haven't tested whether exit code works properly */ + ExitProcess(exitcode); + } + + ExitProcess(0); +}
I had a look at cygstart, but it doesn't even try to be commandline-compatible with Microsoft's start.exe. Oh, well.
Dan, what option would you implement that seems to be important in start.exe ? start has only 4 options : /m minimised and backround /max maximised and foreground /r foreground and start exits immediately (default) /w foreground, wait until termination. cygstart has many more options. in case you run "start foo.txt" it just starts the default action.
BTW, to make 'start foo.txt' work, you need the registry entries
shouldn't winedefault.reg implement these, as we provide notepad ?
[HKEY_CLASSES_ROOT\.txt] @="txtfile" "Content Type"="text/plain"
[HKEY_CLASSES_ROOT\txtfile\shell\open\command] @="C:\\WINDOWS\\NOTEPAD.EXE %1"
I verified that removing either of these on WinMe caused 'start foo.txt' to fail.
I did not verify that, when you use the /w flag, the exit status of the subprocess is returned in the same way as it's done in Windows.
===== Sylvain Petreolle spetreolle(a)users.sourceforge.net Fight against Spam ! http://www.euro.cauce.org/en/index.html ICQ #170597259 "Don't think you are. Know you are." Morpheus, in "Matrix". ___________________________________________________________ Do You Yahoo!? -- Une adresse @yahoo.fr gratuite et en français ! Yahoo! Mail : http://fr.mail.yahoo.com
Sylvain Petreolle wrote:
Dan, what option would you implement that seems to be important in start.exe ?
/w foreground, wait until termination.
cygstart has many more options.
But not /w. I'm not sure we really need all those other options. We really only need to offer the same options as Microsoft's start.exe does. Sure, I'd like to add cygstart's extra options, but let's get a working start with the right license first.
shouldn't winedefault.reg implement these, as we provide notepad ?
Hey, good point. I'll see if I can include that in the next version of my patch. - Dan -- Dan Kegel http://www.kegel.com http://counter.li.org/cgi-bin/runscript/display-person.cgi?user=78045
The /w is the easier to implement.
But not /w. I'm not sure we really need all those other options. We really only need to offer the same options as Microsoft's start.exe does. They _are_ needed. Actually you cant take winefile, right click and execute a custom action like install a .inf / execute an autorun.inf.
Sure, I'd like to add cygstart's extra options, but let's get a working start with the right license first.
shouldn't winedefault.reg implement these, as we provide notepad ?
Hey, good point. I'll see if I can include that in the next version of my patch.
===== Sylvain Petreolle spetreolle(a)users.sourceforge.net Fight against Spam ! http://www.euro.cauce.org/en/index.html ICQ #170597259 "Don't think you are. Know you are." Morpheus, in "Matrix". ___________________________________________________________ Do You Yahoo!? -- Une adresse @yahoo.fr gratuite et en français ! Yahoo! Mail : http://fr.mail.yahoo.com
participants (2)
-
Dan Kegel -
Sylvain Petreolle