windows核心编程(笔记一)

第1章 对程序错误的处理

当一个Windows函数检测到一个错误时,它会使用一个称为线程本地存储器(thread-local storage)的机制,将相应的错误代码号码与调用的线程关联起来.这将使线程能够互相独立地运行,而不会影响各自的错误代码。当函数返回时,它的返回值就能指明一个错误已经发生。若要确定这是个什么错误,请调用GetLastError函数.

当Windows函数运行失败时,应该立即调用GetLastError函数。如果调用另一个Windows函数,它的值很可能被改写。

进行调试的时候,监控线程的最后错误代码是非常有用的。在Microsoft Visual studio 6.0 中,Microsoft的调试程序支持一个非常有用的特性,即可以配置Watch窗口,以便始终都能显示线程的最后错误代码的号码和该错误的英文描述。通过选定Watch窗口中的一行,并键入“@err,hr”,就能够做到这一点。观察图1-1,你会看到已经调用了CreateFile函数.该函数返回INVALID_HANDLE_VALUE(-1)的HANDLE ,表示它未能打开指定的文件。但是Watch窗口向我们显示最后错误代码(即如果调用GetLastError函数,该函数返回的错误代码)是0x00000002。该Watch窗口又进一步指明错误代码2是指“系统不能找到指定的文件。”你会发现它与WinError.h头文件中的错误代码2所指的字符串是相同的。


Visual studio还配有一个小的实用程序,称为Error Lookup 。可以使用Error Lookup将错误代码的号码转换成相应文本描述.



第三章 内核对象
3.1什么是内核对象

内核对象是内核分配的一个内存块,并且只能由该内核访问。该内存块是一种数据结构,它的成员负责维护该对象的各种信息。
为了使操作系统变得更加健壮,这些句柄值是与进程密切相关的。因此,如果将该句柄值传递给另一个进程中的一个线程(使用某种形式的进程间的 通信)那么这另一个进程使用你的进程的句柄值所作的调用就会失败。

内核对象由内核所拥有,而不是由进程所拥有。换句话说,如果你的进程调用了一个创建内核对象的函数,然后你的进程终止运行,那么内核对象不一定被撤消。在大多数情况下,对象将被撤消,但是如果另一个进程正在使用你的进程创建的内核对象,那么该内核知道,在另一个进程停止使用该对象前不要撤消该对象,必须记住的是,内核对象的存在时间可以比创建该对象的进程长。


BOOL CloseHandle(HANDLE hobj);
该函数首先检查调用进程的句柄表,以确保传递给它的索引(句柄)用于标识一个进程实际上无权访问的对象。如果该索引是有效的,那么系统就可以获得内核对象的数据结构的地址,并可确定该结构中的使用计数的数据成员。如果使用计数是0 ,该内核便从内存中撤消该内核对象。

假如忘记调用CloseHandle函数,那么会不会出现内存泄漏呢?答案是可能的,但是也不一定。在进程运行时,进程有可能泄漏资源(如内核对象)。但是,当进程终止运行时,操作系统能够确保该进程使用的任何资源或全部资源均被释放,这是有保证的。对于内核对象来说,系统将执行下列操作:当进程终止运行时,系统会自动扫描进程的句柄表。如果该表拥有任何无效项目(即在终止进程运行前没有关闭的对象),系统将关闭这些对象句柄。如果这些对象中的任何对象的使用计数降为0 ,那么内核便撤消该对象。

3.3跨越进程边界共享内核对象
BOOL CreateProcess(
   PCTSTR pszApplicationName,
   PTSTR pszCommandLine,
   PSECURITY_ATTRIBUTES psaProcess,
   PSECURITY_ATTRIBUTES psaThread,
   BOOL bInheritHandles,
   DWORD fdwCreale,
   PVOIO pvEnvironment,
   PCTSTR pszCurDir,
   PSTARTUPINFO psiStartInfo,
   PPROCESS_INFORMATION ppiProcInfo);

bInheritHandle这个参数。一般来说,当生成一个进程时,将为该参数传递FALSE。该值告诉系统,不希望子进程继承父进程的句柄表中的可继承句柄。

但是,如果为该参数传递TRUE,那么子进程就可以继承父进程的可继承句柄值。当传递TRUE时,操作系统就创建该新子进程,但是不允许子进程立即开始执行它的代码。当然,系统为子进程创建一个新的和空的句柄表,就像它为任何新进程创建句柄表那样。不过,由于将TRUE传递给了CreateProcess的bInheritHandle参数,因此系统要进行另一项操作,即它要遍历父进程的句柄表,对于它找到的包含有效的可继承句柄的每个项目,系统会将该项目准确地拷贝到子进程的句柄表中。该项目拷贝到子进程的句柄表中的位置将与父进程的句柄表中的位置完全相同。这个情况非常重要,因为它意味着在父进程与子进程中,标识内核对象所用的句柄值是相同的。


除了拷贝句柄表项目外,系统还要递增内核对象的使用计数,因为现在两个进程都使用该对象。如果要撤消内核对象,那么父进程和子进程必须调用该对象上的CloseHandle 函数,也可以终止进程的运行。子进程不必首先终止运行,但是父进程也不必首先终止运行。实际上,CreateProcess函数返回后,父进程可以立即关闭对象的句柄,而不影响子进程对该对象进行操作的能力。

3.3.2 改变句柄的标志
有时会遇到这样一种情况,父进程创建一个内核对象,以便检索可继承的句柄,然后生成两个子进程。父进程只想要一个子进程来继承内核对象的句柄。换句话说,有时可能想要控制哪个子进程来继承内核对象的句柄。若要改变内核对象句柄的继承标志,可以调用SetHandleInformation函数.

你可能感兴趣的:(Windows核心编程)