C/c++中一次性执行多个DOS命令的实现思路

  

  

最近给公司的一个系统写了个启动的脚本,但是领导说批处理这样的脚本太低了,要使用EXE来启动,未来还要使用加密工具对EXE进行加密。

  

好吧,我就在网上到处找蝙蝠转exe的工具,找了很久,都没有找到合适的,只有一个用解压缩的软件制作自解压包的方法还算可以,但是这玩意儿有两个坑爹的问题:

  

使用了自定义图标后,安装时会被360报告有木马;
  用解压缩的软件制作的exe,其本质还是解压后执行,解压后的文件其实可以在系统临时目录下找的到,因此以后想要加密其实很容易就会被破解;
  

  

所以最好的办法看来就是自己写一个exe了,考虑到我以前用过C,因此下载了Dev-Cpp这个工具来编写代码。

  

  

在C语言中执行DOS命令的方法很多,如:ShellExecute, WinExec, CreateProcess等,但是这些接口都是只能一次执行一条命令,在我的启动脚本里有很多命令,有一些是设置环境变量的,这样就没法在代码中一条条执行脚本中的命令,必须要找到一个办法可以一次性执行多条命令。

  

在网上找了很久,最终确定使用CreateProcess,同时要使用管道技术,也就是使用CreateProcess创建一个cmd进程,然后通过输入管道将待执行的命令传递给cmd进程,通过输出管道获取cmd进程的输出信息,因为是通过管道进行,所以可以模拟在DOS窗口一行行输入命令,从而实现执行多条DOS命令了。

  

  

从MSDN上找到管道的示例代码,简单修改了一下。

  

首先,将CreateProcess的参数改为启动cmd:,,

        char cmdLine []=" cmd”;//创建子进程。   bFuncRetn=CreateProcess(空,   cmdLine,//命令行   空,//过程安全属性   空,//主要线程安全属性   真的,继承//处理   0,//创建旗帜   空,//使用父母的环境   空,//使用父母的当前目录   ,siStartInfo,//STARTUPINFO指针   ,piProcInfo);//接收PROCESS_INFORMATION      

然后,将原来批处理里面的脚本复制一下,放到一个变量里(这里我改了一下,没有用我实际的脚本,因为那个不通用,不适合做例子),注意,每一行最后要加上回车符\ n,这样才能正确模拟DOS窗口中输入命令的情况:

        CHAR cmds []=" @ECHO \ n”   “cd . . \ n”   “dir \ n”      

再然后,原来的示例代码中是把批处理文件作为EXE的参数传递进来的,既然上面改为将批处理文件内容放到脚本里,代码中从文件中读取命令的那部分就要去掉了,这部分代码就不多说了。

  

完整的示例代码如下:

        # include & lt; stdio.h>   # include & lt; windows.h>   #定义BUFSIZE 4096   处理hChildStdinRd、hChildStdinWr hChildStdinWrDup,   hChildStdoutRd、hChildStdoutWr hChildStdoutRdDup,   hInputFile hStdout;   BOOL CreateChildProcess(无效);   空白WriteToPipe(无效);   空白ReadFromPipe(无效);   空白ErrorExit (const char *);   空白ErrMsg (LPTSTR BOOL);   int主要(int命令行参数个数,char * argv []) {//用来结构包含一个对象的安全描述符,并指定检索到指定这个结构的句柄是否是可继承的。//这个结构为很多函数创建对象时提供安全性设置   用来设定saAttr;   BOOL fSuccess;//设置bInheritHandle国旗就像管道句柄是用来继承。//设置句柄为可继承的,使得子线程可以使用父线程   saAttr。nLength=sizeof(用来);   saAttr。bInheritHandle=TRUE;用来   saAttr。lpSecurityDescriptor=零;//得到当前STDOUT的句柄。//取得当前应用的标准输出句柄,对于Windows控制台应用来说,一般是输出到屏幕   hStdout=GetStdHandle (STD_OUTPUT_HANDLE);//创建一个管道为子进程的标准输出。//创建一个用于输出操作的匿名管道。   如果(!CreatePipe(及hChildStdoutRd, hChildStdoutWr,, saAttr, 0))   ErrorExit (“Stdout管创造失败\ n”);//创建noninheritable读取处理并关闭可继承的阅读处理。//将输出管道的句柄绑定到当前进程   hChildStdoutRd fSuccess=DuplicateHandle (GetCurrentProcess (),   GetCurrentProcess(),和hChildStdoutRdDup 0   假的,   DUPLICATE_SAME_ACCESS);   如果(! fSuccess)   ErrorExit (“DuplicateHandle失败”);   CloseHandle (hChildStdoutRd);//创建一个管道为子进程的标准输入。//创建一个用于输入操作的匿名管道。   如果(!CreatePipe(及hChildStdinRd, hChildStdinWr,, saAttr, 0))   ErrorExit (“Stdin管创造失败\ n”);//复制写句柄管这不是遗传的。//将输入管道的句柄绑定到当前进程   hChildStdinWr fSuccess=DuplicateHandle (GetCurrentProcess (),   GetCurrentProcess(),和hChildStdinWrDup 0   假的,//不继承   DUPLICATE_SAME_ACCESS);   如果(!fSuccess)   ErrorExit (“DuplicateHandle失败”);   CloseHandle (hChildStdinWr);//创建子进程。//创建DOS子进程   fSuccess=CreateChildProcess ();   如果(!fSuccess)   ErrorExit(“创建过程失败”);//写入管道子进程的标准输入。   WriteToPipe ();//读取管是子进程的标准输出。   ReadFromPipe ();   返回0;   }   BOOL CreateChildProcess () {   PROCESS_INFORMATION piProcInfo;   STARTUPINFO siStartInfo;   BOOL bFuncRetn=FALSE;//设置PROCESS_INFORMATION结构的成员。   ZeroMemory(及piProcInfo sizeof (PROCESS_INFORMATION));//设置STARTUPINFO结构的成员。//设定DOS进程的标准输入,输出和错误信息的管道//使用前面创建的值,DOS窗口的输入输出都会被定向到本应用中   ZeroMemory(及siStartInfo sizeof (STARTUPINFO));   siStartInfo。cb=sizeof (STARTUPINFO);   siStartInfo。hStdError=hChildStdoutWr;   siStartInfo。hStdOutput=hChildStdoutWr;   siStartInfo。hStdInput=hChildStdinRd;   siStartInfo。dwFlags |=STARTF_USESTDHANDLES;   char cmdLine []=" cmd”;//创建子进程。   bFuncRetn=CreateProcess(空,   cmdLine,//命令行   空,//过程安全属性   空,//主要线程安全属性   真的,继承//处理   0,//创建旗帜   空,//使用父母的环境   空,//使用父母的当前目录   ,siStartInfo,//STARTUPINFO指针   ,piProcInfo);//接收PROCESS_INFORMATION   如果(bFuncRetn==0)   ErrorExit (“CreateProcess失败”);   其他{   CloseHandle (piProcInfo.hProcess);   CloseHandle (piProcInfo.hThread);   返回bFuncRetn;   }   }   空白WriteToPipe (VOID) {   DWORD dwRead dwWritten;   CHAR chBuf [BUFSIZE];   CHAR cmds []=" @ECHO alt=" C/c++中一次性执行多个DOS命令的实现思路">

C/c++中一次性执行多个DOS命令的实现思路