Windows高级编程学习笔记(二)

第三章 进程

发现这本书的文字很简练,知识点突出,而且翻译的基本没有拗口的地方,是本好书,(^o^)/~

下面进入正题。

关于内存映射

Windows内存管理的分页机制在微机原理课程中有提到,后面的章节也有相关内容。这里提前写是怕以后忘了写出来。
一直不明白”内存映射“是怎么一回事,如很多编程资料中都会说,DLL在内存中只有一份,只是映射到不同进程的地址空间中,但是具体怎么映射的让人只知其一不知其二。还有后面的内存映射文件到底是怎么映射的?使用分页机制可以解释。所谓分页机制就是使用高速缓冲区制作一个表,先将线性地址分解成各个部分,然后分级查找到此线性地址所对应的内存页面(通常4KB)。而这个表的内容是由操作系统来管理的。那么要实现共享DLL所在内存或者其他内存,只需要把相应的页面地址填入进程对应的高速缓冲区中即可,这是基本原理,其中,不是页面对其的内存是怎么处理的这些细节问题只有通过继续学习才能知道,虽然说对于编写程序没什么影响,但是作为一名C/C++程序员,尽可能多地了解更多的底层知识总不是件坏事。

知识点汇总

  • Win32的进程是惰性的。每个进程必须拥有一个主线程(primary thread)才能工作。换句话说,Windows在创建一个进程时,同时会为此进程创建一个线程。这种处理方式把进程和线程完全分开了,能运行的只有线程,进程是线程的更大一级单位,或者说是载体。在Linux中,创建的进程是可以直接运行的,相当于主线程,这种处理方式将进程和线程区分得不是非常清楚。

  • WinMain函数不是GUI程序的入口点,它是由C运行时启动函数调用的。这么说又涉及到什么是运行时启动函数的问题。下面是我的理解:C语言编程中的main()函数大家都知道吧,这个就是入口函数。不管是运行CUI还是GUI程序,都是先进入main()函数。如果是GUI程序,main()函数会先做一些处理(初始化一些变量),然后调用WinMain函数。

  • 了解WinMain的几个参数。

    hInstance:进程的实例句柄hInstance是一个地址,指向应用程序加载到内存时的起始地址(在此程序的线性地址空间)。它和hModule是一样的,之所以存在两个称呼,是由于历史原因在16位windows中遗留下来的称呼,或者说为了保持兼容性而保留的。在测试时发现每次运行程序时这个值都会不一样。
    相关函数(32位windows下):

    • GetModuleHandle(LPCTSTR lpszModule):获取已加载的EXE或DLL文件的起始地址。参数是模块名称,注意查找范围仅限于当前进程。如果为NULL,则返回此程序EXE在内存中的起始地址。另外,如果在DLL中调用此函数,同时参数为NULL,返回的仍然是调用进程的地址,而不是DLL的基地址,和上面的结论相同。

    hPrevInstance:在16位的windows下表示此应用程序的前一个运行实例,在32位下没有此意义,只是为了兼容。

    lpszCmdLine:启动参数。非常特别需要注意的是,它总一个ANSI字符串。当你CreateProcess时,传入的非空命令行参数也必须为ANSI字符串,否则应用程序会出错或者崩溃。
    这个lpszCmdLine和CUI的main函数的命令行参数不一样,第一个参数(可执行文件路径)被main除去之后传入了WinMain。
    相关函数(32bit):

    • LPTSTR GetCommandLine(VOID):获取命令行指针,有ANSI版和UINCODE版。
    • LPWSTR CommandLineToArgvW(LPWSTR cmdLine, LPINT pArgc):将宽字符版的命令行参数转换成参数数组,数组个数保存在*pArgc中。

    还可以使用全局变量来访问命令行参数:_argv(原始的ANSI字符串数组),_argc。不过如果WinMain是在mian()函数中调用的,那么自然可以访问mian()函数的两个参数:argc, argv。

  • 进程的环境变量。它就是一组全局字符串,由系统设置,这个字符串在注册表中可以找到。子进程继承自父进程,但是进程间环境变量内存区是独立的。

    相关函数:

    • GetEnvironmentVariable()
    • SetEnvironmentVaribale()
  • 进程的驱动器目录可以通过环境变量来读写。

    相关函数:
    SetCurrentDirectory()
    GetFullPathName()

  • 操作系统个版本。

    相关函数:
    DWORD GetVersionEx(LPOSVERSIONINFO lpVersionInformation):

  • 重要函数:CreateProcess()
    上一段代码:

// CreateProcess.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
#include "windows.h"
int _tmain(int argc, _TCHAR* argv[])
{
    //wprintf(L"%s\n", (const wchar_t*)argv[0]);
    STARTUPINFOA si; // 这个结构体有些成员挺有用,还有专门针对开发屏幕保护程序的标志,另外WinMian()函数的nCmdShow也是通过此结构体传递的
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);

    SECURITY_ATTRIBUTES saProcess;
    SECURITY_ATTRIBUTES saThread;
    saProcess.nLength = sizeof(saProcess);
    saProcess.lpSecurityDescriptor = NULL;
    saProcess.bInheritHandle = TRUE; // 这是设置某个内核对象的可继承性
    saThread.nLength = sizeof(saThread);
    saThread.lpSecurityDescriptor = NULL;
    saThread.bInheritHandle = FALSE; // 含义同saProcess
    PROCESS_INFORMATION piProcess;

    BOOL res = CreateProcessA(
        NULL, // 如果非空,则只在当前目录下查找
        "notepad.exe", // 必须为ANSI字符串
        &saProcess,
        &saThread,
        false, // 这是针对进程这个特殊的内核对象独有的,因为创建进程时需要创建内核句柄表,这就存在是否继承父进程的问题。
        0,
        NULL, // 指向新的环境变量字符串区,为NULL,则使用默认的、继承自父进程的环境变量
        NULL, // 设置当前驱动器和工作路径(必须包含盘符)。为NULL,则使用和父进程相同的驱动器和工作路径。
        &si,
        &piProcess // 只有它是输出,不能NULL,否则创建错误,错误码为87:参数错误
        );

    if (FALSE == res)
    {
        printf("创建新进程出错,错误码:%d", GetLastError());
    }

    return 0;
}
  • 结束进程

    三种方法:

    • 主动调用ExitProcess()函数。

    • 外部调用TerminateProcess()函数,不推荐使用,会导致资源不能被释放以及DLL推出时执行的操作没有被执行等问题。

    • 进程中所有线程都结束,系统会自动终止进程。特别的,如果主线程是自然返回的话,系统会调用ExitProcess()自动结束进程,此时可能还有线程正在执行,它们都将被终止。如果在主线程结束时想保持其他线程继续运行,那么需要主线程主动调用ExitThread()终止自己。

    进程结束,不影响子进程。
    使用WaitForSingleObject()实现阻塞调用进程直到子进程运行结束。
    创建完全分离的子进程的要点是:释放所有本进程中与子进程相关的句柄。

  • 查看进程退出代码或者查看进程是否终结:GetExitCodeProcess()。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
【原 书 名】 Advanced Windows (3rd Ed) 【原出版社】 Microsoft Press 【作 者】(美)Jeffrey Richter 【译 者】 王书洪[同译者作品] 刘光明 【内容简介】 本书以详尽资料和大量的范例深入讨论了有关32位Windows编程高级问题,包括进程和线程的管理、Win 32的内存管理、消息处理、动态链接库、文件系统和设备输入输出、结构化异常处理、Unicode等,并重点讨论了Windows 95和Windows NT在实现上的不同之处,其中包含了大量的编程技巧。 本书可供高等院校计算机专业的师生和广大的计算机编程人员使用。 【人物简介】 Jeffrey RichterJeffrey Richter是一位在全球享有盛誉的技术作家,尤其在Windows/.NET领域有着杰出的贡献。他的第一本Windows著作Windows 3: A Developer's Guide大获好评,从而声名远扬。之后,他又推出了经典著作《Windows 高级编程指南》和《Windows核心编程》。如今这两本书早已成为Windows程序设计领域的颠峰之作,培育了几代软件开发设计人员。他的每一本新作问世,我们都有理由相信这是一本巨著,我们想要的一切尽在其中。Jeffery 是Wintellect公司的创始人之一,也是MSDN杂志.NET专栏的特邀编辑。现在他正领导开发该公司的.NET程序设计课程,向大众推广.NET技术。因为他自1999年开始就参与了微软.NET框架开发组的咨询工作,与这些一线人员一起经历了.NET的孕育与诞生,所以他对.NET思想的领悟、对.NET的细节熟稔,是其他任何作家难以企及的。他是.NET著作领域中当之无愧的一面旗帜。
本书是按照Windows 7的功能组织划分的,这样读者便能很快找到应用程序所需的内容。通常,每章涉及一个专题或是一类专题(例如Taskbar编程技术)。如果某个专题或某类专题跨越多章,通常靠前章节内容较简单,靠后章节需要熟悉一些编程技能才能理解。本书还要用到一些第三方库文件,如何使用这些库文件在书中有详细的讲解。如果对示例代码进行适当的讲解,您就会举步维艰。本书将上述专题划分为以下几部分: ● Windows 7简介:在这一部分中就您所关心的许多问题进行初步解答,例如Windows 7中的新功能。同时,这一部分还介绍了如何创建Windows 7升级策略。Windows 7有很多新功能,这导致许多开发人员面对创建升级策略问题时手足无措,因此本书还进一步就此问题提供了一些有建设性的建议。最后,在这一部分中讨论了.NET Framework 4.0。许多Windows 7的新功能要求采用新版.NET Framework。 ● 使用Windows 7用户界面:在您第一次启动Windows 7操作系统时,首先注意到的功能便是Windows 7的用户界面。它不但看上去引人注目,而且内在还有很多实用功能。这一部分内容帮助您了解所有用户界面的功能,同时让您学会使用这些新功能,例如Jump List。您或许注意到右击某些Windows 7应用程序会出现一个最近文件列表——您也能在应用程序中加入此功能,它属于这一部分的内容。这部分还要讨论新的界面功能,例如Ribbon界面,其中涉及了如何让应用程序充分利用Aero Glass的功能。在这一部分中甚至还能找到专门讨论多点触摸的专题。 ● 开发安全的应用程序:Windows 7中的安全发生了翻天覆地的变化,这一点用户未必能注意到,但不能视而不见。虽然微软放松了某些地方的安全要求,允许更多应用程序能畅通无阻地运行,但这只是其中的一种安全需求。在其他方面,微软明显加强了安全保障或是把整个安全措施推倒重来。您或许会突然发现开发的应用程序无法像从前那样正常运行,因为应用程序没有访问某些资源的权限,或是某个资源再也不能使用。此外,您还能了解到如何使用Windows 7安全功能,例如Windows Firewall。这一部分内容的代码是本书代码最多的地方,它包含了很多添加、删除、查询Windows Firewall端口的示例程序。 ● Windows 7高级编程:许多Windows 7的新功能并不完全适合于现有分类。您或许注意到了Windows 7的库功能,这是一种新功能,用户能把他们的文件放到库中并访问库中的文件,但用户无需考虑文件实际的存放位置。这一部分内容包含了一些讲解如何把应用程序的文件添加到库中的代码,这样您就可以把文件保存到一个安全的位置,但需要这些文件的用户仍能访问这些文件。此外,这部分内容还会介绍另外一些新技术,例如触发器-启动服务、64位应用程序支持和并行处理技术。这部分内容甚至还用了一章的篇幅专门介绍Windows 7对传感器所提供的支持。想象一下,您的显示器能根据外部光源的明暗自动调节亮度,这是多么棒的功能。但这仅仅只是传感器的一种用法,本书会讲解使用这些传感器的技术。最后,您可能有某个应用程序就是无法在Windows 7环境下运行,但您又必须要使用这个应用程序。这部分内容还有一章专门讨论Windows XP模式,它能解决Windows 7环境下旧应用程序无法运行的问题。 ● 在命令行方式下工作:今日开发人员和系统管理员使用的命令行提示符早在DOS时代就已经出现了。事实上,命令行中有些命令自从DOS时代到现在都未曾改变过。遗憾的是,命令提示符难以掌握、容易出错,所以微软开发了一种新的命令提示符,即Windows PowerShell。Windows PowerShell 2.0随Windows 7一起发布,它修正了第一版中出现的许多问题。例如,Windows PowerShell 2.0包含了一个编辑器,通过此编辑器,您可以随心所欲地编写代码,而随之附带的调试器可帮助您发现代码中的错误。本书的这一部分内容将详细而深入地探讨Windows PowerShell。事实上,您甚至能学到如何创建自己的脚本和cmdlet。 使用本书的必备条件 本书是一本讲解Windows 7编程技术的书籍,所以需要安装Windows 7。Windows 7 Ultimate版本中的功能是最为丰富的,本书绝大多数的示例程序能在这一版本的Windows 7下正常运行。最好不要使用Windows 7 Starter,因为它没有Aero Glass功能以及本书涉及到的其他一些功能。如果您想编写64位应用程序,就必须安装64位的Windows 7,否则32位的Windows 7就已经能满足本书的需求了。 本书另外假定您已经安装了Visual Studio 2010。您必须安装能运行示例程序的C#语言。本书代码是使用Visual Studio 2010 Ultimate测试的,但这些代码在Visual Studio 2010 Professional和Visual Studio 2010 Premium下也应该能正常运行。这些示例程序一般在Express Edition或特殊的教学产品上无法运行,因为这些版本缺少必要的功能。 您同时需要连接Internet。许多示例程序要求使用第三方库文件,您需要从网上下载并安装这些库文件。Windows 7中的许多功能在.NET Framework 4.0中只是部分实现,因此要创建能运行的应用程序,就必须使用这些第三方库文件。 如果您希望运行对硬件有特殊要求的应用程序,例如应用程序要求具有传感器,那么就需要将硬件连接到系统中。第18章的传感器示例程序事实上只要求使用软件传感器,因此如果您的系统中没有连接这类硬件,这些示例程序仍是可以运行的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

撬动未来的支点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值