]> git.lyx.org Git - features.git/blob - development/Win32/hidecmd.c
Update development/Win32/hidecmd.c, from Enrico Forestieri
[features.git] / development / Win32 / hidecmd.c
1 /* -*- C -*- */
2 /**
3  * \file hidecmd.c
4  * This file is part of LyX, the document processor.
5  * Licence details can be found in the file COPYING.
6  *
7  * \author hasherfrog
8  * \author Bo Peng
9  * \author Enrico Forestieri
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 /**
15  *  This is a wrapper program to start lyx under windows hiding its
16  *  console window. It is adapted from program hidec at
17  *  http://www.msfn.org/board/index.php?showtopic=49184&mode=threaded
18  *
19  *  This wrapper should be named lyx.exe and placed in the same directory
20  *  as the real lyx executable which _must_ be renamed as lyxc.exe
21  *
22  *  Usage: 
23  *      hidecmd [VAR=val ...] [<params>]
24  *  where:
25  *         VAR=val    set VAR=val (multiple settings may be specified)
26  *         <params>   parameters for the real lyx executable
27  *
28  *  How to build this program:
29  *    msvc:
30  *          cl.exe hidecmd.c /GA /O1 /Felyx.exe /link /subsystem:windows \
31  *                 kernel32.lib advapi32.lib user32.lib libcmt.lib
32  *    mingw/gcc:
33  *      gcc -mwindows hidecmd.c -o lyx.exe
34  *
35  */
36
37 #include <process.h>
38 #include <windows.h>
39
40 #ifdef _MSC_VER
41 //
42 // Using msvc, the following pragmas can reduce executable size from
43 // 44k to 6k. I am not sure if mingw/gcc can take advantage of them
44 // though.
45 //
46 // do not link to default libraries
47 #pragma comment(linker,"/NODEFAULTLIB")
48 // unite code and data section (make the program smaller)
49 #pragma comment(linker,"/MERGE:.rdata=.text")
50 // resolve record in section of code
51 #pragma comment(linker,"/SECTION:.text,EWR")
52 // the new entry point (the WinMain entry point is big)
53 #pragma comment(linker,"/ENTRY:NewWinMain")
54
55 void NewWinMain(void)
56 #else  // mingw/gcc uses this entry point
57 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszCmd, int nCmd)
58 #endif
59 {
60         STARTUPINFO si;
61         PROCESS_INFORMATION pi;
62         DWORD exitcode = 0;
63         char delim = ' ';
64         char * var;
65         char * val;
66         // two " are needed here: the first one quotes the entire
67         // command, the second one the executable name
68         char cmd[1024] = "cmd /c \"\"";
69         //  i0 = strlen(cmd);
70         int i0 = 9;
71         int i;
72         int err = 0;
73         int inquote;
74         char * cmdLine = GetCommandLine();
75         // the name of the executable to be launched
76         // (must be in the same directory)
77         char * lyxc = "lyxc.exe";
78
79         // When using GetCommandLine(), command name is included
80         // but the full path may be missing, so skip it.
81         if (*cmdLine == '\"') {
82                 delim = '\"';
83                 cmdLine++;
84         }
85
86         while (*cmdLine != delim && *cmdLine != 0)
87                 cmdLine++;
88
89         if (*cmdLine == delim)
90                 cmdLine++;
91
92         // skip over ' ' or '\t'
93         while (*cmdLine != 0 && (*cmdLine == ' ' || *cmdLine == '\t'))
94                 cmdLine++; 
95
96         // Use GetModuleFileName() to get the path to lyxc.exe
97         GetModuleFileName(0, cmd + i0, sizeof(cmd) / 2);
98
99         // substitute executable name
100         for (i = i0; cmd[i] != 0; ++i);
101
102         for (--i; i >= i0 && cmd[i] != '\\' && cmd[i] != '/'; --i);
103
104         for (++i; *lyxc && i < sizeof(cmd); )
105                 cmd[i++] = *lyxc++;
106
107         // check whether lyxc.exe is there
108         cmd[i] = '\0';
109         lyxc = cmd + i0;
110         if (GetFileAttributesA(lyxc) == 0xFFFFFFFF) {
111                 exitcode = GetLastError();
112                 MessageBox(0, lyxc, "Error: cannot find the real LyX executable below", 0);
113                 ExitProcess(exitcode);
114         }
115
116         // it's there, so finish quoting filename
117         cmd[i++] = '\"';
118
119         // parse remainder of command line
120         while (*cmdLine != 0 && !err) {
121                 if (i < sizeof(cmd))
122                         cmd[i++] = ' ';
123                 else
124                         err = 1;
125
126                 if ((*cmdLine >= 'A' && *cmdLine <= 'Z') ||
127                     (*cmdLine >= 'a' && *cmdLine <= 'z'))
128                         var = cmd + i;
129                 else
130                         var = NULL;
131
132                 val = NULL;
133                 inquote = 0;
134                 while (!err && ((*cmdLine != 0 && *cmdLine != ' ' &&
135                                 *cmdLine != '\t') || inquote))
136                 {
137                         if (*cmdLine == '\"')
138                                 inquote = 1 - inquote;
139
140                         if (var && *cmdLine == '=' && !inquote)
141                                 val = cmd + i;
142
143                         if (i < sizeof(cmd))
144                                 cmd[i++] = *cmdLine;
145                         else
146                                 err = 1;
147
148                         cmdLine++;
149                 }
150
151                 if (var && val && !err) {
152                         *val++ = '\0';          // mark end of var
153                         if (*val == '\"') {     // account for quoted val
154                                 ++val;
155                                 --i;
156                         }
157                         cmd[i] = '\0';          // mark end of val
158                         i = var - cmd - 1;      // reset pointer
159                         SetEnvironmentVariable(var, val);
160                         // MessageBox(0, val, var, 0);
161                 }
162
163                 // skip spaces
164                 while (*cmdLine != 0 && (*cmdLine == ' ' || *cmdLine == '\t')) 
165                         cmdLine++;
166         }
167
168         if (i < sizeof(cmd) - 1) {
169                 // finish quoting the entire command
170                 cmd[i++] = '\"';
171                 cmd[i] = '\0';
172         } else
173                 err = 1;
174         
175         if (err) {
176                 MessageBox(0, "Please, use a shorter command line.",
177                                 "Error: command line is too long", 0);
178                 ExitProcess(0);
179         }
180
181         // create process with new console
182         // memset(&si, 0, sizeof(si));
183         val = (char *) &si;
184         for (i = 0; i < sizeof(si); ++i)
185                 val[i] = 0x00;
186         si.cb = sizeof(si);
187         si.dwFlags = STARTF_USESHOWWINDOW;
188         si.wShowWindow = SW_HIDE;
189         if (CreateProcess(NULL, cmd,
190                 NULL, NULL, FALSE, CREATE_NEW_CONSOLE,
191                 NULL, NULL, &si, &pi))
192         {
193                 CloseHandle( pi.hProcess );
194                 CloseHandle( pi.hThread );
195         }
196         else
197                 exitcode = GetLastError();
198
199         /* terminate this */
200         ExitProcess(exitcode);
201 }