高手:调用DOS命令,当还有参数中包含“<”符号时不能创建进程,如何解决?

rocsoar 2004-08-02 04:37:53
调用DOS命令并得到返回值的函数如下:

bool __fastcall TForm1::RunCmd(AnsiString cmd,TStringList *stringlist)
{
TMemoryStream *memstream=new TMemoryStream();
AnsiString rn="\\r\\n";
PROCESS_INFORMATION proc;
STARTUPINFO start;
SECURITY_ATTRIBUTES sa;
long ret;
unsigned long lngBytesread;
HANDLE hReadPipe,hWritePipe;
char *strBuff=(char *)malloc(256);
if(strBuff==NULL)
{
return false;
}
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle=true;
sa.lpSecurityDescriptor=NULL;
ret=CreatePipe(&hReadPipe,&hWritePipe,&sa,0);
if(ret==0)
{
//创建管道失败
return false;
}
memset(&start,0x00,sizeof(STARTUPINFO));
start.cb=sizeof(STARTUPINFO);
start.dwFlags=STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
start.hStdOutput=hWritePipe;
start.hStdError=hWritePipe;
bool retc=CreateProcess(NULL,cmd.c_str(),NULL,NULL,true, 0, 0, NULL, &start, &proc);
if(!retc)
{
return false;
}
CloseHandle(hWritePipe);
unsigned long len;
memstream->Position=0;
while(true)
{
memset(strBuff,0x00,256);
GetFileSize(hReadPipe,&len);
ret = ReadFile(hReadPipe, strBuff, 256, &lngBytesread,NULL);
if(ret==0)
{
break;
}
else
{
memstream->Write(strBuff,lngBytesread);
}
}
CloseHandle(proc.hProcess);
CloseHandle(proc.hThread);
CloseHandle(hReadPipe);
memstream->Position=0;
free(strBuff);
stringlist->LoadFromStream(memstream);
memstream->Clear();
delete memstream;
return true;
}


如果我调用的命令如下:abcde.exe -s param1 <parame.txt
就会在bool retc=CreateProcess(NULL,cmd.c_str(),NULL,NULL,true, 0, 0, NULL, &start, &proc); 这一行出错。
请问如何改进?我必须要用到那样带“<”的参数,所以叫改DOS命令的人就不要浪费时间了。谢谢
...全文
288 26 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
jishiping 2004-08-04
  • 打赏
  • 举报
回复
"错误的原因是不能创建进程"
----------------------------------------------------------------------
这个原因,应该是找不到你的执行程序造成的。你执行的程序,没有使用目录名,此时
系统只会在当前的目录(就是你的程序目录)、系统的环境变量Path指定的目录、Windows
的目录,Windows的System32(或者System)目录这几个目录下查找。如果找不到执行程序,
就会出现你说的错误信息。

对于执行程序abcde.exe,你应该使用带全路径的名称,这样可能就可以了。
rocsoar 2004-08-04
  • 打赏
  • 举报
回复
To FallenAngel(堕落天使) :
你说的是正确的,但是程序如何去发送字符串?
yyszh 2004-08-04
  • 打赏
  • 举报
回复
这个不能作为参数,应该对进程的输入管道重定向吧?
具体做法不是很清楚,似乎是创建一个管道,然后跟进程的输入进行关联。
FallenAngel 2004-08-04
  • 打赏
  • 举报
回复
jishiping(JSP 季世平),他的<就是当输入符号来用,不是算特殊符号

发送字符串吧,不要用这个输入符号了
rocsoar 2004-08-04
  • 打赏
  • 举报
回复
To jishiping(JSP 季世平):
我已经绝望了,用了你的函数,还是返回同样的错误代码。
虽然失败,还是挺谢谢你的热心帮助,谢谢!!!!
rocsoar 2004-08-04
  • 打赏
  • 举报
回复
这种解决办法是先创建一个dos窗口,然后再在此窗口执行命令,可以通过重定向把结果输出到文件。
rocsoar 2004-08-04
  • 打赏
  • 举报
回复
该问题从另外一个途径得到解决。

我贴代码出来。

Main.cpp

//---------------------------------------------------------------------------

#include <vcl.h>
#include <stdlib.h>
#pragma hdrstop

#include "Main.h"



//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{

ConWin.Open(); //打开控制台窗口
ConWin.Caption = "控制台视窗测试程序";

}
//---------------------------------------------------------------------------

void __fastcall TForm1::BitBtn2Click(TObject *Sender)
{

ConWin.Execute(Edit1->Text); //在控制台视窗里面执行 DOS 命令

}
//---------------------------------------------------------------------------
void __fastcall TForm1::BitBtn3Click(TObject *Sender)
{
ConWin.printf("在控制台视窗里面显示文字\n");

}
//---------------------------------------------------------------------------
void __fastcall TForm1::BitBtn4Click(TObject *Sender)
{

ConWin.ClrScr(); //清屏

SMALL_RECT r;
ConWin.GetRect(r);
ConWin.MoveTo((r.Right+r.Left-30)/2, (r.Bottom+r.Top)/2);
ConWin.SetColor(FOREGROUND_GREEN|FOREGROUND_INTENSITY|BACKGROUND_BLUE);
ConWin.printf("屏幕中央显示蓝色背景的绿色文字");

ConWin.MoveTo(r.Left,r.Bottom); //光标移动到左下角
ConWin.SetColor(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);

}
//---------------------------------------------------------------------------
void __fastcall TForm1::BitBtn5Click(TObject *Sender)
{
ConWin.Close(); //关闭控制台窗口
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BitBtn6Click(TObject *Sender)
{
system("dos dir");

}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
BitBtn5Click(NULL);
}
//---------------------------------------------------------------------------

Main.h

//---------------------------------------------------------------------------

#ifndef MainH
#define MainH

#include "DosWin.h"
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Buttons.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TBitBtn *BitBtn1;
TBitBtn *BitBtn2;
TBitBtn *BitBtn3;
TBitBtn *BitBtn4;
TBitBtn *BitBtn5;
TBitBtn *BitBtn6;
TEdit *Edit1;
void __fastcall BitBtn1Click(TObject *Sender);
void __fastcall BitBtn2Click(TObject *Sender);
void __fastcall BitBtn3Click(TObject *Sender);
void __fastcall BitBtn4Click(TObject *Sender);
void __fastcall BitBtn5Click(TObject *Sender);
void __fastcall BitBtn6Click(TObject *Sender);
void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
private: // User declarations
TConsoleWindow ConWin; //自定义的控制台窗口类
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif


DosWin.cpp
//---------------------------------------------------------------------------
#pragma hdrstop
#include "DosWin.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)

void TConsoleWindow::Open(void)
{
if(!hCon)
{
AllocConsole();
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
}
}
//---------------------------------------------------------------------------
void TConsoleWindow::Close(void)
{
if(hCon)
{
FreeConsole();
hCon = NULL;
}
}
//---------------------------------------------------------------------------
AnsiString TConsoleWindow::fGetCaption(void)
{
char s[260];
GetConsoleTitle(s,260);
return AnsiString(s);
}
//---------------------------------------------------------------------------
void TConsoleWindow::fSetCaption(AnsiString s)
{
SetConsoleTitle(s.c_str());
}
//---------------------------------------------------------------------------
DWORD TConsoleWindow::printf(const char *f,...)
{
AnsiString s;
va_list argptr;
va_start(argptr, f);
s.vprintf(f, argptr);
va_end(argptr);
DWORD dwWritten=0;
if(WriteConsole(hCon,s.c_str(),s.Length(),&dwWritten,NULL))
return dwWritten;
return 0;
}
//---------------------------------------------------------------------------
void TConsoleWindow::MoveTo(short x, short y)
{
COORD CurPos = {x,y};
SetConsoleCursorPosition(hCon, CurPos);
}
//---------------------------------------------------------------------------
void TConsoleWindow::SetColor(WORD c)
{
SetConsoleTextAttribute(hCon, c);
}
//---------------------------------------------------------------------------
void TConsoleWindow::GetRect(SMALL_RECT &r)
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hCon, &ConInfo);
r = ConInfo.srWindow;
}
//---------------------------------------------------------------------------
int TConsoleWindow::Execute(AnsiString s)
{
return system(s.c_str());
}
//---------------------------------------------------------------------------
void TConsoleWindow::ClrScr(WORD c)
{
DWORD nBytesWrite;
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hCon, &ConInfo);
COORD CurPos = { CurPos.X = ConInfo.srWindow.Left, CurPos.Y = ConInfo.srWindow.Top };
FillConsoleOutputAttribute(hCon, c, ConInfo.dwSize.X*ConInfo.dwSize.Y, CurPos, &nBytesWrite);
FillConsoleOutputCharacter(hCon, 0, ConInfo.dwSize.X*ConInfo.dwSize.Y, CurPos, &nBytesWrite);
}
//---------------------------------------------------------------------------

DosWin.h

//---------------------------------------------------------------------------

#ifndef DosWinH
#define DosWinH
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include <vcl.h>
//---------------------------------------------------------------------------
class TConsoleWindow
{
public:
TConsoleWindow() { hCon=NULL; }
~TConsoleWindow() { Close(); }

void Open(void);
void Close(void);
int Execute(AnsiString s);
DWORD printf(const char *f,...);
void MoveTo(short x, short y);
void SetColor(WORD c);
void GetRect(SMALL_RECT &r);
void ClrScr(WORD c=FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);

__property HANDLE Handle = { read = hCon };
__property AnsiString Caption = { read = fGetCaption, write = fSetCaption };

private:
HANDLE hCon;
AnsiString fGetCaption(void);
void fSetCaption(AnsiString);
};

#endif
rocsoar 2004-08-03
  • 打赏
  • 举报
回复
TO jishiping(JSP季世平):
高手,仍然不行咯。
befree 2004-08-03
  • 打赏
  • 举报
回复
也不行吧
jishiping 2004-08-03
  • 打赏
  • 举报
回复
调用的命令如下:abcde.exe -s param1 <parame.txt
改为: abcde.exe -s param1 "<parame.txt"
rocsoar 2004-08-03
  • 打赏
  • 举报
回复
高手快出来啊。楼上所有的方法仍然不行。
Benjiaming 2004-08-03
  • 打赏
  • 举报
回复
学习
jishiping 2004-08-03
  • 打赏
  • 举报
回复
也许,你可能认为,有些用户不知道上面的知识,遇到特殊字符时,需要程序自己在参数两边添加双引号,这也是可以的。

AnsiString CheckCmdLine(AnsiString str)
{
int nPos;
AnsiString ret;
AnsiString str1;

while(str.Length() != 0) {
while(str.Length()!=0 && (str[1]
==' ' || str[1]=='\t'))
str.Delete(1, 1);
if (str.Length()==0) break;

if (ret.Length()) ret += ' ';
if (str[1] == '\"') {
ret += '\"'; str.Delete(1, 1);
if ((nPos=str.Pos('\"')) == 0)
nPos = str.Length();
str1 = str.SubString(1, nPos);
}
else {
if ((nPos=str.Pos(' ')) == 0)
nPos = str.Length();
else
nPos -= 1;
str1 = AnsiString('\"') + str.
SubString(1,nPos) + '\"';
}
ret += str1; str.Delete(1, nPos);
}
return ret;
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
TStringList *StrList=new TStringList;
AnsiString strcmd;

strcmd = Edit1->Text;
RunCmd(CheckCmdLine(strcmd), StrList);
AnsiString str1 = StrList->Strings[0];
ShowMessage(str1);
}
rocsoar 2004-08-03
  • 打赏
  • 举报
回复
To jishiping(JSP 季世平):
我之所以非要用到这个特殊符号,是因为在DOS操作台下,输入“abcde.exe -s param1” 后,屏幕会等待输入一个XML文档的内容,但是在DOS下,可以用"<"这个符号带上已经写好内容的文件名,就可以不用自己输入,从而得到返回结果。
但是在我写的程序里面,总是不能正确运行,老是报错。错误编号为:ERROR:25054加一串乱码。

被TeamSite搞疯。。。。。。。。
jishiping 2004-08-03
  • 打赏
  • 举报
回复
必要时参数两边加上双引号,这是每个人都要知道的,而不仅仅是程序员才需要知道。一般
的Windows使用者,他也必须要知道这一点,否则他就无法自己在DOS窗口(或者Windows的
Run窗口)执行带特殊字符的程序。最常见的特殊字符,就是空格字符了。如果你打开资源管
理器的“文件夹选项”下的“文件类型”,然后查看每个类型的 open 操作,你就会发现它
们的参数 %1 两边,基本上都加上了双引号。
jishiping 2004-08-03
  • 打赏
  • 举报
回复
你只要在Edit1里面输入 abcde.exe -s param1 "<parame.txt" 就可以了。当命令行参数包含
特殊字符时,必须要在参数两边加上双引号。特殊字符包括 < > | 以及空格。比如,你的程
序安装在 C:\Program Files\Test\Test.exe 下,假设你的程序要关联 .txt 类型的文件,那
么在注册表中,你关联你的程序时,必须写成(%1时第一个参数):
"C:\Program Files\Test\Test.exe" "%1"
为了防止参数带特殊字符,参数两边必须使用双引号。另外,你的执行程序的目录包含空格,
所以上面的执行程序两边也要加上双引号。
constantine 2004-08-03
  • 打赏
  • 举报
回复
up
rocsoar 2004-08-03
  • 打赏
  • 举报
回复
TO jishiping(JSP季世平):
我能够在DOS下顺利执行以下命令:abcde.exe -s param1 <parame.txt

然后原程序如下:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
TStringList *StrList=new TStringList;
AnsiString strcmd;

strcmd = Edit1->Text;
RunCmd(strcmd,StrList);
AnsiString str1 = StrList->Strings[0];
ShowMessage(str1);

}

bool __fastcall TForm1::RunCmd(AnsiString cmd,TStringList *stringlist)
{
TMemoryStream *memstream=new TMemoryStream();
AnsiString rn="\\r\\n";
PROCESS_INFORMATION proc;
STARTUPINFO start;
SECURITY_ATTRIBUTES sa;
long ret;
unsigned long lngBytesread;
HANDLE hReadPipe,hWritePipe;
char *strBuff=(char *)malloc(256);
if(strBuff==NULL)
{
return false;
}
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle=true;
sa.lpSecurityDescriptor=NULL;
ret=CreatePipe(&hReadPipe,&hWritePipe,&sa,0);
if(ret==0)
{
//创建管道失败
return false;
}
memset(&start,0x00,sizeof(STARTUPINFO));
start.cb=sizeof(STARTUPINFO);
start.dwFlags=STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
start.hStdOutput=hWritePipe;
start.hStdError=hWritePipe;
bool retc=CreateProcess(NULL,cmd.c_str(),NULL,NULL,true, 0, 0, NULL, &start, &proc);
if(!retc)
{
return false;
}
CloseHandle(hWritePipe);
unsigned long len;
memstream->Position=0;
while(true)
{
memset(strBuff,0x00,256);
GetFileSize(hReadPipe,&len);
ret = ReadFile(hReadPipe, strBuff, 256, &lngBytesread,NULL);
if(ret==0)
{
break;
}
else
{
memstream->Write(strBuff,lngBytesread);
}
}
CloseHandle(proc.hProcess);
CloseHandle(proc.hThread);
CloseHandle(hReadPipe);
memstream->Position=0;
free(strBuff);
stringlist->LoadFromStream(memstream);
memstream->Clear();
delete memstream;
return true;
}

我在Edit1里面输入 abcde.exe -s param1 <parame.txt,再点击button1,然后没有显示出正确的结果,报错。错误的原因是不能创建进程。请问如何改正程序?谢谢指点。
jishiping 2004-08-03
  • 打赏
  • 举报
回复
我自己写了一个程序,参数带 < 字符,运行时,不加引号,无法运行。在 < 所在的参数两边,加上双引号后,就能运行了。你不要先用程序测试,你自己先在DOS窗口输入上面的命
令,看看是否可以运行。如果DOS下可以,那么就肯定是你的程序写错了。
hy1080 2004-08-02
  • 打赏
  • 举报
回复
学习
加载更多回复(6)

1,222

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧