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调用规范的比较,初学者常犯错误及注意事项.以下是应用程序与操作 ...
随机推荐
- TF-IDF 学习
参考资料, 阮一峰的博客 http://www.ruanyifeng.com/blog/2013/03/tf-idf.html 非常感谢他, 能用如此通俗易懂的文字来阐述概念 TF -- Term ...
- React项目的打包与部署到腾讯云
腾讯云送了30天的免费试用,于是有了把react项目部署到上面的想法.项目是默认生成的,只是一个页面,但是这个过程中也遇到了不少麻烦与问题.下面来具体梳理下: create-react-app 来自F ...
- 死磕 java同步系列之AQS起篇
问题 (1)AQS是什么? (2)AQS的定位? (3)AQS的实现原理? (4)基于AQS实现自己的锁? 简介 AQS的全称是AbstractQueuedSynchronizer,它的定位是为Jav ...
- 仓鼠找sugar(lca)
洛谷——P3398 仓鼠找sugar 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅( ...
- bzoj 4921: [Lydsy六月月赛]互质序列
4921: [Lydsy六月月赛]互质序列 Time Limit: 1 Sec Memory Limit: 256 MBSubmit: 188 Solved: 110[Submit][Status ...
- U盘格式化时分配单元的大小的设置
格式化时主要有如下格式,且对应的操作系统的不一样: FAT32:Windows和Mac都支持,不过单个文件不能超过4G,但可以采用分包压缩的方式搞定. NTFS:Windows专用格式,Mac常规无法 ...
- 转载cookie理解
本文转自https://www.cnblogs.com/dojo-lzz/p/5580301.html 服务器端像客户端发送Cookie是通过HTTP响应报文实现的,在Set-Cookie中设置需要像 ...
- SpringUtils写法
@Componentpublic class SpringUtils implements ApplicationContextAware { @Override public void setApp ...
- 邁向IT專家成功之路的三十則鐵律 鐵律二十五:IT人屈辱之道-十倍奉還
現代人普遍火氣都很大,與人爭論時只要有一點點感到屈辱,便會開始大聲反擊,甚至於暴力相向.至於企業中的人事相鬥,則是典型的來個明爭暗鬥,直到成為老闆眼中的紅人,在逐漸掌握了權力之後再來個內部大清洗,不久 ...
- lstm作的第一首诗,纪念
黄獐春风见破黛,十道奇昌犹自劳. 开领秦都色偏早,未知长柳是来恩. 争时欲下花木湿,早打红筵枝上香. 酣质矫胶麦已暮,丝窗瑞佩满含龙. 感觉有点意思哈,花木对应枝上,还有点对仗的意味. 于是接着又弄了 ...