windows核心编程之进程

什么是进程?

进程是一个正在运行程序的实例。由两部分组成:一个内核对象,用于管理进程以及一个地址空间,包含所有可执行文件或DLL模块的代码和数据,此外还包含动态内存分配。


在分析进程之前,先看下windows程序是如何创建的?

Windows应用程序分为CUI和GUI程序,即控制台用户界面和图形用户界面。

不同的应用程序链接器开关不同,/SUBSYSTEM:CONSOLE和/SUBSYSTEM:WINDOWS分别代表不同应用程序的链接器开关。

不同的应用程序必须有一个入口点函数,开始运行的时候,该函数被调用。为此,VC的“系统-子系统”值删除掉,即不指定控制台或GUI,则编译器会根据代码中存在main或者WinMain来自动选择子系统(这里不谈Unicode了),很方便!

启动程序:

根据子系统执行mainCRTStartup/WinMainCRTStartup,在该函数中干几件事(1)准备命令行和环境变量(用于char *argv[]char *env[])(2)初始化CRT的全局变量(包括_osver_winmajor_winver__argc_environ等)(3)初始化CRT运行库的内存分配(mallocfree)、IO函数等(4)初始化全局对象调用C++构造函数。


退出程序:

main返回后mainCRTStartup会调用exitexit干以下几件事:(1)执行通过_onexit注册的函数(2)执行全局对象的C++析构函数(通过atexit注册的)(3)判断_CrtDumpMemoryLeaks设置的内存泄漏检测标志,尝试检测内存泄漏(4)调用ExitProcess


Windows应用程序如何使用实例句柄呢?

可执行文件的实例被当做(w)WinMain函数的一个参数hInstanceExe传入。有时需要HINSTANCE,有时候需要HMODULE类型。通过GetModuleFileName获取该类型句柄。HINSTANCE是指可执行文件的映像文件加载到内存后的基址(链接器中可以配置)。可以通过GetModuleHandle函数返回一个句柄或者基地址。传入NULL可以得到执行文件的HINSTANCE(即使调用者位于某个模块中同样返回应用程序基址)。


进程的环境变量

 访问环境变量:char *env[]参数、GetEnvironmentStringsGetEnvironmentVariableExpandEnvironmentStrings(将一个使用了类似”%USERPROFILE%”环境变量的字符串中的变量替换成值)。系统环境变量:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Enviroment。用户环境变量:HKEY_CURRENT_USER\Enviroment修改环境变量后可以通知相关的系统窗口(如控制面板等):SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) “Enviroment”)

进程的驱动器和目录

如果不提供完整路径,windows函数会在当前驱动器的当前目录查找文件和目录。

更改和获取当前目录的方式为如下函数GetCurrentDirectory和SetCurrentDirectory。进程的当前目录的设置,如一个进程的环境变量如下

=C:=C:\Uility\Bin

=D:=D:\Program Files

为此C驱动器的当前目录为\Uility\Bin ,D盘驱动器的当前目录为\Program Files 可以用C函数_chdir函数可以设置环境变量。

GetVersionEx获取系统版本信息。

VerifyVersionInfo检测当前系统是否满足版本需要

如何创建一个进程呢?CreateProcess函数

当一个线程调用该函数时,就会创建一个内核对象并初始使用计数为1,用于管理进程,然后系统为进程创建一个虚拟地址空间。主线程内核对象和进程的内核对象一样。主线程会运行windows程序的启动函数,并调用入口函数。该函数的参数介绍如下:

CreateProcess的参数:关于lpApplicationNamelpCommandLine,有两种用法:(1前者指定应用程序路径,后者指定参数(第一个参数前面要有一个空格,似乎底层会直接连接两个串)(2)前者为NULL,后者指定路径和参数,空格隔开。常用第二种方法。注意,lpCommandLine中由于是用空格分隔参数的,所以对其中含有空格的路径一定要用内层引号括起来。另外CreateProcessW有一个奇怪的行为,它会修改参数lpCommandLine(似乎只在lpApplicationName为空的时候会修改),所以使用Unicode版本的时候传入的该参数不能是常字符串(如L”Nodepad 1.txt”),而应该另外准备缓冲传给该API供其修改,因为ANSI版本是调用Unicode版本的且在编码转换的时候内置了缓冲,所以CreateProcessAlpCommandLine参数可以是常串(最终API会修改转换编码的临时缓冲)。默认情况下,CUICUI型子进程会和父进程共享控制台,在参数dwCreationFlags中添加DETACHED_PROCESSCREATE_NEW_CONSOLE标志可以阻止这种行为。在dwCreationFlags中添加CREATE_NEW_PROCESS_GROUP标志,可以控制进程组的组织,用户按下Ctrl+C的时候同一进程组的所有进程得到通知。lpEnvironment指定为NULL的时候,底层为用GetEnvironmentStrings来填充。lpCurrentDirectoryNULL的时候,子进程继承父进程的当前目录。lpStartupInfo不能为空,至少要初始化结构为0并将cb赋为sizeof。使用STARTUPINFOEX结构作为lpStartupInfo参数,还可以具体指定子进程要继承哪些父进程的可继承内核对象(即使bInheritHandles参数为FALSE)。

Windows创建子进程的目的?

1.与父进程地址隔离;2.可以同时处理不同的代码;

进程之间如何共享数据呢?

动态数据交换DDE,OLE,管道,邮件槽,其中匿名管道使用过,用来执行.bat脚本去抓取手机产品的数据。共享数据最方便的方式是内存映射文件。

内存映射文件解析:

与虚拟内存相比,内存映射文件允许开发人员预定一块地址空间区域并给球调拨物理存储器。内存映射文件的物理存储器来自于磁盘上已有的文件。内存映射主要用于以下三种情况:

• 系统使用内存映射文件,以便加载和执行. exe和DLL文件。这可以大大节省页文件空间和应用程序启动运行所需的时间。

• 可以使用内存映射文件来访问磁盘上的数据文件。这使你可以不必对文件执行I/O操作,并且可以不必对文件内容进行缓存。

• 可以使用内存映射文件,使同一台计算机上运行的多个进程能够相互之间共享数据。Windows确实提供了其他一些方法,以便在进程之间进行数据通信,但是这些方法都是使用内存映射文件来实现的,这使得内存映射文件成为单个计算机上的多个进程互相进行通信的最有效的方法。

首先分析一下操作系统内存原理:这篇文章讲述非常好:http://blog.csdn.net/do2jiang/article/details/4690967

分析进程的数据共享方法1,即在同一个可执行文件或DLL的多个实例间共享静态数据。

每个.exe文件或DLL文件映射由许多段组成。每个标准的段名都以点号开始。

编译程序的时候,编译器会将代码放在一个名叫.text的段中。比外,未经过初始化的数据放在.bss段中,将已经初始化的数据放在.data段中。

除了标准段以外,编译的时候使用编译器指示符来创建自己的段。举例:

#pragma data_seg("Shared")

LONG g_lInstanceCount = 0;

#pragma data_seg()

/SECTION:Shared, RWS


存映射文件在进程中共享数据的例子:

http://www.cnblogs.com/fangyukuan/archive/2010/09/09/1822310.html


  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值