进程的创建与使用(win32-API)

2024-08-28 12:28
文章标签 使用 创建 进程 api win32

本文主要是介绍进程的创建与使用(win32-API),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、前言

进程可以被视作操作系统中运行程序的一个实例,是系统资源分配和调度的基本单位。每一个进程都拥有自己独立的地址空间、一组状态信息(如打开的文件、内存映射等),以及一个或多个线程来执行代码。进程之间的隔离性确保了它们不会相互干扰,而这种隔离性也是多任务操作系统能够同时运行多个应用程序而不发生冲突的关键。

在程序设计中,进程提供了并发执行的基础,允许多个程序或程序的不同部分同时运行,从而提高了系统的效率和响应速度。其次,进程之间的通信(IPC)机制,如管道、消息队列、共享内存等,使得不同进程间的数据交换成为可能,这对于构建复杂的应用系统至关重要。进程为错误处理和资源管理提供了边界,例如,一个进程崩溃通常不会影响到其他进程的正常运行。

在Windows环境下,C语言可以通过调用Win32 API来创建和管理进程。 CreateProcess函数是最常用的方法。这个函数允许启动一个新的进程,并且可以控制其继承属性、优先级、环境变量等参数。

image-20240715145317183

以下是一个简单的示例,展示如何使用CreateProcess函数来创建一个新进程:

#include <windows.h>
#include <stdio.h>int main() {STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory(&si, sizeof(si));si.cb = sizeof(si);ZeroMemory(&pi, sizeof(pi));// 尝试创建一个新进程if (!CreateProcess(NULL,   // 没有启动应用程序的路径,使用命令行"notepad.exe", // 要启动的应用程序名NULL,           // 进程的安全属性NULL,           // 线程的安全属性FALSE,          // 不继承句柄0,              // 创建标志NULL,           // 使用父进程的环境块NULL,           // 使用父进程的当前目录&si,            // STARTUPINFO结构&pi) )          // PROCESS_INFORMATION结构{printf( "CreateProcess failed (%d).\n", GetLastError() );return 0;}// 等待子进程退出WaitForSingleObject(pi.hProcess, INFINITE);// 关闭进程和主程序句柄CloseHandle(pi.hProcess);CloseHandle(pi.hThread);return 0;
}

在这个示例中,CreateProcess函数接收多个参数来指定新进程的特性,包括要启动的可执行文件名、安全属性、环境变量等。成功创建后,PROCESS_INFORMATION结构体将包含新进程和主线程的句柄,这些句柄可以用于进一步的进程管理操作,如等待进程结束、读取进程输出或向进程发送信号等。通过这种方式,C语言程序员可以在Windows平台上灵活地控制和管理进程,以实现复杂的系统级功能。

二、实操案例

2.1 CreateProcess函数详解

CreateProcess函数是Windows API中的一个重要成员,用于创建新的进程。允许启动一个可执行程序,并且可以控制新进程的属性,如环境、优先级、继承的句柄等。

以下是CreateProcess函数的原型和各个参数的详细说明:

BOOL CreateProcess(LPCTSTR               lpApplicationName,   // 可执行文件名称LPTSTR                lpCommandLine,      // 命令行参数LPSECURITY_ATTRIBUTES lpProcessAttributes,// 进程安全属性LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全属性BOOL                  bInheritHandles,    // 是否继承句柄DWORD                 dwCreationFlags,    // 创建标志LPVOID                lpEnvironment,      // 环境块LPCTSTR               lpCurrentDirectory, // 当前工作目录LPSTARTUPINFO         lpStartupInfo,      // 启动信息LPPROCESS_INFORMATION lpProcessInformation// 进程信息
);
  • lpApplicationName: LPCTSTR类型,指向一个包含可执行文件全路径名的字符串。如果此参数为NULL,则lpCommandLine必须包含完整的可执行文件名和路径。

  • lpCommandLine: LPTSTR类型,指向一个包含命令行字符串的缓冲区。该字符串包含可执行文件名和所有命令行参数。如果lpApplicationName不为NULL,则lpCommandLine应仅包含参数列表。

  • lpProcessAttributes: LPSECURITY_ATTRIBUTES类型,指向一个描述新进程安全属性的结构体。如果不需要特殊的安全属性,则可以传递NULL

  • lpThreadAttributes: LPSECURITY_ATTRIBUTES类型,类似于lpProcessAttributes,但针对的是新进程的第一个线程。通常情况下,你也可以传递NULL

  • bInheritHandles: BOOL类型,指示新进程是否继承父进程的句柄。如果设为TRUE,那么父进程中所有可继承的句柄都会被继承;否则,新进程将不继承任何句柄。

  • dwCreationFlags: DWORD类型,是一个位掩码,用于指定创建进程的选项。常见的标志包括:

    • CREATE_NEW_CONSOLE: 如果创建的进程是一个控制台应用程序,那么即使它的父进程不是控制台应用程序,也会给它分配一个新的控制台窗口。
    • CREATE_SUSPENDED: 创建进程但不立即开始执行。
    • CREATE_NO_WINDOW: 如果创建的是控制台应用程序,则不显示其窗口。
    • DETACHED_PROCESS: 创建一个与父进程完全分离的进程。
  • lpEnvironment: LPVOID类型,指向一个环境块。这是由CreateEnvironmentBlock函数创建的环境变量集合。如果不需要修改环境变量,则可以传递NULL

  • lpCurrentDirectory: LPCTSTR类型,指向一个包含初始工作目录的字符串。如果未指定,则使用父进程的当前目录。

  • lpStartupInfo: LPSTARTUPINFO类型,指向一个STARTUPINFO结构体,它包含了有关如何创建新进程的信息,如控制台窗口大小、位置、标题等。

  • lpProcessInformation: LPPROCESS_INFORMATION类型,指向一个PROCESS_INFORMATION结构体,此结构体将在成功创建进程后填充,包含新进程的句柄和其他信息。

CreateProcess函数返回TRUE表示成功,如果失败,则返回FALSE,可以通过调用GetLastError函数来获取具体的错误代码。

在使用CreateProcess时,通常需要初始化STARTUPINFOPROCESS_INFORMATION结构体,确保它们的cb成员被正确设置为结构体的大小,以便CreateProcess函数知道结构体的确切大小。

2.2 调用ffmpeg转换视频

开发环境:在Windows下安装一个VS即可。我当前采用的版本是VS2020。

下面是一个具体的示例代码,演示了如何使用CreateProcess函数来启动FFmpeg并进行视频转换。在这个例子中,把一个MP4格式的视频转换成AVI格式。

前提是,要确保你的系统中已经安装了FFmpeg,并且其可执行文件路径已经被添加到了系统PATH环境变量中。这样,在调用CreateProcess时,你可以直接使用ffmpeg作为可执行文件名,而无需提供完整路径。

下面是C语言的示例代码:

#include <windows.h>
#include <stdio.h>int main() {STARTUPINFO si;PROCESS_INFORMATION pi;char commandLine[1024];// 设置命令行参数,这里我们假定源文件名为"input.mp4",目标文件名为"output.avi"sprintf(commandLine, "ffmpeg -i input.mp4 output.avi");ZeroMemory(&si, sizeof(si));si.cb = sizeof(si);ZeroMemory(&pi, sizeof(pi));// 创建一个新进程,注意这里的NULL代表使用默认的环境变量if (!CreateProcess(NULL,commandLine,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)){printf("CreateProcess failed with error code: %d\n", GetLastError());return 1;}// 等待子进程结束WaitForSingleObject(pi.hProcess, INFINITE);// 关闭句柄CloseHandle(pi.hProcess);CloseHandle(pi.hThread);return 0;
}

这段代码中,使用sprintf函数来构造FFmpeg的命令行参数。这里,假设输入文件名为input.mp4,输出文件名为output.aviCreateProcess函数被用来启动FFmpeg进程,并传入上述构造的命令行字符串。WaitForSingleObject函数则确保程序会等到FFmpeg完成视频转换后再继续执行。

2.3 同时启动多个进程

开发环境:在Windows下安装一个VS即可。我当前采用的版本是VS2020。

要在C语言中同时运行三个FFmpeg进程以转换三个不同的视频文件,可以创建三个进程并将它们分别放入一个数组中。 使用WaitForMultipleObjects函数来等待所有进程完成。

下面是一个示例代码,展示了如何实现这一功能:

#include <windows.h>
#include <stdio.h>#define NUM_PROCESSES 3void create_ffmpeg_process(const char *inputFile, const char *outputFile, PROCESS_INFORMATION *pi)
{STARTUPINFO si;char commandLine[1024];// 构造FFmpeg命令行sprintf(commandLine, "ffmpeg -i \"%s\" \"%s\"", inputFile, outputFile);ZeroMemory(&si, sizeof(si));si.cb = sizeof(si);ZeroMemory(pi, sizeof(*pi));// 创建进程if (!CreateProcess(NULL, commandLine,NULL, NULL, FALSE, 0, NULL, NULL, &si, pi)){printf("CreateProcess failed for %s -> %s with error code: %d\n", inputFile, outputFile, GetLastError());}
}int main()
{PROCESS_INFORMATION pi[NUM_PROCESSES];HANDLE hEvents[NUM_PROCESSES];DWORD waitResult;// 创建三个FFmpeg进程create_ffmpeg_process("video1.mp4", "video1_converted.avi", &pi[0]);create_ffmpeg_process("video2.mp4", "video2_converted.avi", &pi[1]);create_ffmpeg_process("video3.mp4", "video3_converted.avi", &pi[2]);// 准备事件句柄数组for (int i = 0; i < NUM_PROCESSES; i++){hEvents[i] = pi[i].hProcess;}// 等待所有进程完成waitResult = WaitForMultipleObjects(NUM_PROCESSES, hEvents, TRUE, INFINITE);if (waitResult == WAIT_FAILED){printf("WaitForMultipleObjects failed with error code: %d\n", GetLastError());return 1;}// 关闭所有句柄for (int i = 0; i < NUM_PROCESSES; i++){CloseHandle(pi[i].hProcess);CloseHandle(pi[i].hThread);}return 0;
}

在这段代码中,定义了一个create_ffmpeg_process函数,接受输入文件名、输出文件名和一个PROCESS_INFORMATION结构体作为参数,用于创建单个FFmpeg进程。在main函数中,为每个视频文件调用这个函数,创建三个进程,并将每个进程的句柄存放在一个数组中。

使用WaitForMultipleObjects函数来等待所有三个进程完成。这个函数会阻塞,直到所有指定的事件(在这里是进程句柄)都被满足,即所有进程都已退出。最后,遍历进程信息数组,关闭所有的进程和线程句柄。

这篇关于进程的创建与使用(win32-API)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1114759

相关文章

Spring IoC 容器的使用详解(最新整理)

《SpringIoC容器的使用详解(最新整理)》文章介绍了Spring框架中的应用分层思想与IoC容器原理,通过分层解耦业务逻辑、数据访问等模块,IoC容器利用@Component注解管理Bean... 目录1. 应用分层2. IoC 的介绍3. IoC 容器的使用3.1. bean 的存储3.2. 方法注

Python内置函数之classmethod函数使用详解

《Python内置函数之classmethod函数使用详解》:本文主要介绍Python内置函数之classmethod函数使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 类方法定义与基本语法2. 类方法 vs 实例方法 vs 静态方法3. 核心特性与用法(1编程客

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

Linux中压缩、网络传输与系统监控工具的使用完整指南

《Linux中压缩、网络传输与系统监控工具的使用完整指南》在Linux系统管理中,压缩与传输工具是数据备份和远程协作的桥梁,而系统监控工具则是保障服务器稳定运行的眼睛,下面小编就来和大家详细介绍一下它... 目录引言一、压缩与解压:数据存储与传输的优化核心1. zip/unzip:通用压缩格式的便捷操作2.

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

Python中win32包的安装及常见用途介绍

《Python中win32包的安装及常见用途介绍》在Windows环境下,PythonWin32模块通常随Python安装包一起安装,:本文主要介绍Python中win32包的安装及常见用途的相关... 目录前言主要组件安装方法常见用途1. 操作Windows注册表2. 操作Windows服务3. 窗口操作

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹