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 == L'/') 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_ERROR1, 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 == NULL) 182 { 183 error_out_of_memory(); 184 return 1; 185 } 186 SetLastError(0); 187 size = GetEnvironmentVariable (_T("COMSPEC"), comspec, MAX_PATH); 188 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) 189 { 190 _tcscpy(comspec, _T("cmd")); 191 } 192 else 193 { 194 if (size > MAX_PATH) 195 { 196 LPTSTR Oldcomspec = comspec; 197 comspec = cmd_realloc(comspec,size * sizeof(TCHAR) ); 198 if (comspec==NULL) 199 { 200 cmd_free(Oldcomspec); 201 return 1; 202 } 203 size = GetEnvironmentVariable (_T("COMSPEC"), comspec, size); 204 } 205 } 206 207 nErrorLevel = 0; 208 209 if (!*Rest) 210 { 211 Rest = _T("cmd.exe"); 212 } 213 else 214 /* Parsing the command that gets called by start, and it's parameters */ 215 { 216 BOOL bInside = FALSE; 217 INT i; 218 /* find the end of the command and put the arguments in param */ 219 for (i = 0; Rest[i]; i++) 220 { 221 if (Rest[i] == _T('\"')) 222 bInside = !bInside; 223 if (_istspace(Rest[i]) && !bInside) 224 { 225 param = &Rest[i+1]; 226 Rest[i] = _T('\0'); 227 break; 228 } 229 } 230 } 231 232 _tcscpy(szUnquotedName, Rest); 233 StripQuotes(szUnquotedName); 234 235 /* get the PATH environment variable and parse it */ 236 /* search the PATH environment variable for the binary */ 237 if (SearchForExecutable(szUnquotedName, szFullName)) 238 { 239 /* check if this is a .BAT or .CMD file */ 240 dot = _tcsrchr(szFullName, _T('.')); 241 if (dot && (!_tcsicmp(dot, _T(".bat")) || !_tcsicmp(dot, _T(".cmd")))) 242 { 243 bBat = TRUE; 244 _stprintf(szFullCmdLine, _T("\"%s\" /K %s"), comspec, Rest); 245 TRACE ("[BATCH: %s %s]\n", debugstr_aw(szFullName), debugstr_aw(Rest)); 246 } 247 else 248 { 249 TRACE ("[EXEC: %s %s]\n", debugstr_aw(szFullName), debugstr_aw(Rest)); 250 _tcscpy(szFullCmdLine, szFullName); 251 } 252 253 /* build command line for CreateProcess() */ 254 if (param != NULL) 255 { 256 _tcsncat(szFullCmdLine, _T(" "), CMDLINE_LENGTH - _tcslen(szFullCmdLine)); 257 _tcsncat(szFullCmdLine, param, CMDLINE_LENGTH - _tcslen(szFullCmdLine)); 258 } 259 260 /* fill startup info */ 261 memset (&stui, 0, sizeof (STARTUPINFO)); 262 stui.cb = sizeof (STARTUPINFO); 263 stui.dwFlags = STARTF_USESHOWWINDOW; 264 stui.lpTitle = lpTitle; 265 stui.wShowWindow = wShowWindow; 266 267 bCreate = CreateProcess(bBat ? comspec : szFullName, 268 szFullCmdLine, NULL, NULL, TRUE, dwCreationFlags, 269 lpEnvironment, lpDirectory, &stui, &prci); 270 if (bCreate) 271 { 272 if (dwAffinityMask) 273 { 274 SetProcessAffinityMask(prci.hProcess, dwAffinityMask); 275 ResumeThread(prci.hThread); 276 } 277 CloseHandle(prci.hThread); 278 } 279 } 280 else 281 { 282 /* The file name did not seem to be valid, but maybe it's actually a 283 * directory or URL, so we still want to pass it to ShellExecute. */ 284 _tcscpy(szFullName, szUnquotedName); 285 } 286 287 if (!bCreate) 288 { 289 /* CreateProcess didn't work; try ShellExecute */ 290 DWORD flags = SEE_MASK_NOCLOSEPROCESS; 291 if (!(dwCreationFlags & CREATE_NEW_CONSOLE)) 292 flags |= SEE_MASK_NO_CONSOLE; 293 prci.hProcess = RunFile(flags, szFullName, param, lpDirectory, wShowWindow); 294 } 295 296 if (prci.hProcess != NULL) 297 { 298 if (bWait) 299 { 300 DWORD dwExitCode; 301 WaitForSingleObject (prci.hProcess, INFINITE); 302 GetExitCodeProcess (prci.hProcess, &dwExitCode); 303 nErrorLevel = (INT)dwExitCode; 304 } 305 CloseHandle (prci.hProcess); 306 307 /* Update our local codepage cache */ 308 { 309 UINT uNewInputCodePage = GetConsoleCP(); 310 UINT uNewOutputCodePage = GetConsoleOutputCP(); 311 312 if ((InputCodePage != uNewInputCodePage) || 313 (OutputCodePage != uNewOutputCodePage)) 314 { 315 /* Update the locale as well */ 316 InitLocale(); 317 } 318 319 InputCodePage = uNewInputCodePage; 320 OutputCodePage = uNewOutputCodePage; 321 322 /* Update the streams codepage cache as well */ 323 ConStreamSetCacheCodePage(StdIn , InputCodePage ); 324 ConStreamSetCacheCodePage(StdOut, OutputCodePage); 325 ConStreamSetCacheCodePage(StdErr, OutputCodePage); 326 } 327 } 328 else 329 { 330 ErrorMessage(GetLastError (), 331 _T("Error executing CreateProcess()!!\n")); 332 } 333 334 cmd_free(comspec); 335 return 0; 336 } 337 338 #endif 339 340 /* EOF */ 341