1 /* 2 * START.C - start internal command. 3 * 4 * 5 * History: 6 * 7 * 24-Jul-1999 (Eric Kohl) 8 * Started. 9 * 10 * 30-Apr-2005 (Magnus Olsen <magnus@greatlord.com>) 11 * Remove all hardcoded strings in En.rc 12 */ 13 14 #include "precomp.h" 15 16 #ifdef INCLUDE_CMD_START 17 18 /* Find the end of an option, and turn it into a nul-terminated string 19 * in place. (It's moved back one character, to make room for the nul) */ 20 static TCHAR *GetParameter(TCHAR **pPointer) 21 { 22 BOOL bInQuote = FALSE; 23 TCHAR *start = *pPointer; 24 TCHAR *p; 25 for (p = start; *p; p++) 26 { 27 if (!bInQuote && (*p == _T('/') || _istspace(*p))) 28 break; 29 bInQuote ^= (*p == _T('"')); 30 p[-1] = *p; 31 } 32 p[-1] = _T('\0'); 33 *pPointer = p; 34 return start - 1; 35 } 36 37 INT cmd_start (LPTSTR Rest) 38 { 39 TCHAR szFullName[CMDLINE_LENGTH]; 40 TCHAR szUnquotedName[CMDLINE_LENGTH]; 41 TCHAR *param = NULL; 42 TCHAR *dot; 43 INT size; 44 LPTSTR comspec; 45 BOOL bWait = FALSE; 46 BOOL bBat = FALSE; 47 BOOL bCreate = FALSE; 48 TCHAR szFullCmdLine[CMDLINE_LENGTH]; 49 PROCESS_INFORMATION prci; 50 STARTUPINFO stui; 51 #ifdef UNICODE 52 DWORD dwCreationFlags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT; 53 #else 54 DWORD dwCreationFlags = CREATE_NEW_CONSOLE; 55 #endif 56 DWORD dwAffinityMask = 0; 57 LPTSTR lpTitle = NULL; 58 LPTSTR lpDirectory = NULL; 59 LPTSTR lpEnvironment = NULL; 60 WORD wShowWindow = SW_SHOWNORMAL; 61 62 while (1) 63 { 64 if (_istspace(*Rest)) 65 { 66 Rest++; 67 } 68 else if (*Rest == _T('"') && !lpTitle) 69 { 70 lpTitle = GetParameter(&Rest); 71 StripQuotes(lpTitle); 72 } 73 else if (*Rest == _T('/')) 74 { 75 LPTSTR option; 76 Rest++; 77 option = GetParameter(&Rest); 78 if (*option == _T('?')) 79 { 80 ConOutResPaging(TRUE,STRING_START_HELP1); 81 return 0; 82 } 83 else if (_totupper(*option) == _T('D')) 84 { 85 lpDirectory = option + 1; 86 if (!*lpDirectory) 87 { 88 while (_istspace(*Rest)) 89 Rest++; 90 lpDirectory = GetParameter(&Rest); 91 } 92 StripQuotes(lpDirectory); 93 } 94 else if (_totupper(*option) == _T('I')) 95 { 96 /* rest of the option is apparently ignored */ 97 lpEnvironment = lpOriginalEnvironment; 98 } 99 else if (!_tcsicmp(option, _T("MIN"))) 100 { 101 wShowWindow = SW_MINIMIZE; 102 } 103 else if (!_tcsicmp(option, _T("MAX"))) 104 { 105 wShowWindow = SW_MAXIMIZE; 106 } 107 else if (!_tcsicmp(option, _T("AFFINITY"))) 108 { 109 TCHAR *end; 110 while (_istspace(*Rest)) 111 Rest++; 112 option = GetParameter(&Rest); 113 /* Affinity mask is given in hexadecimal */ 114 dwAffinityMask = _tcstoul(option, &end, 16); 115 if (*end != _T('\0') || dwAffinityMask == 0 || 116 dwAffinityMask == (DWORD)-1) 117 { 118 ConErrResPrintf(STRING_ERROR_INVALID_PARAM_FORMAT, option); 119 return 1; 120 } 121 dwCreationFlags |= CREATE_SUSPENDED; 122 } 123 else if (!_tcsicmp(option, _T("B"))) 124 { 125 dwCreationFlags &= ~CREATE_NEW_CONSOLE; 126 dwCreationFlags |= CREATE_NEW_PROCESS_GROUP; 127 } 128 else if (!_tcsicmp(option, _T("LOW"))) 129 { 130 dwCreationFlags |= IDLE_PRIORITY_CLASS; 131 } 132 else if (!_tcsicmp(option, _T("NORMAL"))) 133 { 134 dwCreationFlags |= NORMAL_PRIORITY_CLASS; 135 } 136 else if (!_tcsicmp(option, _T("HIGH"))) 137 { 138 dwCreationFlags |= HIGH_PRIORITY_CLASS; 139 } 140 else if (!_tcsicmp(option, _T("REALTIME"))) 141 { 142 dwCreationFlags |= REALTIME_PRIORITY_CLASS; 143 } 144 else if (!_tcsicmp(option, _T("ABOVENORMAL"))) 145 { 146 dwCreationFlags |= ABOVE_NORMAL_PRIORITY_CLASS; 147 } 148 else if (!_tcsicmp(option, _T("BELOWNORMAL"))) 149 { 150 dwCreationFlags |= BELOW_NORMAL_PRIORITY_CLASS; 151 } 152 else if (!_tcsicmp(option, _T("SEPARATE"))) 153 { 154 dwCreationFlags |= CREATE_SEPARATE_WOW_VDM; 155 } 156 else if (!_tcsicmp(option, _T("SHARED"))) 157 { 158 dwCreationFlags |= CREATE_SHARED_WOW_VDM; 159 } 160 else if (!_tcsicmp(option, _T("W")) || 161 !_tcsicmp(option, _T("WAIT"))) 162 { 163 bWait = TRUE; 164 } 165 else 166 { 167 ConErrResPrintf(STRING_TYPE_ERROR, option); 168 return 0; 169 } 170 } 171 else 172 { 173 /* It's not an option - must be the beginning of 174 * the actual command. Leave the loop. */ 175 break; 176 } 177 } 178 179 /* get comspec */ 180 comspec = cmd_alloc ( MAX_PATH * sizeof(TCHAR)); 181 if (!comspec) 182 { 183 WARN("Cannot allocate memory for start comspec!\n"); 184 error_out_of_memory(); 185 return 1; 186 } 187 SetLastError(0); 188 size = GetEnvironmentVariable (_T("COMSPEC"), comspec, MAX_PATH); 189 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) 190 { 191 _tcscpy(comspec, _T("cmd")); 192 } 193 else 194 { 195 if (size > MAX_PATH) 196 { 197 LPTSTR Oldcomspec = comspec; 198 comspec = cmd_realloc(comspec,size * sizeof(TCHAR) ); 199 if (comspec==NULL) 200 { 201 cmd_free(Oldcomspec); 202 return 1; 203 } 204 size = GetEnvironmentVariable (_T("COMSPEC"), comspec, size); 205 } 206 } 207 208 nErrorLevel = 0; 209 210 if (!*Rest) 211 { 212 Rest = _T("cmd.exe"); 213 } 214 else 215 /* Parsing the command that gets called by start, and it's parameters */ 216 { 217 BOOL bInside = FALSE; 218 INT i; 219 /* find the end of the command and put the arguments in param */ 220 for (i = 0; Rest[i]; i++) 221 { 222 if (Rest[i] == _T('\"')) 223 bInside = !bInside; 224 if (_istspace(Rest[i]) && !bInside) 225 { 226 param = &Rest[i+1]; 227 Rest[i] = _T('\0'); 228 break; 229 } 230 } 231 } 232 233 _tcscpy(szUnquotedName, Rest); 234 StripQuotes(szUnquotedName); 235 236 /* get the PATH environment variable and parse it */ 237 /* search the PATH environment variable for the binary */ 238 if (SearchForExecutable(szUnquotedName, szFullName)) 239 { 240 /* check if this is a .BAT or .CMD file */ 241 dot = _tcsrchr(szFullName, _T('.')); 242 if (dot && (!_tcsicmp(dot, _T(".bat")) || !_tcsicmp(dot, _T(".cmd")))) 243 { 244 bBat = TRUE; 245 _stprintf(szFullCmdLine, _T("\"%s\" /K %s"), comspec, Rest); 246 TRACE ("[BATCH: %s %s]\n", debugstr_aw(szFullName), debugstr_aw(Rest)); 247 } 248 else 249 { 250 TRACE ("[EXEC: %s %s]\n", debugstr_aw(szFullName), debugstr_aw(Rest)); 251 _tcscpy(szFullCmdLine, szFullName); 252 } 253 254 /* build command line for CreateProcess() */ 255 if (param != NULL) 256 { 257 _tcsncat(szFullCmdLine, _T(" "), CMDLINE_LENGTH - _tcslen(szFullCmdLine)); 258 _tcsncat(szFullCmdLine, param, CMDLINE_LENGTH - _tcslen(szFullCmdLine)); 259 } 260 261 /* fill startup info */ 262 memset (&stui, 0, sizeof (STARTUPINFO)); 263 stui.cb = sizeof (STARTUPINFO); 264 stui.dwFlags = STARTF_USESHOWWINDOW; 265 stui.lpTitle = lpTitle; 266 stui.wShowWindow = wShowWindow; 267 268 bCreate = CreateProcess(bBat ? comspec : szFullName, 269 szFullCmdLine, NULL, NULL, TRUE, dwCreationFlags, 270 lpEnvironment, lpDirectory, &stui, &prci); 271 if (bCreate) 272 { 273 if (dwAffinityMask) 274 { 275 SetProcessAffinityMask(prci.hProcess, dwAffinityMask); 276 ResumeThread(prci.hThread); 277 } 278 CloseHandle(prci.hThread); 279 } 280 } 281 else 282 { 283 /* The file name did not seem to be valid, but maybe it's actually a 284 * directory or URL, so we still want to pass it to ShellExecute. */ 285 _tcscpy(szFullName, szUnquotedName); 286 } 287 288 if (!bCreate) 289 { 290 /* CreateProcess didn't work; try ShellExecute */ 291 DWORD flags = SEE_MASK_NOCLOSEPROCESS; 292 if (!(dwCreationFlags & CREATE_NEW_CONSOLE)) 293 flags |= SEE_MASK_NO_CONSOLE; 294 prci.hProcess = RunFile(flags, szFullName, param, lpDirectory, wShowWindow); 295 } 296 297 if (prci.hProcess != NULL) 298 { 299 if (bWait) 300 { 301 DWORD dwExitCode; 302 WaitForSingleObject (prci.hProcess, INFINITE); 303 GetExitCodeProcess (prci.hProcess, &dwExitCode); 304 nErrorLevel = (INT)dwExitCode; 305 } 306 CloseHandle (prci.hProcess); 307 308 /* Update the local code page cache */ 309 { 310 UINT uNewInputCodePage = GetConsoleCP(); 311 UINT uNewOutputCodePage = GetConsoleOutputCP(); 312 313 if ((InputCodePage != uNewInputCodePage) || 314 (OutputCodePage != uNewOutputCodePage)) 315 { 316 InputCodePage = uNewInputCodePage; 317 OutputCodePage = uNewOutputCodePage; 318 319 /* Reset the current thread UI language */ 320 if (IsConsoleHandle(ConStreamGetOSHandle(StdOut)) || 321 IsConsoleHandle(ConStreamGetOSHandle(StdErr))) 322 { 323 ConSetThreadUILanguage(0); 324 } 325 /* Update the streams cached code page */ 326 ConStdStreamsSetCacheCodePage(InputCodePage, OutputCodePage); 327 328 /* Update the locale as well */ 329 InitLocale(); 330 } 331 } 332 } 333 else 334 { 335 ErrorMessage(GetLastError (), 336 _T("Error executing CreateProcess()!!\n")); 337 } 338 339 cmd_free(comspec); 340 return 0; 341 } 342 343 #endif 344 345 /* EOF */ 346