Removed redundant LANGUAGE statements.
[wine] / programs / winevdm / winevdm.c
1 /*
2  * Wine virtual DOS machine
3  *
4  * Copyright 2003 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "winbase.h"
22 #include "wine/winbase16.h"
23 #include "winuser.h"
24 #include "wine/debug.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(winevdm);
27
28 extern void WINAPI wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline );
29
30
31 /***********************************************************************
32  *           build_command_line
33  *
34  * Build the command line of a process from the argv array.
35  * Copied from ENV_BuildCommandLine.
36  */
37 static char *build_command_line( char **argv )
38 {
39     int len;
40     char *p, **arg, *cmd_line;
41
42     len = 0;
43     for (arg = argv; *arg; arg++)
44     {
45         int has_space,bcount;
46         char* a;
47
48         has_space=0;
49         bcount=0;
50         a=*arg;
51         while (*a!='\0') {
52             if (*a=='\\') {
53                 bcount++;
54             } else {
55                 if (*a==' ' || *a=='\t') {
56                     has_space=1;
57                 } else if (*a=='"') {
58                     /* doubling of '\' preceeding a '"',
59                      * plus escaping of said '"'
60                      */
61                     len+=2*bcount+1;
62                 }
63                 bcount=0;
64             }
65             a++;
66         }
67         len+=(a-*arg)+1 /* for the separating space */;
68         if (has_space)
69             len+=2; /* for the quotes */
70     }
71
72     if (!(cmd_line = HeapAlloc( GetProcessHeap(), 0, len ? len + 1 : 2 ))) 
73         return NULL;
74
75     p = cmd_line;
76     *p++ = (len < 256) ? len : 255;
77     for (arg = argv; *arg; arg++)
78     {
79         int has_space,has_quote;
80         char* a;
81
82         /* Check for quotes and spaces in this argument */
83         has_space=has_quote=0;
84         a=*arg;
85         while (*a!='\0') {
86             if (*a==' ' || *a=='\t') {
87                 has_space=1;
88                 if (has_quote)
89                     break;
90             } else if (*a=='"') {
91                 has_quote=1;
92                 if (has_space)
93                     break;
94             }
95             a++;
96         }
97
98         /* Now transfer it to the command line */
99         if (has_space)
100             *p++='"';
101         if (has_quote) {
102             int bcount;
103             char* a;
104
105             bcount=0;
106             a=*arg;
107             while (*a!='\0') {
108                 if (*a=='\\') {
109                     *p++=*a;
110                     bcount++;
111                 } else {
112                     if (*a=='"') {
113                         int i;
114
115                         /* Double all the '\\' preceeding this '"', plus one */
116                         for (i=0;i<=bcount;i++)
117                             *p++='\\';
118                         *p++='"';
119                     } else {
120                         *p++=*a;
121                     }
122                     bcount=0;
123                 }
124                 a++;
125             }
126         } else {
127             strcpy(p,*arg);
128             p+=strlen(*arg);
129         }
130         if (has_space)
131             *p++='"';
132         *p++=' ';
133     }
134     if (len) p--;  /* remove last space */
135     *p = '\0';
136     return cmd_line;
137 }
138
139
140 /***********************************************************************
141  *           usage
142  */
143 static void usage(void)
144 {
145     WINE_MESSAGE( "Usage: winevdm.exe [--app-name app.exe] command line\n\n" );
146     ExitProcess(1);
147 }
148
149
150 /***********************************************************************
151  *           main
152  */
153 int main( int argc, char *argv[] )
154 {
155     DWORD count;
156     HINSTANCE16 instance;
157     LOADPARAMS16 params;
158     WORD showCmd[2];
159     char buffer[MAX_PATH];
160     STARTUPINFOA info;
161     char *cmdline, *appname, **first_arg;
162
163     if (!argv[1]) usage();
164
165     if (!strcmp( argv[1], "--app-name" ))
166     {
167         if (!(appname = argv[2])) usage();
168         first_arg = argv + 3;
169     }
170     else
171     {
172         if (!SearchPathA( NULL, argv[1], ".exe", sizeof(buffer), buffer, NULL ))
173         {
174             WINE_MESSAGE( "winevdm: can't exec '%s': file not found\n", argv[1] );
175             ExitProcess(1);
176         }
177         appname = buffer;
178         first_arg = argv + 1;
179     }
180
181     if (*first_arg) first_arg++;  /* skip program name */
182     cmdline = build_command_line( first_arg );
183
184     if (WINE_TRACE_ON(winevdm))
185     {
186         int i;
187         WINE_TRACE( "GetCommandLine = '%s'\n", GetCommandLineA() );
188         WINE_TRACE( "appname = '%s'\n", appname );
189         WINE_TRACE( "cmdline = '%.*s'\n", cmdline[0], cmdline+1 );
190         for (i = 0; argv[i]; i++) WINE_TRACE( "argv[%d]: '%s'\n", i, argv[i] );
191     }
192
193     GetStartupInfoA( &info );
194     showCmd[0] = 2;
195     showCmd[1] = (info.dwFlags & STARTF_USESHOWWINDOW) ? info.wShowWindow : SW_SHOWNORMAL;
196
197     params.hEnvironment = 0;
198     params.cmdLine = MapLS( cmdline );
199     params.showCmd = MapLS( showCmd );
200     params.reserved = 0;
201
202     RestoreThunkLock(1);  /* grab the Win16 lock */
203
204     /* some programs assume mmsystem is always present */
205     LoadLibrary16( "mmsystem.dll" );
206
207     if ((instance = LoadModule16( appname, &params )) < 32)
208     {
209         if (instance == 11)  /* try DOS format */
210         {
211             /* loader expects arguments to be regular C strings */
212             wine_load_dos_exe( appname, cmdline + 1 );
213             /* if we get back here it failed */
214             instance = GetLastError();
215         }
216
217         WINE_MESSAGE( "winevdm: can't exec '%s': ", appname );
218         switch (instance)
219         {
220         case  2: WINE_MESSAGE("file not found\n" ); break;
221         case 11: WINE_MESSAGE("invalid exe file\n" ); break;
222         default: WINE_MESSAGE("error=%d\n", instance ); break;
223         }
224         ExitProcess(instance);
225     }
226
227     /* wait forever; the process will be killed when the last task exits */
228     ReleaseThunkLock( &count );
229     Sleep( INFINITE );
230     return 0;
231 }