createprocess有时会无法成功运行命令行?

qinyi1229 2015-04-02 08:56:26
手头有一个项目,需要调用cmd命令行,本来是用winexec的,但后来被要求加一个功能(需要在命令行窗口运行的时候输入些内容)
于是只能用createprocess来对cmd窗口建立管道通信,但在调试的时候发现有一定的概率命令行不能被成功运行,查了半天原因估计是因为在字符串上(因为要求的命令行是个字符串变量),所以估计是这个原因导致的。

所以想问问大家,有没有什么办法能解决这个问题,或者用winexec打开cmd,然后用createprocess作为它的父进程,但是不知道怎么操作,网上也搜不到相关资料,恳请各位大侠指点一下小弟,谢谢了!
...全文
373 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
simple 2019-02-18
  • 打赏
  • 举报
回复


BOOL ExcuteCommand(const std::string &strCmd, UINT uCmdShow = SW_HIDE)
{
UINT uRet = WinExec(strCmd.c_str(), uCmdShow);
return (31 < uRet);
}
BOOL ExcuteCommand2(const std::string &strCmd, UINT uCmdShow = SW_HIDE)
{
// 打开本地文件
int iErr = (int)ShellExecute(NULL, _T("open"), "cmd.exe", strCmd.c_str(), NULL, uCmdShow);
if (SE_ERR_NOASSOC == iErr || SE_ERR_ACCESSDENIED == iErr)
{// 没有相关的程序能够打开该文件
}
else if (32 > iErr)
{
}
return (32 > iErr);
}
BOOL ExcuteCommand3(const std::string &strCmd, UINT uCmdShow = SW_HIDE)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof STARTUPINFO;
si.wShowWindow = uCmdShow;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
BOOL res = CreateProcess(
NULL,
const_cast<char*>(strCmd.c_str()),
NULL,
NULL,
NULL,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&si,
&pi);

if(res)
{
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
return TRUE;
}

void CRestartApplicationDlg::OnBnClickedBtnExec()
{
// TODO: 在此添加控件通知处理程序代码
SetDlgItemText(IDC_STATIC, "开始");
CString strCommand;
GetDlgItemText(IDC_EDIT_COMMAND, strCommand);
ExcuteCommand(strCommand.GetString(), SW_SHOW);
SetDlgItemText(IDC_STATIC, "运行结束");
}
void CRestartApplicationDlg::OnBnClickedBtnExec2()
{
// TODO: 在此添加控件通知处理程序代码
SetDlgItemText(IDC_STATIC, "开始");
CString strCommand;
GetDlgItemText(IDC_EDIT_COMMAND, strCommand);
ExcuteCommand2(strCommand.GetString(), SW_SHOW);
SetDlgItemText(IDC_STATIC, "运行结束");
}
void CRestartApplicationDlg::OnBnClickedBtnExec3()
{
// TODO: 在此添加控件通知处理程序代码
SetDlgItemText(IDC_STATIC, "开始");
CString strCommand;
GetDlgItemText(IDC_EDIT_COMMAND, strCommand);
ExcuteCommand3(strCommand.GetString(), SW_SHOW);
SetDlgItemText(IDC_STATIC, "运行结束");
}


在OnInitDialog中

SetDlgItemText(IDC_EDIT_COMMAND, "cmd.exe /c xcopy /e /c /y C:\\Users\\administrator\\Desktop\\test\\* C:\\Users\\administrator\\Desktop\\test2\\");

OnBnClickedBtnExec可以运行,但没有等待其结束
OnBnClickedBtnExec2同OnBnClickedBtnExec
OnBnClickedBtnExec3就出现闪了一下黑屏,然后什么也没有,然而将其换成“cmd.exe /c rmdir C:\\Users\\administrator\\Desktop\\test2\\”却可以,等待完成后才继续执行接下来的代码
赵老师帮我看看,我发不了贴
simple 2019-02-18
  • 打赏
  • 举报
回复

BOOL ExcuteCommand3(const std::string &strCmd, UINT uCmdShow = SW_HIDE)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof STARTUPINFO;
si.wShowWindow = uCmdShow;
si.dwFlags = STARTF_USESHOWWINDOW /* | STARTF_USESTDHANDLES */; // STARTF_USESTDHANDLES会导致lpCommandLine传递错误(原因未明)
BOOL res = CreateProcess(
NULL,
const_cast<char*>(strCmd.c_str()),
NULL,
NULL,
NULL,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&si,
&pi);

if(res)
{
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
return TRUE;
}

经过上面修改,便可以运行xcopy命令了
STARTF_USESTDHANDLES :使用stdinput、stdoutput、stderr,貌似是重定向输入输出用的,以获得其运行结果
赵4老师 2015-04-03
  • 打赏
  • 举报
回复
C:\>cmd /? 启动 Windows 命令解释程序一个新的实例 CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF] [[/S] [/C | /K] string] /C 执行字符串指定的命令然后中止 /K 执行字符串指定的命令但保留 /S 在 /C 或 /K 后修改字符串处理(见下) /Q 关闭回显 /D 从注册表中停用执行 AutoRun 命令(见下) /A 使向内部管道或文件命令的输出成为 ANSI /U 使向内部管道或文件命令的输出成为 Unicode /T:fg 设置前景/背景颜色(详细信息,请见 COLOR /?) /E:ON 启用命令扩展(见下) /E:OFF 停用命令扩展(见下) /F:ON 启用文件和目录名称完成字符(见下) /F:OFF 停用文件和目录名称完成字符(见下) /V:ON 将 ! 作为定界符启动延缓环境变量扩展。如: /V:ON 会 允许 !var! 在执行时允许 !var! 扩展变量 var。var 语法 在输入时扩展变量,这与在一个 FOR 循环内不同。 /V:OFF 停用延迟环境扩展。 请注意,如果字符串有引号,可以接受用命令分隔符 '&&' 隔开 的多个命令。并且,由于兼容原因,/X 与 /E:ON 相同,/Y 与 /E:OFF 相同,并且 /R 与 /C 相同。忽略任何其他命令行开关。 如果指定了 /C 或 /K,命令行开关后的命令行其余部分将作为命令行处 理;在这种情况下,会使用下列逻辑处理引号字符("): 1. 如果符合下列所有条件,那么在命令行上的引号字符将被 保留: - 不带 /S 命令行开关 - 整整两个引号字符 - 在两个引号字符之间没有特殊字符,特殊字符为下列中的 一个: <>()@^| - 在两个引号字符之间有至少一个空白字符 - 在两个引号字符之间有至少一个可执行文件的名称。 2. 否则,老办法是,看第一个字符是否是一个引号字符,如果 是,舍去开头的字符并删除命令行上的最后一个引号字符, 保留最后一个引号字符之后的文字。 如果 /D 未在命令行上被指定,当 CMD.EXE 开始时,它会寻找 以下 REG_SZ/REG_EXPAND_SZ 注册表变量。如果其中一个或 两个都存在,这两个变量会先被执行。 HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\AutoRun 和/或 HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun 命令扩展是按默认值启用的。您也可以使用 /E:OFF,为某一 特定调用而停用扩展。您可以在机器上和/或用户登录会话上 启用或停用 CMD.EXE 所有调用的扩展,这要通过设置使用 REGEDT.EXE 的注册表中的一个或两个 REG_DWORD 值: HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\EnableExtensions 和/或 HKEY_CURRENT_USER\Software\Microsoft\Command Processor\EnableExtensions 到 0x1 或 0x0。用户特定设置比机器设置有优先权。命令行 开关比注册表设置有优先权。 命令扩展包括对下列命令所做的更改和/或添加: DEL 或 ERASE COLOR CD 或 CHDIR MD 或 MKDIR PROMPT PUSHD POPD SET SETLOCAL ENDLOCAL IF FOR CALL SHIFT GOTO START (同时包括对外部命令调用所做的更改) ASSOC FTYPE 有关特定详细信息,请键入 commandname /? 查看。 延迟环境变量扩展不按默认值启用。您可以用/V:ON 或 /V:OFF 开关,为 CMD.EXE 的某个调用而启用或停用延迟环境变量扩展。 您可以在机器上和/或用户登录会话上启用或停用 CMD.EXE 所有 调用的延迟扩展,这要通过设置使用 REGEDT.EXE 的注册表中的 一个或两个 REG_DWORD 值: HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\DelayedExpansion 和/或 HKEY_CURRENT_USER\Software\Microsoft\Command Processor\DelayedExpansion 到 0x1 或 0x0。用户特定设置比机器设置有优先权。命令行开关 比注册表设置有优先权。 如果延迟环境变量扩展被启用,惊叹号字符可在执行时间,被用来 代替一个环境变量的数值。 您可以用 /F:ON 或 /F:OFF 开关为 CMD.EXE 的某个 调用而启用或禁用文件名完成。您可以在计算上和/或 用户登录会话上启用或禁用 CMD.EXE 所有调用的完成, 这可以通过使用 REGEDIT.EXE 设置注册表中的下列 REG_DWORD 的全部或其中之一: HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\CompletionChar HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\PathCompletionChar 和/或 HKEY_CURRENT_USER\Software\Microsoft\Command Processor\CompletionChar HKEY_CURRENT_USER\Software\Microsoft\Command Processor\PathCompletionChar 由一个控制字符的十六进制值作为一个特定参数(例如,0x4 是Ctrl-D,0x6 是 Ctrl-F)。用户特定设置优先于机器设置。 命令行开关优先于注册表设置。 如果完成是用 /F:ON 开关启用的,两个要使用的控制符是: 目录名完成用 Ctrl-D,文件名完成用 Ctrl-F。要停用 注册表中的某个字符,请用空格(0x20)的数值,因为此字符 不是控制字符。 如果键入两个控制字符中的一个,完成会被调用。完成功能将 路径字符串带到光标的左边,如果没有通配符,将通配符附加 到左边,并建立相符的路径列表。然后,显示第一个相符的路 径。如果没有相符的路径,则发出嘟嘟声,不影响显示。之后, 重复按同一个控制字符会循环显示相符路径的列表。将 Shift 键跟控制字符同时按下,会倒着显示列表。如果对该行进行了 任何编辑,并再次按下控制字符,保存的相符路径的列表会被 丢弃,新的会被生成。如果在文件和目录名完成之间切换,会 发生同样现象。两个控制字符之间的唯一区别是文件完成字符 符合文件和目录名,而目录完成字符只符合目录名。如果文件 完成被用于内置式目录命令(CD、MD 或 RD),就会使用目录 完成。 用引号将相符路径括起来,完成代码可以正确处理含有空格 或其他特殊字符的文件名。同时,如果备份,然后从行内调用 文件完成,完成被调用时位于光标右方的文字会被调用。 需要引号的特殊字符是: <space> &()[]{}^=;!'+,`~

64,649

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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