如何打开一个程序或创建一个进程 (适用与执行CMD命令)

打开一个程序和创建一个进程基本上是同一个意思。我们的工具箱里面有几个函数备选:
system, WinExec, ShellExecuteEx, CreateProcess,他们有以下几点不同:
- 只有system是同步操作。
- 只有ShellExecuteEx, CreateProcess支持Unicode。
- 是否打开新的Console窗口: 只在父子都是console下有效
   system,WinExec总是不会打开。ShellExecuteEx,CreateProcess则可以控制是否打开新Console窗口
- 是否显示:在父子至少有一个不是console的情况下有效。

[system]
system是在简单的可怜,只需传入一个命令行。
system( "notepad C://boot.ini" );


[WinExec]
WinExec比之system能够控制目标窗口显示与否。
WinExec( "notepad C://boot.ini", SW_SHOW );
WinExec( "/"C://WINDOWS//system32//notepad.exe/" C://boot.ini", SW_HIDE );
cout << "xx" << endl;
WinExec( "taskkill", SW_HIDE );
cout << "xx" << endl; // 这个xx会先于taskkill的内容显示(因为创建进程是异步的,并且不会很快)


[ShellExecuteEx]
WinExec最大的缺陷是不支持宽字符,你无法找到WinExecW。另外你无法针对你打开的程序做进一步的操作,比如等待程序结束等。
如果你有这些需要,就应该使用ShellExecuteEx。
需要做的配置一个SHELLEXECUTEINFO结构,该结构描述如何打开以及打开什么样的程序。然后以ShellExecuteEx调用之。

SHELLEXECUTEINFO info;
ZeroMemory( &info, sizeof( info ) );
info.cbSize = sizeof( info );
// SEE_MASK_NOCLOSEPROCESS代表需要返回进程Handle
// SEE_MASK_NO_CONSOLE只在父子都是console时有作用,表示不要产生新的console窗口。
info.fMask = SEE_MASK_NOCLOSEPROCESS |SEE_MASK_NO_CONSOLE;
info.lpFile = _T( "notepad" ); // 注意如果没有提供路径则按下列顺序搜索文件(当前目录,系统目录,注意不包括环境变量path中的目录)
info.lpParameters = _T( "C://boot.ini" );
info.nShow = SW_SHOW;

ShellExecuteEx( &info );
// 可以进程Handle做些事情,最常见的就是等待进程结束。
WaitForSingleObject( info.hProcess, INFINITE );

 
[CreateProcess]
提供了比ShellExecuteEx更为精细的参数控制。
通常使用CreateProcess需要提供至关重要的4个参数
 - cmdLine 
 - creationFlag
 - startupInfo
 - processInfo
 
* cmdLine是你需要呼叫之process的命令行参数,比如要打开D:/test.txt, 你可以提供"notepad D://test.txt";
   值得注意的是Unicode版本的CreateProcessW要求cmdLine不能是const 
* creationFlag决定如何产生目标process
 creationFlag = CREATE_NEW_CONSOLE 将在新的console产生process
 creationFlag = CREATE_NO_WINDOW 将在后台产生process
* startupInfo决定产生的process的其实信息,通常我们会设置产生process时是否显示窗口,这样做:
  startupInfo.dwFlags = STARTIF_USESHOWWINDOW;
  startupInfo.wShowWindow = SW_SHOW; // SW_HIDE(表示在后台运作,与creationFlag呼应)
* processInfo则是个输出参数,目标进程创建成功后,此输出参数将包含进程相关信息。

下面是一个典型的示例

HANDLE ExecuteFile( const CString& fileName, const CString& arguments,
                   DWORD showWindowOption, 
                   const CString& windowTitle )
{
    DWORD creationFlag = 0;

    STARTUPINFO startupInfo;
    ZeroMemory( &startupInfo, sizeof( startupInfo ) );
    startupInfo.cb = sizeof( startupInfo );
    startupInfo.dwFlags = STARTF_USESHOWWINDOW; // 使特定成员有效
    startupInfo.wShowWindow = ( WORD )showWindowOption;
    startupInfo.lpTitle = const_cast< LPWSTR >( windowTitle.GetString() );

    CString commandLine = fileName + _T( " " ) + arguments;   
    
    PROCESS_INFORMATION processInfo;
    CreateProcess( 
        NULL, 
        const_cast< LPWSTR >( commandLine.GetString() ), 
        NULL, 
        NULL, 
        false, 
        creationFlag, 
        NULL, 
        NULL, 
        &startupInfo, 
        &processInfo 
        );    
    return processInfo.hProcess;
}


可以在创建进程后通过WaitForSingleObject来捕捉核心对象hProcess
当进程结束后,WaitForSingleObject(hProcess, INFINITE)返回。
当然你可以WaitForSingleObject(hProcess, 0) == WAIT_OBJECT_0来立刻检测进程是否结束。


最后一定要CloseHandle( hProcess ) 关闭进程句柄

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CMDebug 是 Take Command IDE 和批处理调试器组件的独立版本。 CMDebug 适用于开发人员创建批处理文件以在 CMD(Windows 默认命令处理器)或 TCC-RT(TCC 的免费运行时版本)中运行。 CMDebug 允许您使用集成的图形化IDE编写和调试批处理脚本。 CMDebug 包括选项卡式编辑窗口以及具有单个步骤,断点,语法着色,工具提示,书签以及选项卡式变量和监视窗口的复杂调试器。 Windows 批处理文件编程从未如此简单或更强大! 您可以使用 CMDebug 开发与 CMD 兼容的批处理文件(.BAT 或 .CMD)或与 TCC-RT 兼容的脚本(.BTM)。如果选择“ TCC 语法”选项,则 CMDebug 支持完整的 TCC-RT 命令集。如果选择“ CMD 语法”选项,则 CMDebug 将禁用仅TCC的内部命令,变量和函数。一些内部 CMD/TCC 命令的行为也将稍有不同,或修改其显示输出以更紧密地匹配 CMD 的行为。 通过将 CMDebug 与 TCC-RT 结合使用,可以使用 TCC 命令语言创建(和加密)脚本,然后使用免费的 TCC-RT 运行时将它们分发到无限数量的目标计算机上。 CMD 编程调试命令增强版 JP Software CMDebug 25 中文版CMD 编程调试命令增强版 JP Software CMDebug 25 中文版 CMDebug 汉化版功能 使用集成的图形化 IDE 创建和调试批处理脚本。 IDE 包括选项卡式编辑窗口和具有单个步进,断点,语法着色,工具提示,书签,选项卡式变量和监视窗口的复杂调试器。 Windows 批处理文件编程从未如此简单或更强大! TCC-RT 脚本语言是 Windows CMD shell 的巨大超集,具有 245 多个内部命令,400 多个内部函数和 300 多个系统变量。几乎所有的CMD命令命令(例如 DIR,COPY,DEL,START 等)都通过数百个其他选项得到了增强。 TCC 添加了 200 多个新命令。 TCC-RT 通常可以在一两行中完成,这需要数十个 CMD 命令(如果 CMD 完全可以做到) 。 脚本语言包括一整套扩展的流控制结构,包括 IF-Then-Else,DO 和 FOR 循环,SWITCH,子例程,批处理库等。 使用 TCC-RT 语法时,大多数交互式命令(例如 COPY,DEL,DIR,MOVE,REN,START 等)都有命令对话框,可让您选择文件名和选项并在执行之前查看命令行。最强大的 Windows 命令处理器也是最容易使用的! 监视系统的硬件和软件事件,并在触发事件时执行命令。您可以监视目录更改,剪贴板,事件日志,以太网和 WiFi 连接,服务,进程以及 USB 和 Firewire 连接。 环境变量替换得到了极大的增强,包括嵌套变量,延迟扩展,间接变量,多维数组变量以及对注册表中系统,用户和易失变量的直接访问。 按日期,时间,大小,所有者和扩展通配符或正则表达式选择或排除文件,以在文件管理中提供极大的灵活性。 为大多数文件处理命令(即COPY,DEL,DIR,MOVE等)指定多个文件名,或者指定包含文件名参数的文件名。 (COPY 甚至支持多个目标以及多个来源。) 有多种类型的 I/O 重定向,包括重定向和管道传输到 STDERR,“处理中”管道,“ here-document”和“ here-string”重定向以及 Tee 和 Y 管道配件。 将击键发送到任何应用程序(控制台或 GUI) 。 TCC-RT 包含用于 ZIP,7ZIP,TAR,JAR,GZIP 和 BZIP 文件的内部压缩和提取命令。 您可以在所有命令处理器文件处理命令(COPY,DEL,MOVE 等)中访问 FTP,TFTP 和 HTTP(包括 SSL 和 SSH)目录和文件。 包括对 Perl,Lua,REXX,PowerShell,Python,Tcl/tk 和任何 Windows Active Scripting 语言的内部支持。您甚至可以在批处理脚本中组合多种语言。 以及成千上万的详细信息-请参阅我们的在线帮助。 CMDebug 中文版与 Microsoft Windows 7,Server 2008R2,Windows 8,Server 2012,Windows 10,Server 2016 和 Server 2019 的任何版本兼容。CMDebug 提供 32 位和 64 位版本。
要在Java中执行Windows的cmd命令并返回该命令进程ID,您可以使用`Process`类和`ProcessBuilder`类来实现。下面是一个示例代码: ```java import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class CmdExecutionWithProcessBuilderExample { public static void main(String[] args) { try { // 创建ProcessBuilder对象 ProcessBuilder processBuilder = new ProcessBuilder("cmd", "/c", "echo Hello World"); // 启动进程 Process process = processBuilder.start(); // 获取进程ID long pid = getProcessId(process); System.out.println("进程ID:" + pid); // 等待命令执行完毕 process.waitFor(); System.out.println("命令执行完毕!"); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } private static long getProcessId(Process process) { long pid = -1; try { // 获取Process对象内部的pid字段 if (process.getClass().getName().equals("java.lang.Win32Process") || process.getClass().getName().equals("java.lang.ProcessImpl")) { java.lang.reflect.Field field = process.getClass().getDeclaredField("handle"); field.setAccessible(true); long handle = field.getLong(process); // 调用Windows API获取进程ID Kernel32 kernel = Kernel32.INSTANCE; WinNT.HANDLE winHandle = new WinNT.HANDLE(); winHandle.setPointer(Pointer.createConstant(handle)); pid = kernel.GetProcessId(winHandle); } } catch (Exception e) { e.printStackTrace(); } return pid; } } // 定义内部类和接口以获取进程ID interface Kernel32 extends com.sun.jna.Library { Kernel32 INSTANCE = com.sun.jna.Native.load("kernel32", Kernel32.class); int GetProcessId(WinNT.HANDLE Process); } interface WinNT extends com.sun.jna.win32.StdCallLibrary { interface HANDLE extends com.sun.jna.PointerType { } } ``` 在上面的示例中,我们使用`ProcessBuilder`类创建一个cmd命令进程,并使用`start()`方法启动进程。然后,我们通过调用`getProcessId()`方法获取该进程的ID。 `getProcessId()`方法使用Java Native Access (JNA)库来调用Windows API,从`Process`对象中获取进程的句柄,并通过句柄获取进程ID。 请注意,上述代码需要依赖JNA库,您需要在项目中引入JNA库的相关依赖。此外,根据您执行的具体命令和环境,可能需要进行额外的适配和测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值