Windows程序设计(1)——Win32运行原理(二)
3 创建进程
3.1 进程和线程
进程通常被定义为一个存在运行的程序的实例。进程是一个正在运行的程序,它拥有自己的虚拟地址空间,拥有自己的代码、数据和其他系统资源。一个进程也包含一个或者多个运行在此进程内的线程。
程序是指一连串的静态的指令,而进程是一个容器,它包含了一系列运行在这个程序实例上下文中的线程使用的资源。
每个进程至少拥有一个在它的地址空间中运行的线程。操作系统创建进程后,会创建一个线程执行进程中的代码。通常把这个线程称为该进程的主线程。
3.2 应用程序的启动过程
应用程序必须有一个入口函数,它在程序开始运行的时候被调用。如:
int main(int argc, char* argv[]);
操作系统事实上并不是真正的调用main函数,而是去调用C/C++运行期启动函数,此函数会初始化C/C++运行期库。它会保证在用户的代码执行之前所有的全局的或者静态的C++对象能够被正确的创建,执行这些对象的构造函数中的代码。在控制台应用程序中,C/C++运行期启动函数会调用程序入口函数main。
在Win32程序的启动过程中。应用程序的启动过程就是进程的创建过程,操作系统是通过调用CreateProcess函数来创建新的进程的。当一个线程调用CreateProcess函数的时候,系统会创建一个进程内核对象,其使用计数被初始化为1。此进程内核对象不是进程本身,仅仅是一个系统用来管理这个进程的小的数据结构。系统然后会为新的进程创建一个虚拟地址空间,加载应用程序运行时所需要的代码和数据。
系统接着会为新进程创建一个主线程,这个主线程通过执行C/C++运行期启动代码开始运行,C/C++运行期启动代码又会调用main函数。如果系统成功创建了新的进程和其主线程,CreateProcess函数会返回TRUE,否则返回FALSE。
一般将创建进程称为父进程,被创建的进程称为子进程。系统在创建进程时会为新进程指定一个STARTUPINFO类型的变量,这个结构包含了父进程传递给子进程的一些显示信息。
typedef struct _STARTUPINFO {
DWORD cb; // 本结构长度,总是应该设为为sizeof(STARTUPINFO)
LPTSTR lpReserved; // 保留字段
LPTSTR lpDesktop; // 指定桌面名称
LPTSTR lpTitle; // 操控台应用程序使用,指定控制台窗口标题
DWORD dwX; // 指定新创建窗口的位置坐标和大小信息
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars; // 控制台应用程序使用,指定控制台窗口的大小
DWORD dwYCountChars;
DWORD dwFillAttribute; // 控制台应用程序使用,指定控制台窗口的前/背景色
DWORD dwFlags; // 标志,标识本结构中哪些成员的值是有效的
WORD wShowWindow; // 窗口显示方式
WORD cbReserved2; // 保留
LPBYTE lpReserved2; // 保留
HANDLE hStdInput; // 控制台应用程序使用,内个标准句柄
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
一个进程可能调用GetStartupInfo函数来取得父进程创建自己时使用的STARTUPINFO结构。事实上,Windows系统就是通过调用这个函数来取得当前进程的创建信息的。
VOID GetStartupInfo(
LPSTARTUPINFO lpStartupInfo // startup information
);
定义一个STARTUPINFO结构的对象以后,总要在使用此对象将对象的cb成员初始化为STARTUPINFO结构的大小,如:
STARTUPINFO si = {sizeof(si)};
::GetStartupInfo(&si);
3.3 CreateProcess函数
CreateProcess函数创建一个新的进程和该进程的主线程。函数原型如下:
BOOL CreateProcess(
LPCTSTR lpApplicationName, // 可执行文件/模块的名称
LPTSTR lpCommandLine, // 指定传递给执行模块的参数
LPSECURITY_ATTRIBUTES lpProcessAttributes, // 进程安全性,值为NULL表示使用默认安全属性
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全性,值为NULL表示使用默认安全属性
BOOL bInheritHandles, // 指定当前进程中的可继承句柄是否可被新进程继承
DWORD dwCreationFlags, // 指定新进程的优先级和其他创建标志
LPVOID lpEnvironment, // 指定新进程使用的环境变量
LPCTSTR lpCurrentDirectory, // 指定新进程使用的当前目录
LPSTARTUPINFO lpStartupInfo, // 指定新进程中主窗口位置、大小和标准句柄等
LPPROCESS_INFORMATION lpProcessInformation // 返回新建进程的标志信息,如ID和句柄
);
这里很多的变量类型都与平时使用的不太一样,它一般有如下的定义:
typedef unsigned long DWORD;
typedef int BOOL;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef float FLOAT;
typedef void far *LPVOID;
typedef int INT;
typedef unsigned int UINT;
lpApplicationName和lpCommandLine参数指定了新的进程将要使用的可执行文件的名称和传递给新进程的参数,如果lpApplicationName为空,那么将lpCommandLine中第一个空白分隔之前的字符串做为模块名。如下启动记事本:
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
char *szCommandLine = "notepad";
::CreateProcess(NULL, szCommandLine, NULL, NULL,
FALSE, NULL, NULL, NULL, &si, &pi);
如果lpCommandLine参数中的第一个单词没有后缀,则.exe后缀将被添加进来。CreateProcess函数将会按照以下路径去搜索可执行文件:
- 调用进程的可执行文件所在的目录。
- 调用进程的当前目录。
- Windows的系统目录(system32目录)。
- Windows目录。
- 在名称为PATH的环境变量中列出的目录。
如果文件名中包含了目录,系统会直接在这个目录中查找可执行文件。可以给启动的进程传递参数,如下参数,将使用记事本打开主进程当前目录下的ReadMe.txt文件:
char* szCommandLine = "notepad ReadMe.txt";
lpProcessInformation参数是一个指向PROCESS_INFORMATION结构的指针。CreateProcess函数在返回之前会初始化此结构成员。结构定义如下:
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess; // 新建进程的内核句柄
HANDLE hThread; // 新建进程中主线程的内核句柄
DWORD dwProcessId; // 新建进程的ID
DWORD dwThreadId; // 新建进程的主线程的ID
} PROCESS_INFORMATION;
创建一个新的进程促使系统创建一个进程内核对象和一个线程内核对象。在创建它们的时候,系统将每个对象的使用计数初始化为1。然后在CreateProcess返回之前,这个函数打开此进程内核对象和线程内核对象的句柄,并将它们的值传给上述结构的hProcess和hThread成员。此时这些内核对象的使用计数为2。因此父进程中必须有线程调用CloseHandle关闭这两个内核对象的句柄,否则子进程已经终止了,该进程的进程内核对象和主线程的内核对象也不会被释放。
进程和线程都分被分配一个唯一的ID号,且二者不会相同。但该ID会被重新利用,也就是说当一个ID的进程终止后,后续的进程或者线程是有可能再次使用该ID的。
3.4 实例
如下实例打开系统的记事本。
#include <stdio.h>
#include <windows.h>
int main(int argc, char* argv[])
{
TCHAR szCommandLine[] = "notepad";
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
BOOL bRet = ::CreateProcess(
NULL, // 该参数留空
szCommandLine, // 命令行参数
NULL, // 默认进程安全性
NULL, // 默认线程安全性
FALSE, // 指定当前进程内的句柄不被子进程继承
NULL, // 不指定优先级和创建参数
NULL, // 使用本进程的环境变量
NULL, // 使用本进程的驱动器和目录
&si,
&pi);
if (bRet)
{
// 关闭不使用的句柄
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
printf("Process ID: %d\n", pi.dwProcessId);
printf("Thread ID: %d\n", pi.dwThreadId);
}
getchar();
return 0;
}
运行结果如:
Windows程序设计(1)——Win32运行原理(二)的更多相关文章
- Windows程序设计(1)——Win32运行原理(一)
CPU保护模式与Windows系统 1 Windows多任务 2 虚拟内存 3 处理器的特权级别 内核对象 1 内核对象有什么用 2 对象句柄 3 使用计数 1 CPU保护模式与Windows系统 8 ...
- Windows程序设计(1)——Win32运行原理(三)
进程控制 1 获得系统进程 2 终止当前进程 3 终止其他进程 4 进程控制 4.1 获得系统进程 使用toolhelp模块可以实现获取系统中当前运行当中的进程列表. 思路如下,使用CreateToo ...
- 重学c#系列——c#运行原理(二)
前言 c# 是怎么运行的呢?是否和java一样运行在像jvm的虚拟机上呢?其实差不多,但是更广泛. c# 运行环境不仅c#可以运行,符合.net framework 开发规范的都可以运行. c# 程序 ...
- Nginx+FastCGI运行原理(二)
1.4 PHP与PHP-FPM的安装及优化(2) 标签rlimit_files用于设置PHP-FPM对打开文件描述符的限制,默认值为1024.这个标签的值必须和Linux内核打开文件数关联起来,例如, ...
- Python+Appium运行简单的demo,你需要理解Appium运行原理!
坚持原创输出,点击蓝字关注我吧 作者:清菡 博客:oschina.云+社区.知乎等各大平台都有. 目录 一.Appium 的理念 四个原则 1.Web-Selenium 的运行原理 2.Appium ...
- Java运行原理及内存分析
Java运行原理及内存分析 一.Java运行原理 二.Java内存分析
- java_自定义标签运行原理
一.自定义标签运行原理: 二.文字说明 1.IE->web服务器 2.Web服务器->jsp 3.遇到自定义标签,首先实例化标签所对应的标签处理器类 4.调用setPageContext方 ...
- 第二章--Win32程序运行原理 (部分概念及代码讲解)
学习<Windows程序设计>记录 概念贴士: 1. 每个进程都有赋予它自己的私有地址空间.当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,而属于其他进程的内存被屏蔽了起来,不 ...
- C++学习笔记1(Windows程序运行原理及程序编写流程)
窗口产生过程,句柄原理,消息队列,回调函数,窗口关闭与应用程序退出的工作关系,使用VC++的若干小技巧,stdcall与Lessonecl调用规范的比较,初学者常犯错误及注意事项.以下是应用程序与操作 ...
随机推荐
- 海量端口扫描工具masscan
海量端口扫描工具masscan masscan号称是互联网上最快的端口扫描工具,可以6分钟扫描整个互联网,每秒可以发送一百万个数据包.为了提高处理速度,masscan定制了TCP/IP栈,从而不影 ...
- jenkins的Pipeline代码流水线管理
1.新建一个pipline任务 2.自写一个简单的pipline脚本 a.Pipeline的脚本语法在Pipeline Syntax中,片段生成器,示例步骤中选择builf:Build a job b ...
- spring与事务管理
就我接触到的事务,使用最多的事务管理器是JDBC事务管理器.现在就记录下在spring中是如何使用JDBC事务管理器 1)在spring中配置事务管理器 <!-- JDBC事务 --> ...
- sqlserverinternals.com
http://sqlblog.com/blogs/kalen_delaney/default.aspx https://sqlserverinternals.com/
- iOS Mobile Development: Using Xcode Targets to Reuse the Code 使用xcode targets来实现代码复用
In the context of iOS mobile app development, a clone is simply an app that is based off another mob ...
- mac os+selenium2+chrome驱动+python3
mac os 10.11.5 mac自带python2.7,自己下载了python3.5,pip list查看系统中的安装包,本人电脑中已经安装了pip和setuptools,若未安装,请先使用 su ...
- webpack入门(六)——html-webpack-plugin
html-webpack-plugin 该插件可以简化创建调用webpack bundles的html文件.在每次编译后,文件名会包含有hash值的bundles 特别有用.你可以让插件为您生成一个H ...
- hql 多对多查询
这种查询,hibernate 建议用 From Dealer s inner join fetch s.carSerieses cs 实现,注意这种实现只支持b.c,不支持b.cs. 如果要用b.c ...
- Android——动画的分类
Android包含三种动画:View Animation, Drawable Animation, Property Animation(Android 3.0新引入). 1.View Animati ...
- openCV—Python(1)——初始化环境
本系列博客主要參考自--Adrian Rosebrock:<Practical Python and OpenCV: An Introductory,Example Driven Guide t ...