我用C(不是C ++)编写cmd提示符,程序已编译但是当我运行它时,我输入了几次命令,程序错误并中止 我认为这是由于内存分配: 这是源代码:
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
char* Execute(char*);
HANDLE readIN = NULL;
HANDLE writeIN = NULL;
HANDLE readOUT = NULL;
HANDLE writeOUT = NULL;
int
main(int argc, char** argv)
{
SECURITY_ATTRIBUTES saAttr;
STARTUPINFO si;
PROCESS_INFORMATION pi;
char cmd[12];
char* out = NULL;
ZeroMemory(cmd,sizeof(cmd));
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
CreatePipe(&readOUT, &writeOUT, &saAttr, 0);
CreatePipe(&readIN, &writeIN, &saAttr, 0);
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
GetStartupInfo(&si);
si.cb = sizeof(STARTUPINFO);
si.hStdError = writeOUT;
si.hStdOutput = writeOUT;
si.hStdInput = readIN;
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
CreateProcess(NULL,
"cmd.exe",
NULL,
NULL,
TRUE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi
);
while (TRUE)
{
out = Execute(cmd);
printf("%s\n", out);
scanf("%s", cmd);
strcat(cmd,"\n");
}
free(out);
return 0;
}
char*
Execute(char* cmd)
{
DWORD bwritten = 0;
DWORD buffersize = 0;
int outputsize = 0;
DWORD breaden = 0;
char* output = NULL;
char* buffer = NULL;
DWORD n_buffersize;
WriteFile(writeIN, cmd, strlen(cmd), &bwritten, NULL);
while (TRUE)
{
Sleep(2000);
PeekNamedPipe(readOUT, NULL, NULL, NULL,&buffersize, NULL);
n_buffersize = buffersize;
if (n_buffersize)
{
buffer = (char*)malloc(n_buffersize + 1);
ZeroMemory(buffer,sizeof(buffer));
ReadFile(readOUT, buffer, n_buffersize, &breaden, NULL);
}
else
break;
if (breaden)
{
outputsize += n_buffersize + 1;
output = (char*)realloc(output, outputsize);
strcat(output, buffer);
free(buffer);
}
}
return output;
}
答案 0 :(得分:4)
你在哪里:
buffer = (char*)malloc(n_buffersize + 1);
ZeroMemory(buffer,sizeof(buffer));
请注意,最初是n_buffersize = 0
,因此您只分配1个字节。
但是你将sizeof(char*)
个字节数归零(在32位系统上为4个字节,在64位系统上为8个字节)。
您可以将分配的字节数归零,即n_buffersize + 1
。或者使用calloc()
代替malloc()
。
答案 1 :(得分:0)
Execute()
内的内存管理可以简化。使用两个缓冲区,尤其是strcat()
缓冲区,效率很低。但更重要的是,main()
中的循环正在泄漏Execute()
输出的内存,无论它是如何分配的。
您也没有遵循MSDN上记录的有关STD(IN|OUT|ERR)
重定向的所有指南:
Creating a Child Process with Redirected Input and Output
即,您继承了不应该继承的句柄,并且在cmd.exe
运行时您没有关闭不使用的句柄。
尝试更像这样的东西:
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
char* Execute(char*);
HANDLE readIN = NULL;
HANDLE writeIN = NULL;
HANDLE readOUT = NULL;
HANDLE writeOUT = NULL;
int
main(int argc, char** argv)
{
SECURITY_ATTRIBUTES saAttr;
STARTUPINFO si;
PROCESS_INFORMATION pi;
char cmd[256];
char* out = NULL;
ZeroMemory(cmd, sizeof(cmd));
ZeroMemory(&saAttr, sizeof(saAttr));
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&readOUT, &writeOUT, &saAttr, 0)) {
// error handling...
}
if (!SetHandleInformation(readOUT, HANDLE_FLAG_INHERIT, 0)) {
// error handling...
}
if (!CreatePipe(&readIN, &writeIN, &saAttr, 0)) {
// error handling...
}
if (!SetHandleInformation(writeIN, HANDLE_FLAG_INHERIT, 0)) {
// error handling...
}
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(STARTUPINFO);
si.hStdError = writeOUT;
si.hStdOutput = writeOUT;
si.hStdInput = readIN;
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
if (!CreateProcess(NULL,
"cmd.exe",
NULL,
NULL,
TRUE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi
))
{
// error handling...
CloseHandle(readIN);
CloseHandle(writeIN);
CloseHandle(readOUT);
CloseHandle(writeOUT);
}
else
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(readOUT);
CloseHandle(writeIN);
do
{
if (scanf("%254s", cmd) != 1)
break;
strcat(cmd,"\n");
out = Execute(cmd);
if (!out) {
printf("ERROR!\n");
break;
}
printf("%s\n", out);
free(out);
}
while (TRUE);
CloseHandle(writeOUT);
CloseHandle(readIN);
}
return 0;
}
char*
Execute(char* cmd)
{
DWORD bwritten = 0;
DWORD buffersize = 0;
int outputsize = 0;
DWORD bread = 0;
char* buffer = NULL;
char* output = NULL;
buffersize = strlen(cmd);
while (buffersize > 0)
{
if (!WriteFile(writeIN, cmd, buffersize, &bwritten, NULL))
return NULL;
cmd += bwritten;
buffersize -= bwritten;
}
do
{
Sleep(2000);
if (!PeekNamedPipe(readOUT, NULL, NULL, NULL, &buffersize, NULL))
break;
if (buffersize == 0)
break;
buffer = (char*) realloc(output, outputsize + buffersize + 1);
if (!buffer) {
free(output);
return NULL;
}
output = buffer;
if (!ReadFile(readOUT, output + outputsize, buffersize, &bread, NULL))
bread = 0;
outputsize += bread;
output[outputsize] = '\0';
}
while (bread > 0);
return output;
}