On Wed, Jul 26, 2006 at 11:18:52AM -0500, Bo Peng wrote: > > We could arrange things such that the program looks at its name and if > > it isn't called lyx.exe it behaves exactly as it does now, otherwise, > > after parsing the env vars, it prefixes the remaining parameters on the > > command line with "cmd /c lyxc.exe". > > It becomes too magical then. I would prefer either > > 1. we keep it as it is (maybe change /var to -var), and pass cmd /c > lyxc.exe explicitly, this allows some flexibility for the windows > installer, and it is not terribly difficult to use. > > or > > 2. completely trnasform this to a lyx.exe that can take -var=val in > additional to what the real lyx.exe is doing now. > > > Do you want me to make the change? > > Yes, please.
Please, find attached a patch for hidecmd.c. It works in the following way. After renaming the real lyx executable as lyxc.exe and hidecmd.exe as lyx.exe lyx.exe var=val var1=val1 -dbg 4 -geometry "10x10+10-10" file1.lyx file2.lyx results in set var=val set var1=val1 cmd /c ""path\to\lyxc.exe" -dbg 4 -geometry "10x10+10-10" file1.lyx file2.lyx" The behavior with respect to environment variables is similar to the *nix env program, i.e., everything in the form a=b is taken as a request to set the env var "a" to the value "b". To avoid this, one can use quoting, such that lyx.exe var="val" "var1=val1" -dbg 4 file.lyx results in set var="val" cmd /c ""path\to\lyxc.exe "var1=val1" -dbg 4 file.lyx" I avoided any call to standard C functions in order to keep the size of the executable small (the stripped size is 7.5 Kb with mingw). Please test. It works for me. -- Enrico
Index: development/Win32/hidecmd.c =================================================================== --- development/Win32/hidecmd.c (revision 14498) +++ development/Win32/hidecmd.c (working copy) @@ -12,39 +12,34 @@ */ /** - * This utility function is used to start lyx under windows, but - * hide the console window. It is adapted from program hidec at + * This is a wrapper program to start lyx under windows hiding its + * console window. It is adapted from program hidec at * http://www.msfn.org/board/index.php?showtopic=49184&mode=threaded * + * This wrapper should be named lyx.exe and placed in the same directory + * as the real lyx executable which _must_ be renamed as lyxc.exe + * * Usage: - * hidecmd [/w] [/VAR=val] <filename> [<params>] - * where: /w wait for program termination - * /VAR=val set VAR=val - * <filename> executable program - * <params> program parameters + * hidecmd [VAR=val ...] [<params>] + * where: + * VAR=val set VAR=val (multiple settings may be specified) + * <params> parameters for the real lyx executable * - * How to built this program: + * How to build this program: * msvc: * cl.exe hidecmd.c /GA /O1 /link /subsystem:windows \ * kernel32.lib advapi32.lib user32.lib libcmt.lib * mingw/gcc: - * gcc -mno-cygwin -mwindows hidecmd.c -o hidecmd + * gcc -mwindows hidecmd.c -o hidecmd * */ #include <process.h> #include <windows.h> - -char * usage = "hidecmd [/w] [/VAR=val] <filename> [<params>]\n" - " where: /w wait for program termination\n" - " /VAR=val set VAR=val\n" - " <filename> executable program\n" - " <params> program parameters\n"; - #ifdef _MSC_VER // -// Using msvc, the following progma can reduce executable size from +// Using msvc, the following pragmas can reduce executable size from // 44k to 6k. I am not sure if mingw/gcc can take advantage of them // though. // @@ -64,19 +59,25 @@ { STARTUPINFO si; PROCESS_INFORMATION pi; - int bWait = 0; DWORD exitcode = 0; char delim = ' '; - char var[128]; - char val[128]; + char * var; + char * val; + // two " are needed here: the first one quotes the entire + // command, the second one the executable name + char cmd[1024] = "cmd /c \"\""; + // i0 = strlen(cmd); + int i0 = 9; + int i; int err = 0; + int inquote; char * cmdLine = GetCommandLine(); - int i; - // start and end of variable/value - char * s; - char * e; + // the name of the executable to be launched + // (must be in the same directory) + char * lyxc = "lyxc.exe"; - // use GetCommandLine(), command name is included. Skip it + // When using GetCommandLine(), command name is included + // but the full path may be missing, so skip it. if (*cmdLine == '\"') { delim = '\"'; cmdLine++; @@ -89,95 +90,106 @@ cmdLine++; // skip over ' ' or '\t' - while ((*cmdLine != 0) && ((*cmdLine == ' ') || (*cmdLine == '\t'))) + while (*cmdLine != 0 && (*cmdLine == ' ' || *cmdLine == '\t')) cmdLine++; - while (*cmdLine == '/') { - // /w or /W option - if (((cmdLine[1] == 'w') || (cmdLine[1] == 'W')) && - (cmdLine[2] == ' ')) + // Use GetModuleFileName() to get the path to lyxc.exe + GetModuleFileName(0, cmd + i0, sizeof(cmd) / 2); + + // substitute executable name + for (i = i0; cmd[i] != 0; ++i); + + for (--i; i >= i0 && cmd[i] != '\\' && cmd[i] != '/'; --i); + + for (++i; *lyxc && i < sizeof(cmd); ) + cmd[i++] = *lyxc++; + + // check whether lyxc.exe is there + cmd[i] = '\0'; + lyxc = cmd + i0; + if (GetFileAttributesA(lyxc) == 0xFFFFFFFF) { + exitcode = GetLastError(); + MessageBox(0, lyxc, "Error: cannot find the real LyX executable below", 0); + ExitProcess(exitcode); + } + + // it's there, so finish quoting filename + cmd[i++] = '\"'; + + // parse remainder of command line + while (*cmdLine != 0 && !err) { + if (i < sizeof(cmd)) + cmd[i++] = ' '; + else + err = 1; + + if ((*cmdLine >= 'A' && *cmdLine <= 'Z') || + (*cmdLine >= 'a' && *cmdLine <= 'z')) + var = cmd + i; + else + var = NULL; + + val = NULL; + inquote = 0; + while (!err && ((*cmdLine != 0 && *cmdLine != ' ' && + *cmdLine != '\t') || inquote)) { - bWait = 1; - cmdLine += 3; - // environment variable - } else { - cmdLine++; + if (*cmdLine == '\"') + inquote = 1 - inquote; - // get var - s = var; - e = s + sizeof(var) - 1; - - while (*cmdLine != 0 && *cmdLine != '=') { - if (s < e) { - *s++ = *cmdLine++; - } else { - cmdLine++; - err = 1; - } - } + if (var && *cmdLine == '=' && !inquote) + val = cmd + i; - // get value - *s = 0; - if (*cmdLine == '=') - cmdLine++; + if (i < sizeof(cmd)) + cmd[i++] = *cmdLine; + else + err = 1; - delim = ' '; - - if (*cmdLine == '\"') { - delim = '\"'; - cmdLine++; - } + cmdLine++; + } - s = val; - e = s + sizeof(val) - 1; - - while (*cmdLine != delim && *cmdLine != 0) { - if (s < e) { - *s++ = *cmdLine++; - } else { - cmdLine++; - err = 1; - } + if (var && val && !err) { + *val++ = '\0'; // mark end of var + if (*val == '\"') { // account for quoted val + ++val; + --i; } - *s = 0; - if (*cmdLine == delim) - cmdLine++; - + cmd[i] = '\0'; // mark end of val + i = var - cmd - 1; // reset pointer SetEnvironmentVariable(var, val); // MessageBox(0, val, var, 0); } // skip spaces - while ((*cmdLine != 0) && ((*cmdLine == ' ') || (*cmdLine == '\t'))) + while (*cmdLine != 0 && (*cmdLine == ' ' || *cmdLine == '\t')) cmdLine++; } - // report error if there is no parameter - if (*cmdLine == 0) - { - MessageBox(0, usage, "Error: Incorrect usage", 0); - ExitProcess(0); - } + if (i < sizeof(cmd) - 1) { + // finish quoting the entire command + cmd[i++] = '\"'; + cmd[i] = '\0'; + } else + err = 1; if (err) { - MessageBox(0, "One of the specified environment variables or its value is too long.", "Error: Variable name or value too long", 0); + MessageBox(0, "Please, use a shorter command line.", + "Error: command line is too long", 0); ExitProcess(0); } // create process with new console // memset(&si, 0, sizeof(si)); - s = (char *) &si; + val = (char *) &si; for (i = 0; i < sizeof(si); ++i) - s[i] = 0x00; + val[i] = 0x00; si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; - if (CreateProcess(NULL, cmdLine, + if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { - if (bWait) - WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); }