[CMD] Improve the situations when the console title can be changed.

- Introduce two small helpers to change and restore the console title.
- Console title can change even when internal commands are executed.
- Note that when commands are run from within batch files, title is unchanged.
- When "cmd.exe /c command" is run, the console title is unchanged; however
  when "cmd.exe /k command" is run, the console title changes.
This commit is contained in:
Hermès Bélusca-Maïto 2018-06-03 02:15:44 +02:00
parent 39af25024a
commit a165999067
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
2 changed files with 70 additions and 27 deletions

View file

@ -149,21 +149,23 @@ typedef NTSTATUS (WINAPI *NtQueryInformationProcessProc)(HANDLE, PROCESSINFOCLAS
PVOID, ULONG, PULONG); PVOID, ULONG, PULONG);
typedef NTSTATUS (WINAPI *NtReadVirtualMemoryProc)(HANDLE, PVOID, PVOID, ULONG, PULONG); typedef NTSTATUS (WINAPI *NtReadVirtualMemoryProc)(HANDLE, PVOID, PVOID, ULONG, PULONG);
BOOL bExit = FALSE; /* indicates EXIT was typed */ BOOL bExit = FALSE; /* Indicates EXIT was typed */
BOOL bCanExit = TRUE; /* indicates if this shell is exitable */ BOOL bCanExit = TRUE; /* Indicates if this shell is exitable */
BOOL bCtrlBreak = FALSE; /* Ctrl-Break or Ctrl-C hit */ BOOL bCtrlBreak = FALSE; /* Ctrl-Break or Ctrl-C hit */
BOOL bIgnoreEcho = FALSE; /* Set this to TRUE to prevent a newline, when executing a command */ BOOL bIgnoreEcho = FALSE; /* Set this to TRUE to prevent a newline, when executing a command */
static BOOL bWaitForCommand = FALSE; /* When we are executing something passed on the commandline after /c or /k */ static BOOL fSingleCommand = 0; /* When we are executing something passed on the command line after /C or /K */
INT nErrorLevel = 0; /* Errorlevel of last launched external program */ INT nErrorLevel = 0; /* Errorlevel of last launched external program */
CRITICAL_SECTION ChildProcessRunningLock; CRITICAL_SECTION ChildProcessRunningLock;
BOOL bDisableBatchEcho = FALSE; BOOL bDisableBatchEcho = FALSE;
BOOL bEnableExtensions = TRUE; BOOL bEnableExtensions = TRUE;
BOOL bDelayedExpansion = FALSE; BOOL bDelayedExpansion = FALSE;
BOOL bTitleSet = FALSE;
DWORD dwChildProcessId = 0; DWORD dwChildProcessId = 0;
LPTSTR lpOriginalEnvironment; LPTSTR lpOriginalEnvironment;
HANDLE CMD_ModuleHandle; HANDLE CMD_ModuleHandle;
BOOL bTitleSet = FALSE; /* Indicates whether the console title has been changed and needs to be restored later */
TCHAR szCurTitle[MAX_PATH];
static NtQueryInformationProcessProc NtQueryInformationProcessPtr = NULL; static NtQueryInformationProcessProc NtQueryInformationProcessPtr = NULL;
static NtReadVirtualMemoryProc NtReadVirtualMemoryPtr = NULL; static NtReadVirtualMemoryProc NtReadVirtualMemoryPtr = NULL;
@ -302,23 +304,51 @@ HANDLE RunFile(DWORD flags, LPTSTR filename, LPTSTR params,
} }
static VOID
SetConTitle(LPCTSTR pszTitle)
{
TCHAR szNewTitle[MAX_PATH];
if (!pszTitle)
return;
/* Don't do anything if we run inside a batch file, or we are just running a single command */
if (bc || (fSingleCommand == 1))
return;
/* Save the original console title and build a new one */
GetConsoleTitle(szCurTitle, ARRAYSIZE(szCurTitle));
StringCchPrintf(szNewTitle, ARRAYSIZE(szNewTitle),
_T("%s - %s"), szCurTitle, pszTitle);
bTitleSet = TRUE;
ConSetTitle(szNewTitle);
}
static VOID
ResetConTitle(VOID)
{
/* Restore the original console title */
if (!bc && bTitleSet)
{
ConSetTitle(szCurTitle);
bTitleSet = FALSE;
}
}
/* /*
* This command (in first) was not found in the command table * This command (in First) was not found in the command table
* *
* Full - buffer to hold whole command line * Full - output buffer to hold whole command line
* First - first word on command line * First - first word on command line
* Rest - rest of command line * Rest - rest of command line
*/ */
static INT static INT
Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd) Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
{ {
TCHAR szFullName[MAX_PATH];
TCHAR *first, *rest, *dot; TCHAR *first, *rest, *dot;
TCHAR szWindowTitle[MAX_PATH];
TCHAR szNewTitle[MAX_PATH*2];
DWORD dwExitCode = 0; DWORD dwExitCode = 0;
TCHAR *FirstEnd; TCHAR *FirstEnd;
TCHAR szFullName[MAX_PATH];
TCHAR szFullCmdLine[CMDLINE_LENGTH]; TCHAR szFullCmdLine[CMDLINE_LENGTH];
TRACE ("Execute: \'%s\' \'%s\'\n", debugstr_aw(First), debugstr_aw(Rest)); TRACE ("Execute: \'%s\' \'%s\'\n", debugstr_aw(First), debugstr_aw(Rest));
@ -344,10 +374,10 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
} }
/* Copy the new first/rest into the buffer */ /* Copy the new first/rest into the buffer */
first = Full;
rest = &Full[FirstEnd - First + 1]; rest = &Full[FirstEnd - First + 1];
_tcscpy(rest, FirstEnd); _tcscpy(rest, FirstEnd);
_tcscat(rest, Rest); _tcscat(rest, Rest);
first = Full;
*FirstEnd = _T('\0'); *FirstEnd = _T('\0');
_tcscpy(first, First); _tcscpy(first, First);
@ -356,8 +386,8 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
{ {
BOOL working = TRUE; BOOL working = TRUE;
if (!SetCurrentDirectory(first)) if (!SetCurrentDirectory(first))
/* Guess they changed disc or something, handle that gracefully and get to root */
{ {
/* Guess they changed disc or something, handle that gracefully and get to root */
TCHAR str[4]; TCHAR str[4];
str[0]=first[0]; str[0]=first[0];
str[1]=_T(':'); str[1]=_T(':');
@ -379,12 +409,10 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
return 1; return 1;
} }
/* Save the original console title and build a new one */ /* Set the new console title */
GetConsoleTitle(szWindowTitle, ARRAYSIZE(szWindowTitle)); FirstEnd = first + (FirstEnd - First); /* Point to the separating NULL in the full built string */
bTitleSet = FALSE; *FirstEnd = _T(' ');
StringCchPrintf(szNewTitle, ARRAYSIZE(szNewTitle), SetConTitle(Full);
_T("%s - %s%s"), szWindowTitle, First, Rest);
ConSetTitle(szNewTitle);
/* check if this is a .BAT or .CMD file */ /* check if this is a .BAT or .CMD file */
dot = _tcsrchr (szFullName, _T('.')); dot = _tcsrchr (szFullName, _T('.'));
@ -392,6 +420,8 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
{ {
while (*rest == _T(' ')) while (*rest == _T(' '))
rest++; rest++;
*FirstEnd = _T('\0');
TRACE ("[BATCH: %s %s]\n", debugstr_aw(szFullName), debugstr_aw(rest)); TRACE ("[BATCH: %s %s]\n", debugstr_aw(szFullName), debugstr_aw(rest));
dwExitCode = Batch(szFullName, first, rest, Cmd); dwExitCode = Batch(szFullName, first, rest, Cmd);
} }
@ -402,7 +432,7 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
STARTUPINFO stui; STARTUPINFO stui;
/* build command line for CreateProcess(): FullName + " " + rest */ /* build command line for CreateProcess(): FullName + " " + rest */
BOOL quoted = !!_tcschr(First, ' '); BOOL quoted = !!_tcschr(First, _T(' '));
_tcscpy(szFullCmdLine, quoted ? _T("\"") : _T("")); _tcscpy(szFullCmdLine, quoted ? _T("\"") : _T(""));
_tcsncat(szFullCmdLine, First, CMDLINE_LENGTH - _tcslen(szFullCmdLine) - 1); _tcsncat(szFullCmdLine, First, CMDLINE_LENGTH - _tcslen(szFullCmdLine) - 1);
_tcsncat(szFullCmdLine, quoted ? _T("\"") : _T(""), CMDLINE_LENGTH - _tcslen(szFullCmdLine) - 1); _tcsncat(szFullCmdLine, quoted ? _T("\"") : _T(""), CMDLINE_LENGTH - _tcslen(szFullCmdLine) - 1);
@ -416,8 +446,9 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
TRACE ("[EXEC: %s]\n", debugstr_aw(szFullCmdLine)); TRACE ("[EXEC: %s]\n", debugstr_aw(szFullCmdLine));
/* fill startup info */ /* fill startup info */
memset (&stui, 0, sizeof (STARTUPINFO)); memset(&stui, 0, sizeof(stui));
stui.cb = sizeof (STARTUPINFO); stui.cb = sizeof(stui);
stui.lpTitle = Full;
stui.dwFlags = STARTF_USESHOWWINDOW; stui.dwFlags = STARTF_USESHOWWINDOW;
stui.wShowWindow = SW_SHOWDEFAULT; stui.wShowWindow = SW_SHOWDEFAULT;
@ -448,9 +479,11 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
SW_SHOWNORMAL); SW_SHOWNORMAL);
} }
*FirstEnd = _T('\0');
if (prci.hProcess != NULL) if (prci.hProcess != NULL)
{ {
if (bc != NULL || bWaitForCommand || IsConsoleProcess(prci.hProcess)) if (bc != NULL || fSingleCommand != 0 || IsConsoleProcess(prci.hProcess))
{ {
/* when processing a batch file or starting console processes: execute synchronously */ /* when processing a batch file or starting console processes: execute synchronously */
EnterCriticalSection(&ChildProcessRunningLock); EnterCriticalSection(&ChildProcessRunningLock);
@ -501,8 +534,7 @@ Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
} }
/* Restore the original console title */ /* Restore the original console title */
if (!bTitleSet) ResetConTitle();
ConSetTitle(szWindowTitle);
return dwExitCode; return dwExitCode;
} }
@ -568,9 +600,19 @@ DoCommand(LPTSTR first, LPTSTR rest, PARSED_COMMAND *Cmd)
/* Skip over whitespace to rest of line, exclude 'echo' command */ /* Skip over whitespace to rest of line, exclude 'echo' command */
if (_tcsicmp(cmdptr->name, _T("echo")) != 0) if (_tcsicmp(cmdptr->name, _T("echo")) != 0)
{
while (_istspace(*param)) while (_istspace(*param))
param++; param++;
}
/* Set the new console title */
SetConTitle(com);
ret = cmdptr->func(param); ret = cmdptr->func(param);
/* Restore the original console title */
ResetConTitle();
cmd_free(com); cmd_free(com);
return ret; return ret;
} }
@ -1896,6 +1938,7 @@ Initialize(VOID)
else if (option == _T('C') || option == _T('K') || option == _T('R')) else if (option == _T('C') || option == _T('K') || option == _T('R'))
{ {
/* Remainder of command line is a command to be run */ /* Remainder of command line is a command to be run */
fSingleCommand = ((option == _T('K')) << 1) | 1;
break; break;
} }
else if (option == _T('D')) else if (option == _T('D'))
@ -1983,14 +2026,13 @@ Initialize(VOID)
{ {
/* Do the /C or /K command */ /* Do the /C or /K command */
GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip); GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip);
bWaitForCommand = TRUE;
/* nExitCode = */ ParseCommandLine(commandline); /* nExitCode = */ ParseCommandLine(commandline);
bWaitForCommand = FALSE; if (fSingleCommand == 1)
if (option != _T('K'))
{ {
// nErrorLevel = nExitCode; // nErrorLevel = nExitCode;
bExit = TRUE; bExit = TRUE;
} }
fSingleCommand = 0;
} }
} }

View file

@ -28,7 +28,8 @@ INT cmd_title(LPTSTR param)
return 0; return 0;
} }
bTitleSet = TRUE; /* Set the new console title, and tell CMD to not reset it */
bTitleSet = FALSE;
return ConSetTitle(param); return ConSetTitle(param);
} }