̶N̶ã̶o̶ ̶s̶e̶i̶ ̶s̶e̶ ̶v̶a̶i̶ ̶l̶h̶e̶ ̶s̶e̶r̶v̶i̶r̶ ̶m̶a̶s̶ ̶e̶m̶ ̶c #̶ ̶o̶ ̶q̶u̶e̶ ̶d̶á̶ ̶p̶a̶r̶a̶ ̶f̶a̶z̶e̶r̶ ̶é̶ ̶c̶r̶i̶a̶r̶ ̶u̶m̶ ̶s̶h̶e̶l̶l̶ ̶f̶a̶l̶s̶o̶(̶F̶a̶k̶e̶ ̶S̶h̶e̶l̶l̶)̶ ̶o̶n̶d̶e̶ ̶o̶ ̶u̶s̶u̶á̶r̶i̶o̶ ̶d̶i̶g̶i̶t̶a̶ ̶a̶ ̶l̶i̶n̶h̶a̶ ̶d̶e̶ ̶c̶o̶m̶a̶n̶d̶o̶ ̶e̶n̶q̶u̶a̶n̶t̶o̶ ̶o̶ ̶f̶a̶k̶e̶ ̶s̶h̶e̶l̶l̶ ̶p̶r̶o̶c̶e̶s̶s̶a̶ ̶e̶s̶s̶a̶ ̶e̶n̶t̶r̶a̶d̶a̶ ̶e̶ ̶r̶e̶t̶r̶a̶n̶s̶m̶i̶t̶e̶ ̶p̶a̶r̶a̶ ̶o̶ ̶̶c̶m̶d̶
̶ ̶o̶ ̶q̶u̶e̶ ̶v̶o̶c̶ê̶ ̶q̶u̶i̶s̶e̶r̶.̶
̶
̶N̶e̶s̶s̶e̶ ̶e̶x̶e̶m̶p̶l̶o̶ ̶e̶u̶ ̶a̶p̶e̶n̶a̶s̶ ̶r̶e̶t̶r̶a̶n̶s̶m̶i̶t̶o̶ ̶p̶a̶r̶a̶ ̶o̶ ̶̶c̶m̶d̶
̶ ̶e̶x̶a̶t̶a̶m̶e̶n̶t̶e̶ ̶t̶u̶d̶o̶ ̶q̶u̶e̶ ̶u̶s̶u̶á̶r̶i̶o̶ ̶d̶i̶g̶i̶t̶a̶r̶,̶ ̶ú̶n̶i̶c̶a̶ ̶c̶o̶i̶s̶a̶ ̶q̶u̶e̶ ̶f̶a̶ç̶o̶ ̶e̶n̶t̶r̶e̶ ̶o̶ ̶d̶i̶g̶i̶t̶a̶r̶ ̶d̶a̶ ̶l̶i̶n̶h̶a̶ ̶d̶e̶ ̶c̶o̶m̶a̶n̶d̶o̶ ̶e̶ ̶r̶e̶c̶o̶n̶h̶e̶c̶i̶m̶e̶n̶t̶o̶ ̶p̶e̶l̶o̶ ̶̶c̶m̶d̶
̶ ̶é̶ ̶q̶u̶e̶b̶r̶a̶r̶ ̶a̶ ̶l̶i̶n̶h̶a̶ ̶d̶e̶ ̶c̶o̶m̶a̶n̶d̶o̶ ̶e̶m̶ ̶e̶s̶p̶a̶ç̶o̶s̶ ̶e̶ ̶i̶m̶p̶r̶i̶m̶i̶r̶ ̶s̶e̶u̶s̶ ̶c̶o̶m̶p̶o̶n̶e̶n̶t̶e̶s̶ ̶e̶n̶t̶r̶e̶ ̶c̶o̶l̶c̶h̶e̶t̶e̶s̶:̶
̶
To solve your problem I created a Fakeshell that acts in two modes. DOS Mode and Fakeshell Mode.
What are these two ways?
In DOS mode the program works exactly the same as the CDM
the characters of operators & && | || < > >> e <<
are processed in a traditional way by performing their respective functions.
In Fakeshell mode the command line is intercepted and broken by the function CommandLineToArgvW
staying in the dll Shell32.dll
that makes the lexical analysis of the command line according to the DOS standard, so that there are no problems of fractures or inconsistencies with the arguments. The command line break is passed to a string array, string[] args = SplitArgs(cmd);
, where the first element is the name of the program you want to call and the rest of the vector are the arguments.
So instead of using the CMD
, the program creates a parallel process that calls the program passed in args[0]
using the rest of the vector args
as arguments. The result is that the characters of operators & && | || < > >> e <<
are not processed but are understood as commands and are understood as simple strings.
Why two ways?
Because Fakeshell Mode does not work under CMD environment then the DOS commands are disabled and the only thing you can do is call executables, batch files or files associated with applications. Then the DOS mode serves to navigate the system and the Fakeshell mode serves to ignore DOS commands.
How to change operation modes?
Press [CTRL] + P and then enter.
The program starts in DOS mode.
The code:
EDITED
using System;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Linq;
namespace FakeShell
{
class FakeShell
{
private static StringBuilder fakeOutput = null;
//*********************************************************************************************************************
// EDIÇÃO
//*********************************************************************************************************************
private static bool prompt = false;
/// <summary>
/// Usa a função Win32 CommandLineToArgvW para analisar e quebrar a string de entrada segundo o formato pedido pelos DOS
/// </summary>
/// <param name="entrada">String a ser analizada</param>
/// <returns>Retorna a quebra da enrada em vetor de strings segundo a sintaxe do dos</returns>
static string[] SplitArgs(string entrada)
{
int contador;
IntPtr ptrArgumentos;
string[] argumentos;
ptrArgumentos = CommandLineToArgvW(entrada, out contador);
if (ptrArgumentos == IntPtr.Zero)
{
return new string[] {"Erro a analisar o argumento"};
}
try
{
argumentos = new string[contador];
for (int i = 0; i < contador; i++)
argumentos[i] = Marshal.PtrToStringUni(
Marshal.ReadIntPtr(ptrArgumentos, i * IntPtr.Size));
return argumentos;
}
finally
{
LocalFree(ptrArgumentos);
}
}
[DllImport("shell32.dll", SetLastError = true)]
static extern IntPtr CommandLineToArgvW(
[MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine,
out int pNumArgs);
[DllImport("kernel32.dll")]
static extern IntPtr LocalFree(IntPtr hMem);
private static void OutputHandler(object sendingProcess,
DataReceivedEventArgs outLine)
{
//Modifiquei o código despejo do buffer mas tem ainda um bug
//Não sei o porque de em alguns momentos ele adiciona um \n na frente do prompt
if (!String.IsNullOrWhiteSpace(outLine.Data))
{
if (prompt)
{
Console.Write(outLine.Data);
prompt = false;
} else Console.WriteLine(outLine.Data);
}
}
//*********************************************************************************************************************
// FIM - EDIÇÃO
//*********************************************************************************************************************
static void Main()
{
//****************************************************************************
// EDIÇÃO
//****************************************************************************
//Adicionei essa variável para controlar o processamento ou não do CMD.
//True é modo DOS
//False é modo FakeShell
bool processarCMD = true; //Começa em modo DOS
//Adicionei essa variável para controlar e exibição ou não do prompt
prompt = false;
//*********************************************************************************************************************
// FIM - EDIÇÃO
//*********************************************************************************************************************
try
{
Process fakeShell = new Process();
fakeShell.StartInfo.FileName = "cmd.exe";
fakeShell.StartInfo.UseShellExecute = false;
fakeShell.StartInfo.RedirectStandardOutput = true;
fakeShell.OutputDataReceived += OutputHandler;
fakeShell.StartInfo.RedirectStandardInput = true;
fakeShell.Start();
StreamWriter streamWriter = fakeShell.StandardInput;
fakeShell.BeginOutputReadLine();
String cmd;
Console.WriteLine("-Fake Shell- digite um comando ou pressione enter para saír:\n");
Console.WriteLine("pressione [CTRL] + P para ativar/desativar o modo de processameto CDM");
streamWriter.Flush();
do
{
//para pegar o prompt
prompt = true;
streamWriter.WriteLine("\x0D");
cmd = Console.ReadLine();
if (!String.IsNullOrEmpty(cmd))
{
//****************************************************************************
// EDIÇÃO
//****************************************************************************
if (cmd == "\u0010")
{
processarCMD = !processarCMD;
Console.WriteLine("<<Modo " + ((processarCMD)? "DOS" : "FakeShell") + ">>\n");
continue;
}
//SplitArgs quebra a linha de comando inserida segundo o formato DOS
string[] args = SplitArgs(cmd);
//Caso queira comutar entre modo DOS e modo FakeShell pressione [CTRL] + P
if (processarCMD) streamWriter.WriteLine(cmd);
else
{
//Esse foreach é só um exemplo ele pega a quebra da linha de comando e imprime
//verticalmente entre colchetes só para mostrar sequencia de quebra.
foreach (var arg in args)
{
Console.WriteLine("[" + arg + "]");
}
//Cria um novo processo paralelo para executar seu Aplicativo
Process newProcess = new Process();
newProcess.StartInfo.FileName = args[0];
//Junta os argumentos
newProcess.StartInfo.Arguments = String.Join(" ", args.Skip(1).ToArray());
newProcess.StartInfo.UseShellExecute = true;
//Inicializa o processo chamando o executável em outra janela
try
{
newProcess.Start();
}
catch (Exception e)
{
streamWriter.WriteLine(e.Message);
continue;
}
//Aguarda até que o applicativo esteja ecerrado
newProcess.WaitForExit();
//Fecha o processo paralelo
newProcess.Close();
}
//****************************************************************************
// FIM - EDIÇÃO
//****************************************************************************
}
} while (!String.IsNullOrEmpty(cmd));
streamWriter.Close();
fakeShell.WaitForExit();
fakeShell.Close();
}
catch (InvalidOperationException e)
{
Console.WriteLine(e);
}
}
}
}
To do the test I created a directory and in this directory I gave the following in both modes:
C: Test> CMD.exe /? >> Test.txt
This command calls CMD help, which is extensive, and saves in a file called Teste.txt
in DOS mode it creates the file normally in fake shell mode it opens a new window with CMD and consumes the srings >>
and Teste.txt
as if they were parameters and ignores the string already /?
is also consumed as parameter and in the window that was opened displays the help of CMD without creating the file Teste.txt
.
OBS:
For your C# program to consume command line the method Main
must have the following signature:
static void Main(string[] args)
Please avoid long discussions in the comments; your talk was moved to the chat
– Maniero