我正在尝试制作一个远程管理员工具,以便可以控制家用计算机,并使服务器正常工作。我可以很好地通过网络发送命令,但是在cmd中执行命令时遇到麻烦。我试图使用CreateProcess()函数启动cmd,然后通过管道写入命令并读取结果。我想多次执行此操作而不关闭cmd,以便可以使用cd等。
似乎至少部分起作用,因为在调用startCmd()函数时,它将为cmd打印欢迎消息。但是,在此之后,当我尝试将命令写入cmd时,它永远不会给我任何输出。当我检查out管道时,它说它已读取0个字节,但首次启动时除外。
这是否意味着我只能执行1条命令,或者在使用一次后是否需要以某种方式操纵管道,或者类似的东西?另外,如果代码太草率,我也表示歉意,我刚刚尝试了许多不同的解决方案,并且我一直没有担心代码的整洁度。
#define BUFSIZE 4096
#define PATHMAX 400
bool running = false;
HANDLE hChildStdInR = NULL;
HANDLE hChildStdInW = NULL;
HANDLE hChildStdOutR = NULL;
HANDLE hChildStdOutW = NULL;
PROCESS_INFORMATION piProcInfo;
void ErrorExit(const char*);
bool startCmd()
{
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&hChildStdOutR, &hChildStdOutW, &saAttr, 0))
ErrorExit("StdoutRd CreatePipe");
// Ensure the read handle to the pipe for STDOUT is not inherited.
if (!SetHandleInformation(hChildStdOutR, HANDLE_FLAG_INHERIT, 0))
ErrorExit("Stdout SetHandleInformation");
// Create a pipe for the child process's STDIN.
if (!CreatePipe(&hChildStdInR, &hChildStdInW, &saAttr, 0))
ErrorExit("Stdin CreatePipe");
// Ensure the write handle to the pipe for STDIN is not inherited.
if (!SetHandleInformation(hChildStdInW, HANDLE_FLAG_INHERIT, 0))
ErrorExit("Stdin SetHandleInformation");
char cmdPath[PATHMAX];
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure. This structure specifies the STDIN and STDOUT handles for redirection.
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = hChildStdOutW;
siStartInfo.hStdOutput = hChildStdOutW;
siStartInfo.hStdInput = hChildStdInR;
siStartInfo.wShowWindow = SW_HIDE;
siStartInfo.dwFlags |= STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
GetEnvironmentVariableA("ComSpec", cmdPath, sizeof(cmdPath));
// Create the child process.
bSuccess = CreateProcess(
cmdPath,
NULL, // command line (NULL because application itsself is cmd)
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
CREATE_NEW_CONSOLE, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
// Close un-needed pipes
/*CloseHandle(hChildStdOutW);
CloseHandle(hChildStdInR);*/ // Doesn't change anything why I uncomment these lines
// If an error occurs, exit the application.
if (!bSuccess)
ErrorExit("CreateProcess");
else
{
// Close handles to the child process and its primary thread. Some applications might keep these handles to monitor the status of the child process, for example.
/*CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);*/
}
return true;
}
bool writeToCmd(const string& s)
{
DWORD dwWritten;
const char* cmd = s.c_str();
return WriteFile(hChildStdInW, cmd, sizeof(cmd), &dwWritten, NULL);
}
bool exec(const string& command)
{
if (!writeToCmd(command)) {
return false;
}
else {
cout << "Succesfully Wrote" << endl;
}
return true;
}
void checkPipe()
{
while (running) {
while (1) {
Sleep(50);
DWORD bytesAvail = 0;
if (!PeekNamedPipe(hChildStdOutR, NULL, 0, NULL, &bytesAvail, NULL)) {
cout << "Failed to call PeekNamedPipe" << endl;
}
if (bytesAvail) {
CHAR buf[BUFSIZE];
DWORD n;
BOOL success = ReadFile(hChildStdOutR, buf, BUFSIZE, &n, NULL);
if (!success || n == 0) {
cout << "Failed to call ReadFile" << endl;
break;
}
string s = string(buf, buf + n);
cout << s << endl;
break;
}
}
}
}
int main(int argc, char** argv)
{
if (argc != 2) {
cout << "Usage: " << argv[0] << " <ADRESS>" << endl;
return 1;
}
ClientSocket client(argv[1], DEFAULT_PORT);
// Wait for initial response
string w = client.recieveLine();
if (w == "welcome") {
cout << "Connection Successful! " << endl;
}
running = true;
if (startCmd()) cout << "Cmd Started" << endl;
thread checkLoop(&checkPipe);
while (true) {
vector<string> command = split(client.recieveLine());
if (command[0] == "run") {
exec(command[1]);
}
else if (command[0] == "exit") {
running = false;
client.sendLine("exit");
break;
}
}
if (!CloseHandle(hChildStdInW))
ErrorExit("StdInWr CloseHandle");
checkLoop.join();
client.close();
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return 0;
}