]> git.lyx.org Git - lyx.git/blob - development/Win32/hidecmd.c
Scons: libintl also needs /MD option
[lyx.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 // open code section for writing
51 #pragma comment(linker,"/SECTION:.text,EWR")
52 // redefine an entry point of the executable
53 // Must be used, if entry point 'void NewWinMain(void)' is used,
54 // instead of the standart 'int WINAPI WinMain(HINSTANCE hInst, ...)'
55 #pragma comment(linker,"/ENTRY:NewWinMain")
56
57 void NewWinMain(void)
58 #else  // mingw/gcc uses this entry point
59 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszCmd, int nCmd)
60 #endif
61 {
62         STARTUPINFO si;
63         PROCESS_INFORMATION pi;
64         DWORD exitcode = 0;
65         char delim = ' ';
66         char * var;
67         char * val;
68         // two " are needed here: the first one quotes the entire
69         // command, the second one the executable name
70         char cmd[1024] = "cmd /c \"\"";
71         //  i0 = strlen(cmd);
72         int i0 = 9;
73         int i;
74         int err = 0;
75         int inquote;
76         char * cmdLine = GetCommandLine();
77         // the name of the executable to be launched
78         // (must be in the same directory)
79         char * lyxc = "lyxc.exe";
80
81         // When using GetCommandLine(), command name is included
82         // but the full path may be missing, so skip it.
83         if (*cmdLine == '\"') {
84                 delim = '\"';
85                 cmdLine++;
86         }
87
88         while (*cmdLine != delim && *cmdLine != 0)
89                 cmdLine++;
90
91         if (*cmdLine == delim)
92                 cmdLine++;
93
94         // skip over ' ' or '\t'
95         while (*cmdLine != 0 && (*cmdLine == ' ' || *cmdLine == '\t'))
96                 cmdLine++; 
97
98         // Use GetModuleFileName() to get the path to lyxc.exe
99         GetModuleFileName(0, cmd + i0, sizeof(cmd) / 2);
100
101         // substitute executable name
102         for (i = i0; cmd[i] != 0; ++i);
103
104         for (--i; i >= i0 && cmd[i] != '\\' && cmd[i] != '/'; --i);
105
106         for (++i; *lyxc && i < sizeof(cmd); )
107                 cmd[i++] = *lyxc++;
108
109         // check whether lyxc.exe is there
110         cmd[i] = '\0';
111         lyxc = cmd + i0;
112         if (GetFileAttributesA(lyxc) == 0xFFFFFFFF) {
113                 exitcode = GetLastError();
114                 MessageBox(0, lyxc, "Error: cannot find the real LyX executable below", 0);
115                 ExitProcess(exitcode);
116         }
117
118         // it's there, so finish quoting filename
119         cmd[i++] = '\"';
120
121         // parse remainder of command line
122         while (*cmdLine != 0 && !err) {
123                 if (i < sizeof(cmd))
124                         cmd[i++] = ' ';
125                 else
126                         err = 1;
127
128                 if ((*cmdLine >= 'A' && *cmdLine <= 'Z') ||
129                     (*cmdLine >= 'a' && *cmdLine <= 'z'))
130                         var = cmd + i;
131                 else
132                         var = NULL;
133
134                 val = NULL;
135                 inquote = 0;
136                 while (!err && ((*cmdLine != 0 && *cmdLine != ' ' &&
137                                 *cmdLine != '\t') || inquote))
138                 {
139                         if (*cmdLine == '\"')
140                                 inquote = 1 - inquote;
141
142                         if (var && *cmdLine == '=' && !inquote)
143                                 val = cmd + i;
144
145                         if (i < sizeof(cmd))
146                                 cmd[i++] = *cmdLine;
147                         else
148                                 err = 1;
149
150                         cmdLine++;
151                 }
152
153                 if (var && val && !err) {
154                         *val++ = '\0';          // mark end of var
155                         if (*val == '\"') {     // account for quoted val
156                                 ++val;
157                                 --i;
158                         }
159                         cmd[i] = '\0';          // mark end of val
160                         i = var - cmd - 1;      // reset pointer
161                         SetEnvironmentVariable(var, val);
162                         // MessageBox(0, val, var, 0);
163                 }
164
165                 // skip spaces
166                 while (*cmdLine != 0 && (*cmdLine == ' ' || *cmdLine == '\t')) 
167                         cmdLine++;
168         }
169
170         if (i < sizeof(cmd) - 1) {
171                 // finish quoting the entire command
172                 cmd[i++] = '\"';
173                 cmd[i] = '\0';
174         } else
175                 err = 1;
176         
177         if (err) {
178                 MessageBox(0, "Please, use a shorter command line.",
179                                 "Error: command line is too long", 0);
180                 ExitProcess(0);
181         }
182
183         // create process with new console
184         // memset(&si, 0, sizeof(si));
185         val = (char *) &si;
186         for (i = 0; i < sizeof(si); ++i)
187                 val[i] = 0x00;
188         si.cb = sizeof(si);
189         si.dwFlags = STARTF_USESHOWWINDOW;
190         si.wShowWindow = SW_HIDE;
191         if (CreateProcess(NULL, cmd,
192                 NULL, NULL, FALSE, CREATE_NEW_CONSOLE,
193                 NULL, NULL, &si, &pi))
194         {
195                 CloseHandle( pi.hProcess );
196                 CloseHandle( pi.hThread );
197         }
198         else
199                 exitcode = GetLastError();
200
201         /* terminate this */
202         ExitProcess(exitcode);
203 }