[笔记]Windows核心编程《三》进程

简介: [笔记]Windows核心编程《三》进程

进程

进程必须有一个线程

PrimaryThread 主线程

进程销毁

主线程的入口点函数返回 return(推荐)

进程的所有线程自然死亡(几乎不出现)

要么进程所有线程都调用ExitThread

调用ExitProcess 强制退出(不推荐)

在进程的一个子线程中调用ExitProcess,

缺陷:

ExitProcess 后的代码会无法执行,会有资源没有释放,因为c/c++运行库也许不能执行正确的清理工作,包括全局对象的析构和本地对象的析构。

在另一个进程调用TerminalProcess(不推荐)

在另一个进程的任意线程中调用TerminalProcess,传入被终止的进程handle。

缺陷:

被终止进程得不到终止的通知,进程得不到正确清理,也不能阻止它被强行终止,但是操作系统会在终止后彻底清理的,确保不会泄露任何操作系统资源(进程的 内存,文件,内核对象计数,用户对象,GDI对象都会被销毁)。

链接器子系统开关

将子系统的正确类型嵌入最终生成的可执行文件。

visitual studio中设置子系统方式:属性-》链接器-》子系统

/Subsystem:console 控制台程序 入口

_tmain(Main):处理ascii字符和字符串的CUI程序(控制台程序)

对应嵌入可执行文件的启动函数 mainCRTStartup

_tmain(wMain):处理Unicode字符和字符串的CUI程序(控制台程序)

对应嵌入可执行文件的启动函数 wMainCRTStartup

/Subsystem:Windows GUI程序 入口

_tWinMain(WinMain):处理ascii字符和字符串的GUI程序(图形化程序)

对应嵌入可执行文件的启动函数 WinMainCRTStartup

_tWinMain(wWinMain):处理Unicode字符和字符串的GUI程序(图形化程序)

对应嵌入可执行文件的启动函数 wWinMainCRTStartup

main函数运行生命周期

C运行时库函数

这些C运行时库函数,主要完成以下任务:

  1. 获取进程命令行指针;
  2. 获取进程环境变量指针;
  3. 初始化C/C++运行时库的全局变量,如果你包含了头Stdlib.h,那么你就可以访问这些变量!//errno这就是一个全局变量。_enrion这是环境变量指针
  4. 初始化malloc函数的内存堆;
  5. 为C++全局类,调用构造函数。

malloc 函数,不要轻易使用,因为这个函数一般来说,最终会调用windows API函数,我们直接调用virtualAlloc windowsAPI函数,效率会高!

main函数运行生命周期

Kenerl 调用XXXCRTStartup函数;

XXXCRTStartup函数调用main函数;

main函数退出;

exit函数被调用(真正调用的是crt0dat.c中的)

static void __cdecl doexit (
        int code,
        int quick,
        int retcaller
        )

这个函数主要做以下事情:

1.调用_onexit函数注册的所有函数;

2.调用C++销毁函数销毁所有的全局和静态类对象;

3.如果_CRTDBG_LEAK_CHECK_DF标志被设置,那么调用CrtDumpMemoryLeaks函数,列出泄露内存。

4.调用ExitProcess函数,系统杀死当前进程!

exit(0),ExitProcess,和TerminateProcess

获得系统

GetVersion() 获得版本号

#include <windows.h>
#include <stdio.h>
#include <VersionHelpers.h> 
void main()
{
    DWORD dwVersion = 0; 
    DWORD dwMajorVersion = 0;
    DWORD dwMinorVersion = 0; 
    DWORD dwBuild = 0;
    LPOSVERSIONINFOW lpVersionInformation;
    dwVersion = GetVersion();//GetVersionEx(lpVersionInformation);
    if (IsWindowsXPOrGreater()) {
        printf("Yes\n");
    };
  printf("%0x\n",dwVersion);
    // Get the Windows version.
  //一个子就是WORD;
  WORD Version=LOWORD(dwVersion);
  //dwVersion中,其地位字,
    dwMajorVersion = (DWORD)(LOBYTE(Version));
  //Version字的低字节代表大版本号
    dwMinorVersion = (DWORD)(HIBYTE(Version));
  //Version字的高字节代表小版本号
    // Get the build number.
    if (dwVersion < 0x80000000)              
        dwBuild = (DWORD)(HIWORD(dwVersion));
  //dwVersion的高位字,表示build号。
    printf("Version is %d.%d (%d)\n", 
                dwMajorVersion,
                dwMinorVersion,
                dwBuild);
  getchar();

CreateProcess函数

函数

BOOL CreateProcess
(
  LPCTSTR lpApplicationName,
  LPTSTR lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL bInheritHandles,
  DWORD dwCreationFlags,
  LPVOID lpEnvironment,
  LPCTSTR lpCurrentDirectory,
  LPSTARTUPINFO lpStartupInfo,
  LPPROCESS_INFORMATIONlpProcessInformation
);

参数解释

运行流程

当一个应用程序调用(或最终结束于)某个进程创建函数,比如CreateProcess 、CreateProcessAsUser、CreateProcessWithTokenW或CreateProcessWithLogonW时,一个Windows子系统进程就被创建起来了

创建一个Windows进程的过程,是由操作系统的三个部分执行一系列步骤来完成的,这三个部分是:

  • 客户方的windows库Kernel32.dll(在CreateProcessAsUser、 CreateProcessWithTokenW.或CreateProcessWithLogonW的情况下时,部分工作是由Advapi32.dl先做的)
  • Windows执行体.
  • Windows子系统进程(Csrss)。
    下面的列表概括了在利用Windows的CreateProcess函数来创建一个进程时所涉及的主要阶段:
  1. 验证参数,转换Windows子系统标志和选项为对应的原生形式:解析、验证和转换属性列表为其原生形式。
  2. 打开将要在该进程中执行的映像文件(.exe)。
  3. 创建Windows执行体进程对象。
  4. 创建初始线程(栈、执行环境,以及Windows执行体线程对象)。
  5. 进行创建之后的、Windows子系统特有的进程初始化。
  6. 开始执行初始线程(除非指定了CREATE SUSPENDED标志)。
  7. 在新进程和线程的环境中,完成地址空间的初始化(比如加载必要的DL),并开始执行程序。

图5.6显示了Windows在创建一个进程时所遵从的步骤的总体情况:

NtCreateProcess函数

CreateUserProcess的更底层实现是该函数

总结

1.使用

C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\Tools

有一些工具 包括GuidGen.exe


相关文章
|
1月前
|
监控 Ubuntu Linux
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
这篇文章介绍了如何在Ubuntu和Windows系统中通过设置相同的时区并使用ntp服务来解决时间同步问题。
65 4
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
|
1月前
|
Java 关系型数据库 MySQL
java控制Windows进程,服务管理器项目
本文介绍了如何使用Java的`Runtime`和`Process`类来控制Windows进程,包括执行命令、读取进程输出和错误流以及等待进程完成,并提供了一个简单的服务管理器项目示例。
38 1
|
2月前
|
网络协议 API Windows
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
|
2月前
|
Windows
[原创]用MASM32编程获取windows类型
[原创]用MASM32编程获取windows类型
|
2月前
|
JavaScript 前端开发 API
MASM32编程通过WMI获取Windows计划任务
MASM32编程通过WMI获取Windows计划任务
|
2月前
|
安全 开发者 Python
揭秘Python IPC:进程间的秘密对话,让你的系统编程更上一层楼
【9月更文挑战第8天】在系统编程中,进程间通信(IPC)是实现多进程协作的关键技术。IPC机制如管道、队列、共享内存和套接字,使进程能在独立内存空间中共享信息,提升系统并发性和灵活性。Python提供了丰富的IPC工具,如`multiprocessing.Pipe()`和`multiprocessing.Queue()`,简化了进程间通信的实现。本文将从理论到实践,详细介绍各种IPC机制的特点和应用场景,帮助开发者构建高效、可靠的多进程应用。掌握Python IPC,让系统编程更加得心应手。
32 4
|
2月前
|
Linux C语言
C语言 多进程编程(四)定时器信号和子进程退出信号
本文详细介绍了Linux系统中的定时器信号及其相关函数。首先,文章解释了`SIGALRM`信号的作用及应用场景,包括计时器、超时重试和定时任务等。接着介绍了`alarm()`函数,展示了如何设置定时器以及其局限性。随后探讨了`setitimer()`函数,比较了它与`alarm()`的不同之处,包括定时器类型、精度和支持的定时器数量等方面。最后,文章讲解了子进程退出时如何利用`SIGCHLD`信号,提供了示例代码展示如何处理子进程退出信号,避免僵尸进程问题。
|
2月前
|
消息中间件 Unix Linux
C语言 多进程编程(五)消息队列
本文介绍了Linux系统中多进程通信之消息队列的使用方法。首先通过`ftok()`函数生成消息队列的唯一ID,然后使用`msgget()`创建消息队列,并通过`msgctl()`进行操作,如删除队列。接着,通过`msgsnd()`函数发送消息到消息队列,使用`msgrcv()`函数从队列中接收消息。文章提供了详细的函数原型、参数说明及示例代码,帮助读者理解和应用消息队列进行进程间通信。
|
2月前
|
缓存 Linux C语言
C语言 多进程编程(六)共享内存
本文介绍了Linux系统下的多进程通信机制——共享内存的使用方法。首先详细讲解了如何通过`shmget()`函数创建共享内存,并提供了示例代码。接着介绍了如何利用`shmctl()`函数删除共享内存。随后,文章解释了共享内存映射的概念及其实现方法,包括使用`shmat()`函数进行映射以及使用`shmdt()`函数解除映射,并给出了相应的示例代码。最后,展示了如何在共享内存中读写数据的具体操作流程。
|
2月前
|
Linux C语言
C语言 多进程编程(七)信号量
本文档详细介绍了进程间通信中的信号量机制。首先解释了资源竞争、临界资源和临界区的概念,并重点阐述了信号量如何解决这些问题。信号量作为一种协调共享资源访问的机制,包括互斥和同步两方面。文档还详细描述了无名信号量的初始化、等待、释放及销毁等操作,并提供了相应的 C 语言示例代码。此外,还介绍了如何创建信号量集合、初始化信号量以及信号量的操作方法。最后,通过实际示例展示了信号量在进程互斥和同步中的应用,包括如何使用信号量避免资源竞争,并实现了父子进程间的同步输出。附带的 `sem.h` 和 `sem.c` 文件提供了信号量操作的具体实现。