深入探讨.NET中的钩子技术[5]
应用程序X继续执行 例如CBT钩子(window创建 等等 )的钩子类型并不切换上下文 对于这些类型的钩子 过程大致如下 应用程序X拥有焦点并执行 应用程序X创建一个窗口 Windows用在应用程序X进程空间中的CBT事件消息参数调用钩子回调函数 应用程序X继续执行 这应该说明了为什么某种类型的钩子能够用这个库结构工作而一些却不能 记住 这正是该库要做的 在上面第 步和第 步之后 分别插入下列步骤 Windows调用钩子回调函数 目标回调函数在非托管的DLL中执行 目标回调函数查找它的相应托管的调用代理 托管代理被以适当的参数执行 目标回调函数返回并执行相应于指定消息的钩子处理 第三步和第四步因非切换钩子类型而注定失败 第三步将失败 因为相应的托管回调函数不会为该应用程序而设置 记住 这个DLL使用全局变量来跟踪这些托管代理并且该钩子DLL被加载到每一个进程空间 但是这个值仅在放钩子的应用程序进程空间中设置 对于另外其它情况 它们全部为null Tim Sylvester在他的《Other hook types》一文中指出 使用一个共享内存区段将会解决这个问题 这是真实的 但是也如Tim所指出的 那些托管代理地址对于除了放钩子的应用程序之外的任何进程是无意义的 这意味着 它们是无意义的并且不能在回调函数的执行过程中调用 那样会有麻烦的 因此 为了把这些回调函数使用于不执行上下文切换的钩子类型 你需要某种进程间的通讯 我已经试验过这种思想 使用非托管的DLL钩子回调函数中的进程外对象进行IPC 如果你能使这种方法工作 我将很高兴了解到这点 至于我的尝试 结果并不理想 基本原因是很难针对各种进程和它们的线程(CoInitialize(NULL))而正确地初始化单元 这是一个在你可以使用对象之前的基本要求 我不怀疑 一定有办法来解决这个问题 但是我还没有试用过它们 因为我认为它们仅有有限的用处 例如 CBT钩子可以让你取消一个窗口创建 如果你希望的话 可以想像 为使这能够工作将会发生什么 钩子回调函数开始执行 调用非托管的钩子DLL中的相应的钩子回调函数 执行必须被路由回到主钩子应用程序 该应用程序必须决定是否允许这一创建 调用必须被路由回仍旧在运行中的钩子回调函数 在非托管的钩子DLL中的钩子回调函数从主钩子应用程序接收到要采取的行动 在非托管的钩子DLL中的钩子回调函数针对CBT钩子调用采取适当的行动 完成钩子回调函数的执行 这不是不可能的 但是不算好的 我希望这会消除在该库中的围绕被允许的和受限制的钩子类型所带来的神秘 七 其它 ◆库文档 我们已经包含了有关ManagedHooks类库的比较完整的代码文档 当以 Documentation 构建配置进行编译时 这被经由Visual Studio NET转换成标准帮助XML 最后 我们已使用NDoc来把它转换成编译的HTML帮助(CHM) 你可以看这个帮助文件 只需简单地在该方案的解决方案资源管理器中点击Hooks chm文件或通过查找与该文相关的可下载的ZIP文件 ◆增强的智能感知 如果你不熟悉Visual Studio NET怎样使用编译的XML文件(pre NDoc output)来为参考库的工程增强智能感知 那么让我简单地介绍一下 如果你决定在你的应用程序中使用这个类库 你可以考虑复制该库的一个稳定构建版本到你想参考它的位置 同时 还要把XML文档文(SystemHooks\ManagedHooks\bin\Debug\Kennedy ManagedHooks xml)复制到相同的位置 当你添加一个参考到该库时 Visual Studio NET将自动地读该文件并使用它来添加智能感知文档 这是很有用的 特别是对于象这样的第三方库 ◆单元测试 我相信 所有的库都应有与之相应的单元测试 既然我是一家公司(主要负责针对 NET环境软件的单元测试)的合伙人和软件工程师 任何人不会对此感到惊讶 因而 你将会在名为ManagedHooksTests的解决方案中找到一个单元测试工程 为了运行该单元测试 你需要下载和安装HarnessIt 这个下载是我们的商业单元测试软件的一个自由的试用版本 在该单元测试中 我对这给予了特殊的注意 在此处 方法的无效参数可能导致C++内存异常的发生 尽管这个库是相当简单的 但该单元测试确实能够帮助我在一些更为微妙的情况下发现一些错误 ◆非托管的/托管的调试 有关混合解决方案(例如 本文的托管的和非托管的代码)最为技巧的地方之一是调试问题 如果你想单步调试该C++代码或在C++代码中设置断点 你必须启动非托管的调试 这是一个Visual Studio NET中的工程设置 注意 你可以非常顺利地单步调试托管的和非托管的层 但是 在调试过程中 非托管的调试确实严重地减慢应用程序的装载时间和执行速度 八 最后警告 很明显 系统钩子相当有力量 然而 使用这种力量应该是有责任性的 在系统钩子出了问题时 它们不仅仅垮掉你的应用程序 它们可以垮掉在你的当前系统中运行的每个应用程序 但是到这种程度的可能性一般是很小的 尽管如此 在使用系统钩子时 你还是需要再三检查你的代码 我发现了一项可以用来开发应用程序的有用的技术 它使用系统钩子来在微软的虚拟PC上安装你的喜爱的开发操作系统的一个拷贝和Visual Studio NET 然后 你就可以在此虚拟的环境中开发你的应用程序 用这种方式 当你的钩子应用程序出现错误时 它们将仅退出你的操作系统的虚拟实例而不是你的真正的操作系统 我已经不得不重启动我的真正的OS 在这个虚拟OS由于一个钩子错误崩溃时 但是这并不经常 注意 如果你在网上订阅了一个MSDN 那么在你整个订阅过程中你可以自由使用虚拟PC lishixinzhi/Article/program/net/201311/15481
深入探讨.NET中的钩子技术[2]
三 使用代码 在我们深入开发这个库之前 让我们快速看一下我们的目标 在本文中 我们将开发一个类库 它安装全局系统钩子并且暴露这些由钩子处理的事件 作为我们的钩子类的一个 NET事件 为了说明这个系统钩子类的用法 我们将在一个用C#编写的Windows表单应用程序中创建一个鼠标事件钩子和一个键盘事件钩子 这些类库能用于创建任何类型的系统钩子 其中有两个预编译的钩子 MouseHook和KeyboardHook 我们也已经包含了这些类的特定版本 分别称为MouseHookExt和KeyboardHookExt 根据这些类所设置的模型 你能容易构建系统钩子 针对Win API中任何 种钩子事件类型中的任何一种 另外 这个完整的类库中还有一个编译的HTML帮助文件 它把这些类归档化 请确信你看了这个帮助文件 如果你决定在你的应用程序中使用这个库的话 MouseHook类的用法和生命周期相当简单 首先 我们创建MouseHook类的一个实例 mouseHook = new MouseHook();//mouseHook是一个成员变量 接下来 我们把MouseEvent事件绑定到一个类层次的方法上 mouseHook MouseEvent+=new MouseHook MouseEventHandler(mouseHook_MouseEvent);// private void mouseHook_MouseEvent(MouseEvents mEvent int x int y){ string msg =string Format( 鼠标事件:{ }:({ } { }) mEvent ToString() x y); AddText(msg);//增加消息到文本框} 为开始收到鼠标事件 简单地安装下面的钩子即可 mouseHook InstallHook(); 为停止接收事件 只需简单地卸载这个钩子 mouseHook UninstallHook(); 你也可以调用Dispose来卸载这个钩子 在你的应用程序退出时 卸载这个钩子是很重要的 让系统钩子一直安装着将减慢系统中的所有的应用程序的消息处理 它甚至能够使一个或多个进程变得很不稳定 因此 请确保在你使用完钩子时一定要移去你的系统钩子 我们确定在我们的示例应用程序会移去该系统钩子 通过在Form的Dispose方法中添加一个Dispose调用 protected override void Dispose(bool disposing) { if (disposing) {if (mouseHook != null) { mouseHook Dispose(); mouseHook = null;}// }} 使用该类库的情况就是如此 该类库中有两个系统钩子类并且相当容易扩充 四 构建库 这个库共有两个主要组件 第一部分是一个C#类库 你可以直接使用于你的应用程序中 该类库 反过来 在内部使用一个非托管的C++ DLL来直接管理系统钩子 我们将首先讨论开发该C++部分 接下来 我们将讨论怎么在C#中使用这个库来构建一个通用的钩子类 就象我们讨论C++/C#交互一样 我们将特别注意C++方法和数据类型是怎样映射到 NET方法和数据类型的 你可能想知道为什么我们需要两个库 特别是一个非托管的C++ DLL 你还可能注意到在本文的背景一节中提到的两篇参考文章 其中并没有使用任何非托管的代码 为此 我的回答是 对!这正是我写这篇文章的原因 当你思考系统钩子是怎样实际地实现它们的功能时 我们需要非托管的代码是十分重要的 为了使一个全局的系统钩子能够工作 Windows把你的DLL插入到每个正在运行的进程的进程空间中 既然大多数进程不是 NET进程 所以 它们不能直接执行 NET装配集 我们需要一种非托管的代码代理 Windows可以把它插入到所有将要被钩住的进程中 首先是提供一种机制来把一个 NET代理传递到我们的C++库 这样 我们用C++语言定义下列函数(SetUserHookCallback)和函数指针(HookProc) int SetUserHookCallback(HookProc userProc UINT hookID)typedef void (CALLBACK *HookProc)(int code WPARAM w LPARAM l) SetUserHookCallback的第二个参数是钩子类型 这个函数指针将使用它 现在 我们必须用C#来定义相应的方法和代理以使用这段代码 下面是我们怎样把它映射到C# private static extern SetCallBackResults SetUserHookCallback(HookProcessedHandler hookCallback HookTypes hookType)protected delegate void HookProcessedHandler(int code UIntPtr wparam IntPtr lparam)public enum HookTypes { JournalRecord = JournalPlayback = // KeyboardLL = MouseLL = }; lishixinzhi/Article/program/net/201311/15484
深入探讨.NET中的钩子技术
一 介绍 本文将讨论在 NET应用程序中全局系统钩子的使用 为此 我开发了一个可重用的类库并创建一个相应的示例程序(见下图) 你可能注意到另外的关于使用系统钩子的文章 本文与之类似但是有重要的差别 这篇文章将讨论在 NET中使用全局系统钩子 而其它文章仅讨论本地系统钩子 这些思想是类似的 但是实现要求是不同的 二 背景 如果你对Windows系统钩子的概念不熟悉 让我作一下简短的描述 ·一个系统钩子允许你插入一个回调函数 它拦截某些Windows消息(例如 鼠标相联系的消息) ·一个本地系统钩子是一个系统钩子 它仅在指定的消息由一个单一线程处理时被调用 ·一个全局系统钩子是一个系统钩子 它当指定的消息被任何应用程序在整个系统上所处理时被调用 已有若干好文章来介绍系统钩子概念 在此 不是为了重新收集这些介绍性的信息 我只是简单地请读者参考下面有关系统钩子的一些背景资料文章 如果你对系统钩子概念很熟悉 那么你能够从本文中得到你能够得到的任何东西 ·关于MSDN库中的钩子知识 ·Dino Esposito的《Cutting Edge Windows Hooks in the NET Framework》 ·Don Kackman的《在C#中应用钩子》 本文中我们要讨论的是扩展这个信息来创建一个全局系统钩子 它能被 NET类所使用 我们将用C#和一个DLL和非托管C++来开发一个类库 它们一起将完成这个目标 三 使用代码 在我们深入开发这个库之前 让我们快速看一下我们的目标 在本文中 我们将开发一个类库 它安装全局系统钩子并且暴露这些由钩子处理的事件 作为我们的钩子类的一个 NET事件 为了说明这个系统钩子类的用法 我们将在一个用C#编写的Windows表单应用程序中创建一个鼠标事件钩子和一个键盘事件钩子 这些类库能用于创建任何类型的系统钩子 其中有两个预编译的钩子 MouseHook和KeyboardHook 我们也已经包含了这些类的特定版本 分别称为MouseHookExt和KeyboardHookExt 根据这些类所设置的模型 你能容易构建系统钩子 针对Win API中任何 种钩子事件类型中的任何一种 另外 这个完整的类库中还有一个编译的HTML帮助文件 它把这些类归档化 请确信你看了这个帮助文件 如果你决定在你的应用程序中使用这个库的话 MouseHook类的用法和生命周期相当简单 首先 我们创建MouseHook类的一个实例 mouseHook = new MouseHook();//mouseHook是一个成员变量 接下来 我们把MouseEvent事件绑定到一个类层次的方法上 mouseHook MouseEvent+=new MouseHook MouseEventHandler(mouseHook_MouseEvent); // private void mouseHook_MouseEvent(MouseEvents mEvent int x int y){ string msg =string Format( 鼠标事件:{ }:({ } { }) mEvent ToString() x y); AddText(msg);//增加消息到文本框 } 为开始收到鼠标事件 简单地安装下面的钩子即可 mouseHook InstallHook(); 为停止接收事件 只需简单地卸载这个钩子 mouseHook UninstallHook(); 你也可以调用Dispose来卸载这个钩子 在你的应用程序退出时 卸载这个钩子是很重要的 让系统钩子一直安装着将减慢系统中的所有的应用程序的消息处理 它甚至能够使一个或多个进程变得很不稳定 因此 请确保在你使用完钩子时一定要移去你的系统钩子 我们确定在我们的示例应用程序会移去该系统钩子 通过在Form的Dispose方法中添加一个Dispose调用 protected override void Dispose(bool disposing) { if (disposing) { if (mouseHook != null) { mouseHook Dispose(); mouseHook = null; } // } } 使用该类库的情况就是如此 该类库中有两个系统钩子类并且相当容易扩充 四 构建库 这个库共有两个主要组件 第一部分是一个C#类库 你可以直接使用于你的应用程序中 该类库 反过来 在内部使用一个非托管的C++ DLL来直接管理系统钩子 我们将首先讨论开发该C++部分 接下来 我们将讨论怎么在C#中使用这个库来构建一个通用的钩子类 就象我们讨论C++/C#交互一样 我们将特别注意C++方法和数据类型是怎样映射到 NET方法和数据类型的 你可能想知道为什么我们需要两个库 特别是一个非托管的C++ DLL 你还可能注意到在本文的背景一节中提到的两篇参考文章 其中并没有使用任何非托管的代码 为此 我的回答是 对!这正是我写这篇文章的原因 当你思考系统钩子是怎样实际地实现它们的功能时 我们需要非托管的代码是十分重要的 为了使一个全局的系统钩子能够工作 Windows把你的DLL插入到每个正在运行的进程的进程空间中 既然大多数进程不是 NET进程 所以 它们不能直接执行 NET装配集 我们需要一种非托管的代码代理 Windows可以把它插入到所有将要被钩住的进程中 首先是提供一种机制来把一个 NET代理传递到我们的C++库 这样 我们用C++语言定义下列函数(SetUserHookCallback)和函数指针(HookProc) int SetUserHookCallback(HookProc userProc UINT hookID) typedef void (CALLBACK *HookProc)(int code WPARAM w LPARAM l) SetUserHookCallback的第二个参数是钩子类型 这个函数指针将使用它 现在 我们必须用C#来定义相应的方法和代理以使用这段代码 下面是我们怎样把它映射到C# private static extern SetCallBackResults SetUserHookCallback(HookProcessedHandler hookCallback HookTypes hookType) protected delegate void HookProcessedHandler(int code UIntPtr wparam IntPtr lparam) public enum HookTypes { JournalRecord = JournalPlayback = // KeyboardLL = MouseLL = }; 首先 我们使用DllImport属性导入SetUserHookCallback函数 作为我们的抽象基钩子类SystemHook的一个静态的外部的方法 为此 我们必须映射一些外部数据类型 首先 我们必须创建一个代理作为我们的函数指针 这是通过定义上面的HookProcessHandler来实现的 我们需要一个函数 它的C++签名为(int WPARAM LPARAM) 在Visual Studio NET C++编译器中 int与C#中是一样的 也就是说 在C++与C#中int就是Int 事情并不总是这样 一些编译器把C++ int作为Int 对待 我们坚持使用Visual Studio NET C++编译器来实现这个工程 因此 我们不必担心编译器差别所带来的另外的定义 接下来 我们需要用C#传递WPARAM和LPARAM值 这些确实是指针 它们分别指向C++的UINT和LONG值 用C#来说 它们是指向uint和int的指针 如果你还不确定什么是WPARAM 你可以通过在C++代码中单击右键来查询它 并且选择 Go to definition 这将会引导你到在windef h中的定义 //从windef h: typedef UINT_PTR WPARAM; typedef LONG_PTR LPARAM; 因此 我们选择System UIntPtr和System IntPtr作为我们的变量类型 它们分别相应于WPARAM和LPARAM类型 当它们使用在C#中时 现在 让我们看一下钩子基类是怎样使用这些导入的方法来传递一个回叫函数(代理)到C++中 它允许C++库直接调用你的系统钩子类的实例 首先 在构造器中 SystemHook类创建一个到私有方法InternalHookCallback的代理 它匹配HookProcessedHandler代理签名 然后 它把这个代理和它的HookType传递到C++库以使用SetUserHookCallback方法来注册该回叫函数 如上面所讨论的 下面是其代码实现 public SystemHook(HookTypes type){ _type = type; _processHandler = new HookProcessedHandler(InternalHookCallback); SetUserHookCallback(_processHandler _type); } InternalHookCallback的实现相当简单 InternalHookCallback在用一个catch all try/catch块包装它的同时仅传递到抽象方法HookCallback的调用 这将简化在派生类中的实现并且保护C++代码 记住 一旦一切都准备妥当 这个C++钩子就会直接调用这个方法 [MethodImpl(MethodImplOptions NoInlining)] private void InternalHookCallback(int code UIntPtr wparam IntPtr lparam){ try { HookCallback(code wparam lparam); } catch {} } 我们已增加了一个方法实现属性 它告诉编译器不要内联这个方法 这不是可选的 至少 在我添加try/catch之前是需要的 看起来 由于某些原因 编译器在试图内联这个方法 这将给包装它的代理带来各种麻烦 然后 C++层将回叫 而该应用程序将会崩溃 现在 让我们看一下一个派生类是怎样用一个特定的HookType来接收和处理钩子事件 下面是虚拟的MouseHook类的HookCallback方法实现 protected override void HookCallback(int code UIntPtr wparam IntPtr lparam){ if (MouseEvent == null) { return; } int x = y = ; MouseEvents mEvent = (MouseEvents)wparam ToUInt (); switch(mEvent) { case MouseEvents LeftButtonDown: GetMousePosition(wparam lparam ref x ref y); break; // } MouseEvent(mEvent new Point(x y)); } 首先 注意这个类定义一个事件MouseEvent 该类在收到一个钩子事件时激发这个事件 这个类在激发它的事件之前 把数据从WPARAM和LPARAM类型转换成 NET中有意义的鼠标事件数据 这样可以使得类的消费者免于担心解释这些数据结构 这个类使用导入的GetMousePosition函数 我们在C++ DLL中定义的用来转换这些值 为此 请看下面几段的讨论 在这个方法中 我们检查是否有人在听这一个事件 如果没有 不必继续处理这一事件 然后 我们把WPARAM转换成一个MouseEvents枚举类型 我们已小心地构造了MouseEvents枚举来准确匹配它们在C++中相应的常数 这允许我们简单地把指针的值转换成枚举类型 但是要注意 这种转换即使在WPARAM的值不匹配一个枚举值的情况下也会成功 mEvent的值将仅是未定义的(不是null 只是不在枚举值范围之内) 为此 请详细分析System Enum IsDefined方法 接下来 在确定我们收到的事件类型后 该类激活这个事件 并且通知消费者鼠标事件的类型及在该事件过程中鼠标的位置 最后注意 有关转换WPARAM和LPARAM值 对于每个类型的事件 这些变量的值和意思是不同的 因此 在每一种钩子类型中 我们必须区别地解释这些值 我选择用C++实现这种转换 而不是尽量用C#来模仿复杂的C++结构和指针 例如 前面的类就使用了一个叫作GetMousePosition的C++函数 下面是C++ DLL中的这个方法 bool GetMousePosition(WPARAM wparam LPARAM lparam int & x int & y) { MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lparam; x = pMouseStruct >pt x; y = pMouseStruct >pt y; return true; } 不是尽量映射MOUSEHOOKSTRUCT结构指针到C# 我们简单地暂时把它回传到C++层以提取我们需要的值 注意 因为我们需要从这个调用中返回一些值 我们把我们的整数作为参考变量传递 这直接映射到C#中的int* 但是 我们可以重载这个行为 通过选择正确的签名来导入这个方法 private static extern bool InternalGetMousePosition(UIntPtr wparam IntPtr lparam ref int x ref int y) 通过把integer参数定义为ref int 我们得到通过C++参照传递给我们的值 如果我们想要的话 我们还可以使用out int lishixinzhi/Article/program/net/201311/11904
→ dos是什么?怎么进入dos模式
DOS是DiskOperationSystem(磁盘操作系统)的简称。是一个基于磁盘管理的操作系统,它是命令行形式的,靠输入命令的形式把指令传给计算机,让计算机实现操作的,来进行人机对话。对于WIN98系统及之前的windows操作系统都是基于DOS基础上开发的,可以进入DOS,方法是:开机按F8选5就能进然后打WIN加回车就可以进入系统,或者在系统里[开始]中进入MS-DOS然后输入EXIT就可以回来。而对于如2000和XP的没有纯DOS,所以常规方法是不允许WindowsXP进入DOS状态的,但是WindowsXP有一个支持仿DOS命令行的环境——MS-DOS,在其中可以运行大部分的DOS命令,甚至许多DOS下的游戏软件也可以运行。对于那些不能进入DOS的系统,若要进入,可以按下面的方式安装DOS:一、有的系统盘光盘上的工具里面带有DOS程序,可以通过系统光盘进入系统了。开机时按下delete键,就可以进入BOIBOS,在AdvancedBIOSFeatures——FirstBootDrive——CDROM.这样你就可以通过系统盘启动电脑了。然后用光标移动到DOS程序所在位置,按enter键就可以了。二、如果没有光盘或者光盘上没有DOS的话。可以下一个DOS系统,然后安装好,重启系统。在启动时电脑会让选择启动的系统,选择DOS就行了。
什么是DOS?怎么样才能进入纯dos系统呢? 希望能在2014-05-21 16-05之前解答
(一)DOS是什么?有什么用?
我们使用电脑接触最频繁的就是DOS。DOS是英文Disk Operating System的缩写,意思是“磁盘操作系统”,顾名思义,DOS主要是一种面向磁盘的系统软件,说得简单些,DOS就是人与机器的一座桥梁,是罩在机器硬件外面的一层“外壳”,有了DOS,我们就不必去深入了解机器的硬件结构,也不必与死记硬背那些枯燥的机器命令,只需通过一些接近于自然语言的DOS命令,我们就可以轻松地完成绝大多数的日常操作。另外,DOS还能有效地管理各种软硬件资源,对它们进行合理的调度,所有的软件和硬件都在DOS的监控和管理之下,有条不紊地进行着自己的工作。
(二)MS-DOS与PC-DOS
在使用DOS时,我们还会经常听到MS-DOS和PC-DOS,对初学者来说,可以认为二者没有大的区别。事实上,MS-DOS由世界软件大王--Microsoft(微软公司)出品,而PC-DOS则由世界电脑大王--IBM(国际商务机器公司)对MS-DOS略加改动而推出。由于微软在世界软件业的垄断性优势,所以其产品MS-DOS已成为主流操作系统,至于PC-DOS,虽然在功能上不见得逊于MS-DOS,无奈MS-DOS先入为主,PC-DOS纵然使出浑身解数,却也始终不能动摇MS-DOS分毫。
(三)DOS的版本
DOS在1981年推出其1.0版,功能还非常基本和薄弱;1983年推出2.0,主要增加了目录操作功能,使文件管理上了一个新台阶(目录和文件的概念我们将在讲解DOS内部命令时介绍);1984年推出3.0,主要支持1.2MB的5.25英寸高密软盘(1.X和2.X只支持低密盘)和大容量硬盘;1987推出目前普及率最高的DOS 3.3,主要支持3.5英寸软盘和网络。至此,DOS已经发展的相当成熟,尽管后续版本(目前PC-DOS的最新版本为7.0版,MS-DOS公布的最新版本为6.22)不断推出,但均无重大的内核改进,只不过增加了许多实用功能,如检测磁盘,清除病毒,硬盘增容等。
(四)学好DOS的意义
可以说,DOS 3.3是个非常重要的划时代版本,认真学好3.3,一方面可以增强实际操作能力,另一方面也为更好、更快地过渡到新版本打下坚实的基础。因此,本文主要以MS-DOS 3.3为主讲解,适当提及新版本中功能增强的部分。
尽管目前Windows如日中天,大有取代DOS的趋势,而且DOS的生产商微软也停止了MS-DOS的进一步开发,而全面向Windows一体化的方向发展。但是,DOS仍不可否认地是当前的主流操作系统(特别是在我国)。
本节重点内容回顾:DOS的作用,MS-DOS与PC-DOS,DOS的版本,学好DOS的重要性认清了学习DOS的重要性,下面,我们就来正式开始学习DOS,先从最基本的DOS启动讲起。
二、DOS的启动
1、什么是文件?
我们把存放在磁盘或光盘上的有完整意义的一部分数据就称为文件。数据的意义是广泛的,我们编写的程序、拷贝的软件、制作的图象等,都可以称之为数据,而数据则是以文件的形式储存在磁盘上的。对于文件,我们可以进行建立、修改、删除、复制、移动等多种操作。
有了文件自然要加以管理,给文件起名字是最好的方法。每个文件都有一个名字,称为文件名,它由字母、数字或字符组成,如COMMAND.COM。文件名又可分割为主文件名和扩展文件湍肃OMMAND.COM为例,COMMAND就是主文件名,它主要说明文件的内容,COM为扩展文件名,它主要说明文件的性质(在这里COM表示命令文件),中间的小数点为主文件名和扩展文件名的分隔符。DOS规定主文件名不能超过8个字符,扩展文件名不能超过3个字符。由于小数点专用作分隔符,所以主文件名和扩展文件名中不能使用小数点。另外,在文件名中也不允许使用空格。扩展文件名是可以省略的,但主文件名一定要有。所以,以下文件名都是错误的,如.EXE(无主文件名),ABC.BCD.COM(主文件名中含有小数点),ABC.DEFG(扩展文件名超过3个字符)。
在DOS中,规定了三种扩展名为可执行文件,即EXE、COM和BAT。所谓可执行文件,就是在DOS下直接键入主文件名就可以执行程序的文件。除EXE、COM和BAT之外,其他所有文件都不能在DOS下直接执行,称为非执行文件。
2、DOS的构成
DOS主要由三个基本文件和一些外部命令构成,外部命令的概念我们将在以后介绍,这里主要说明三个基本文件(又称为系统文件)。这三个基本文件是MSDOS.SYS,IO.SYS和COMMAND.COM(如果是PC-DOS,则为IBMDOS.COM,IBMBIO.COM和COMMAND.COM)。其中MSDOS.SYS称为DOS内核(可见MSDOS.SYS是个非常重要的文件),它主要是用来管理和启动系统的各个部件,为DOS的引导作好准备工作。IO.SYS(IO为Input&Output的缩写,意即“输入输出”)主要负责系统的基本输入和输出,即DOS与各部件之间的联系。COMMAND.COM文件(COMMAND是“命令”的意思)是DOS与用户的接口,它主要提供了一些DOS的内部命令,并能接受、判别并执行用户输入的命令。磁盘是否具有启动DOS的能力,就看是否具有这三个文件,具有这三个文件的磁盘,就称作引导盘。而除此之外还包含许多DOS外部命令的磁盘则称为系统盘。
最后要注意的是,MSDOS.SYS和IO.SYS两个文件的存储位置是有限制的,它们必须位于磁盘物理位置的最前面,否则将失去引导能力。
(一)什么是DOS的启动
我们每次使用电脑,都必须启动DOS,(又称为引导),否则我们就无法操作电脑。我们打开电脑电源后,电脑首先进行自检,然后,如果是从软盘启动,软驱在嗡嗡作响十几秒后,就会出现A>或A:\>;如果从硬盘启动,那速度要快得多,很快就会出现C>或C:\>。A>、A:\>、C>、C:\>称为DOS提示符(DOS提示符并不是一成不变的,有关DOS提示符的改变,我们将在讲解内部命令PROMPT时详细介绍),它的出现表明DOS已经顺利地完成了引导过程,各种软硬件资源已在监控之下,用户可以开始输入命令了。
(二)启动前的准备工作
既然启动的是DOS,当然磁盘要具有引导的能力(即具有三个系统文件)。如果要从软盘启动,就要有一张DOS引导盘或系统盘,并插入软驱(一定要插入A驱,不同的电脑A驱的位置可能有所不同,事先必须弄清楚),作好启动准备。如果要从硬盘启动,只要使硬盘可以引导就行了。
(三)启动的分类
DOS的启动又可分为冷启动和热启动。冷启动是指切断电脑电源后重新开启电源启动的过程。热启动是指在没有切断电源(即开机)的情况下重新启动的过程。冷启动后机器要首先进行硬件的自检(不同的机器可能自检时间不同,这主要取决于各个部件的配置情况,如内存的多少等),以确定各个部件是否工作正常,如果自检顺利通过,则进入DOS启动状态。热启动则没有机器自检这一过程,这就是二者的主要区别。因此热启动的速度显然要比冷启动快。由于热启动没有切断电脑各部件的电源,因此能有效地延长硬件的寿命,在没有特殊情况(如电脑受到病毒侵袭、某些软件在运行过程中死机并封锁键盘等)的时候,应尽量使用热启动。
冷启动的方法主要是关闭电源,即关机。不过目前绝大多数组装机(或称为兼容机)在机箱上都有一个RESET(意即“重新启动”)按钮,它的主要目的就是简化冷启动,通常在冷启动时应尽量使用RESET钮,它在启动时对机器的冲击比关机(即按POWER钮)小一些,所以有助于延长电脑的使用寿命。要注意,原装机(或称为品牌机),特别是进口机,几乎都没有RESET键(RESET可以说是组装机的“专利”),此时要想冷启动就只有关闭电源了。要注意,如果使用关闭电源的方法进行冷启动,一定要关闭后至少间隔8秒至10秒后再开机,以免由于间隔时间过短损坏部件。 热启动则没有。
钓钩的网络解释钓钩的网络解释是什么
钓钩的网络解释是:钓钩钓钩即钓鱼的钩儿,是渔具中最重要的,没有钓钩钓鱼就无从谈起。钓钩主要由钩尖、倒刺、钩身和钩柄组成。钓钩种类很多,垂钓者可以针对不同的鱼类及大小、不同的水域、不同的垂钓方法选择不同类型的钓钩,从而提高垂钓效果。引申也比喻引诱人的圈套。青铜钓钩继新石器时代的骨制钓钩之后出现的钓鱼工具。河南郑州二里冈商代前期遗址中出土的几件钓钩,长约4厘米,弯度接近直角。钓钩的网络解释是:钓钩钓钩即钓鱼的钩儿,是渔具中最重要的,没有钓钩钓鱼就无从谈起。钓钩主要由钩尖、倒刺、钩身和钩柄组成。钓钩种类很多,垂钓者可以针对不同的鱼类及大小、不同的水域、不同的垂钓方法选择不同类型的钓钩,从而提高垂钓效果。引申也比喻引诱人的圈套。青铜钓钩继新石器时代的骨制钓钩之后出现的钓鱼工具。河南郑州二里冈商代前期遗址中出土的几件钓钩,长约4厘米,弯度接近直角。词性是:名词。结构是:钓(左右结构)钩(左右结构)。注音是:ㄉ一ㄠ_ㄍㄡ。拼音是:diàogōu。钓钩的具体解释是什么呢,我们通过以下几个方面为您介绍:一、词语解释【点此查看计划详细内容】钓钩diàogōu。(1)钓鱼钩,比喻引诱人的圈套。二、引证解释⒈亦作“钓_”。钓鱼的钩儿。引《乐府诗集·相和歌辞三·乌生》:“鲤鱼乃在洛水深渊中,钓钩尚得鲤鱼口。”唐权德舆《渭水》诗:“吕叟年八十,皤然持钓_。”唐杜甫《江村》诗:“老妻画纸为棋局,稚子敲针作钓钩。”⒉比喻引诱人的圈套。引毛泽东《和英国记者贝特兰的谈话·在抗日战争中的八路军》:“危险是在中国居然有些动摇分子正在准备去上敌人的钓钩。”三、国语词典用来钓鱼的钓针。关于钓钩的诗词《长安即事·抛掷清溪旧钓钩》《寄裴生乞钓钩》《过钓钩岭悼亡友盛景韩》关于钓钩的诗句稚子敲针作钓钩轻动风涟下钓钩千古高风一钓钩关于钓钩的成语窃钩窃国钩深图远钩深致远提要钩玄探赜钩深钩元提要钩玄猎秘钩章棘句钩心斗角银钩虿尾关于钓钩的词语提要钩玄银钩虿尾钩深致远钓鳌客钩玄猎秘钩深图远探赜钩深钩元提要钩心斗角研精钩深关于钓钩的造句1、她知道如何把饵装在钓钩上来为女儿们吸引丈夫。2、老人把钓钩从鱼嘴里拔出来,重新安上一条沙丁鱼作饵,把它甩进海里。3、娇妻画纸为棋局,稚子敲针作钓钩。4、明天在向你招手,周末在向你点头,一周的疲乏抛之脑后,轻松的周末细细备筹,邀上三五好友,喝上二两美酒,白天闲垂钓钩,晚上麻将牌九,晴天踏青玩游,雨天网上闲休。。周末的生活实在是美不胜收!周五快乐!5、能生产各类大小规格的海钓钩及淡水鱼钩。点此查看更多关于钓钩的详细信息
钩_的网络解释钩_的网络解释是什么
钩_的网络解释是:钩_钩_是一个汉语词汇,拼音是gōuguà,解释是钩挂。钩_的网络解释是:钩_钩_是一个汉语词汇,拼音是gōuguà,解释是钩挂。结构是:钩(左右结构)_(上下结构)。注音是:ㄍㄡㄍㄨㄚ_。拼音是:gōuguà。钩_的具体解释是什么呢,我们通过以下几个方面为您介绍:一、词语解释【点此查看计划详细内容】1.钩挂。二、引证解释⒈钩挂。参见“__”。引明宋濂《报恩说》:“爱如枳棘,丛生道傍,能__一切。”关于钩_的成语钩章棘句钩深致远银钩虿尾钩金舆羽钩深索隐钩_格磔钩元摘秘盗玉窃钩探赜钩深窃钩窃国关于钩_的词语探赜钩深研精钩深钩元摘秘钩元提要钩玄猎秘钩深致远钩深索隐银钩虿尾盗玉窃钩钩_格磔点此查看更多关于钩_的详细信息
系统钩子是什么??
一、 介绍
本文将讨论在.NET应用程序中全局系统钩子的使用。为此,我开发了一个可重用的类库并创建一个相应的示例程序(见下图)。
你可能注意到另外的关于使用系统钩子的文章。本文与之类似但是有重要的差别。这篇文章将讨论在.NET中使用全局系统钩子,而其它文章仅讨论本地系统钩子。这些思想是类似的,但是实现要求是不同的。
二、 背景
如果你对Windows系统钩子的概念不熟悉,让我作一下简短的描述:
・一个系统钩子允许你插入一个回调函数-它拦截某些Windows消息(例如,鼠标相联系的消息)。
・一个本地系统钩子是一个系统钩子-它仅在指定的消息由一个单一线程处理时被调用。
・一个全局系统钩子是一个系统钩子-它当指定的消息被任何应用程序在整个系统上所处理时被调用。
已有若干好文章来介绍系统钩子概念。在此,不是为了重新收集这些介绍性的信息,我只是简单地请读者参考下面有关系统钩子的一些背景资料文章。如果你对系统钩子概念很熟悉,那么你能够从本文中得到你能够得到的任何东西。
・关于MSDN库中的钩子知识。
・Dino Esposito的《Cutting Edge-Windows Hooks in the .NET Framework》。
・Don Kackman的《在C#中应用钩子》。
本文中我们要讨论的是扩展这个信息来创建一个全局系统钩子-它能被.NET类所使用。我们将用C#和一个DLL和非托管C++来开发一个类库-它们一起将完成这个目标。
三、 使用代码
在我们深入开发这个库之前,让我们快速看一下我们的目标。在本文中,我们将开发一个类库-它安装全局系统钩子并且暴露这些由钩子处理的事件,作为我们的钩子类的一个.NET事件。为了说明这个系统钩子类的用法,我们将在一个用C#编写的Windows表单应用程序中创建一个鼠标事件钩子和一个键盘事件钩子。
这些类库能用于创建任何类型的系统钩子,其中有两个预编译的钩子-MouseHook和KeyboardHook。我们也已经包含了这些类的特定版本,分别称为MouseHookExt和KeyboardHookExt。根据这些类所设置的模型,你能容易构建系统钩子-针对Win32 API中任何15种钩子事件类型中的任何一种。另外,这个完整的类库中还有一个编译的HTML帮助文件-它把这些类归档化。请确信你看了这个帮助文件-如果你决定在你的应用程序中使用这个库的话。
MouseHook类的用法和生命周期相当简单。首先,我们创建MouseHook类的一个实例。
mouseHook = new MouseHook();//mouseHook是一个成员变量
接下来,我们把MouseEvent事件绑定到一个类层次的方法上。
mouseHook.MouseEvent+=new MouseHook.MouseEventHandler(mouseHook_MouseEvent);
// ...
private void mouseHook_MouseEvent(MouseEvents mEvent, int x, int y){
string msg =string.Format("鼠标事件:{0}:({1},{2}).",mEvent.ToString(),x,y);
AddText(msg);//增加消息到文本框
}
为开始收到鼠标事件,简单地安装下面的钩子即可。
mouseHook.InstallHook();
为停止接收事件,只需简单地卸载这个钩子。
mouseHook.UninstallHook();
你也可以调用Dispose来卸载这个钩子。
在你的应用程序退出时,卸载这个钩子是很重要的。让系统钩子一直安装着将减慢系统中的所有的应用程序的消息处理。它甚至能够使一个或多个进程变得很不稳定。因此,请确保在你使用完钩子时一定要移去你的系统钩子。我们确定在我们的示例应用程序会移去该系统钩子-通过在Form的Dispose方法中添加一个Dispose调用。
protected override void Dispose(bool disposing) {
if (disposing) {
if (mouseHook != null) {
mouseHook.Dispose();
mouseHook = null;
}
// ...
}
}
使用该类库的情况就是如此。该类库中有两个系统钩子类并且相当容易扩充。
四、 构建库
这个库共有两个主要组件。第一部分是一个C#类库-你可以直接使用于你的应用程序中。该类库,反过来,在内部使用一个非托管的C++ DLL来直接管理系统钩子。我们将首先讨论开发该C++部分。接下来,我们将讨论怎么在C#中使用这个库来构建一个通用的钩子类。就象我们讨论C++/C#交互一样,我们将特别注意C++方法和数据类型是怎样映射到.NET方法和数据类型的。
你可能想知道为什么我们需要两个库,特别是一个非托管的C++ DLL。你还可能注意到在本文的背景一节中提到的两篇参考文章,其中并没有使用任何非托管的代码。为此,我的回答是,"对!这正是我写这篇文章的原因"。当你思考系统钩子是怎样实际地实现它们的功能时,我们需要非托管的代码是十分重要的。为了使一个全局的系统钩子能够工作,Windows把你的DLL插入到每个正在运行的进程的进程空间中。既然大多数进程不是.NET进程,所以,它们不能直接执行.NET装配集。我们需要一种非托管的代码代理- Windows可以把它插入到所有将要被钩住的进程中。
首先是提供一种机制来把一个.NET代理传递到我们的C++库。这样,我们用C++语言定义下列函数(SetUserHookCallback)和函数指针(HookProc)。
int SetUserHookCallback(HookProc userProc, UINT hookID)
typedef void (CALLBACK *HookProc)(int code, WPARAM w, LPARAM l)
SetUserHookCallback的第二个参数是钩子类型-这个函数指针将使用它。现在,我们必须用C#来定义相应的方法和代理以使用这段代码。下面是我们怎样把它映射到C#。
private static extern SetCallBackResults
SetUserHookCallback(HookProcessedHandler hookCallback, HookTypes hookType)
protected delegate void HookProcessedHandler(int code, UIntPtr wparam, IntPtr lparam)
public enum HookTypes {
JournalRecord = 0,
JournalPlayback = 1,
// ...
KeyboardLL = 13,
MouseLL = 14
};
首先,我们使用DllImport属性导入SetUserHookCallback函数,作为我们的抽象基钩子类SystemHook的一个静态的外部的方法。为此,我们必须映射一些外部数据类型。首先,我们必须创建一个代理作为我们的函数指针。这是通过定义上面的HookProcessHandler 来实现的。我们需要一个函数,它的C++签名为(int,WPARAM,LPARAM)。在Visual Studio .NET C++编译器中,int与C#中是一样的。也就是说,在C++与C#中int就是Int32。事情并不总是这样。一些编译器把C++ int作为Int16对待。我们坚持使用Visual Studio .NET C++编译器来实现这个工程,因此,我们不必担心编译器差别所带来的另外的定义。
接下来,我们需要用C#传递WPARAM和LPARAM值。这些确实是指针,它们分别指向C++的UINT和LONG值。用C#来说,它们是指向uint和int的指针。如果你还不确定什么是WPARAM,你可以通过在C++代码中单击右键来查询它,并且选择"Go to definition"。这将会引导你到在windef.h中的定义。
//从windef.h:
typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;
因此,我们选择System.UIntPtr和System.IntPtr作为我们的变量类型-它们分别相应于WPARAM和LPARAM类型,当它们使用在C#中时。
现在,让我们看一下钩子基类是怎样使用这些导入的方法来传递一个回叫函数(代理)到C++中-它允许C++库直接调用你的系统钩子类的实例。首先,在构造器中,SystemHook类创建一个到私有方法InternalHookCallback的代理-它匹配HookProcessedHandler代理签名。然后,它把这个代理和它的HookType传递到C++库以使用SetUserHookCallback方法来注册该回叫函数,如上面所讨论的。下面是其代码实现:
public SystemHook(HookTypes type){
_type = type;
_processHandler = new HookProcessedHandler(InternalHookCallback);
SetUserHookCallback(_processHandler, _type);
}
InternalHookCallback的实现相当简单。InternalHookCallback在用一个catch-all try/catch块包装它的同时仅传递到抽象方法HookCallback的调用。这将简化在派生类中的实现并且保护C++代码。记住,一旦一切都准备妥当,这个C++钩子就会直接调用这个方法。
[MethodImpl(MethodImplOptions.NoInlining)]
private void InternalHookCallback(int code, UIntPtr wparam, IntPtr lparam){
try { HookCallback(code, wparam, lparam); }
catch {}
}
我们已增加了一个方法实现属性-它告诉编译器不要内联这个方法。这不是可选的。至少,在我添加try/catch之前是需要的。看起来,由于某些原因,编译器在试图内联这个方法-这将给包装它的代理带来各种麻烦。然后,C++层将回叫,而该应用程序将会崩溃。
现在,让我们看一下一个派生类是怎样用一个特定的HookType来接收和处理钩子事件。下面是虚拟的MouseHook类的HookCallback方法实现:
protected override void HookCallback(int code, UIntPtr wparam, IntPtr lparam){
if (MouseEvent == null) { return; }
int x = 0, y = 0;
MouseEvents mEvent = (MouseEvents)wparam.ToUInt32();
switch(mEvent) {
case MouseEvents.LeftButtonDown:
GetMousePosition(wparam, lparam, ref x, ref y);
break;
// ...
}
MouseEvent(mEvent, new Point(x, y));
}
首先,注意这个类定义一个事件MouseEvent-该类在收到一个钩子事件时激发这个事件。这个类在激发它的事件之前,把数据从WPARAM和 LPARAM类型转换成.NET中有意义的鼠标事件数据。这样可以使得类的消费者免于担心解释这些数据结构。这个类使用导入的 GetMousePosition函数-我们在C++ DLL中定义的用来转换这些值。为此,请看下面几段的讨论。
在这个方法中,我们检查是否有人在听这一个事件。如果没有,不必继续处理这一事件。然后,我们把WPARAM转换成一个MouseEvents枚举类型。我们已小心地构造了MouseEvents枚举来准确匹配它们在C ++中相应的常数。这允许我们简单地把指针的值转换成枚举类型。但是要注意,这种转换即使在WPARAM的值不匹配一个枚举值的情况下也会成功。 mEvent的值将仅是未定义的(不是null,只是不在枚举值范围之内)。为此,请详细分析System.Enum.IsDefined方法。
接下来,在确定我们收到的事件类型后,该类激活这个事件,并且通知消费者鼠标事件的类型及在该事件过程中鼠标的位置。
最后注意,有关转换WPARAM和LPARAM值:对于每个类型的事件,这些变量的值和意思是不同的。因此,在每一种钩子类型中,我们必须区别地解释这些值。我选择用C++实现这种转换,而不是尽量用C#来模仿复杂的C++结构和指针。例如,前面的类就使用了一个叫作GetMousePosition的 C++函数。下面是C++ DLL中的这个方法:
bool GetMousePosition(WPARAM wparam, LPARAM lparam, int amp; x, int amp; y) {
MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lparam;
x = pMouseStruct->pt.x;
y = pMouseStruct->pt.y;
return true;
}
不是尽量映射MOUSEHOOKSTRUCT结构指针到C#,我们简单地暂时把它回传到C++层以提取我们需要的值。注意,因为我们需要从这个调用中返回一些值,我们把我们的整数作为参考变量传递。这直接映射到C#中的int*。但是,我们可以重载这个行为,通过选择正确的签名来导入这个方法。
private static extern bool InternalGetMousePosition(UIntPtr wparam,IntPtr lparam, ref int x, ref int y)
通过把integer参数定义为ref int,我们得到通过C++参照传递给我们的值。如果我们想要的话,我们还可以使用out int。
五、 限制
一些钩子类型并不适合实现全局钩子。我当前正在考虑解决办法-它将允许使用受限制的钩子类型。到目前为止,不要把这些类型添加回该库中,因为它们将导致应用程序的失败(经常是系统范围的灾难性失败)。下一节将集中讨论这些限制背后的原因和解决办法。
HookTypes.CallWindowProcedure
HookTypes.CallWindowProret
HookTypes.ComputerBasedTraining
HookTypes.Debug
HookTypes.ForegroundIdle
HookTypes.JournalRecord
HookTypes.JournalPlayback
HookTypes.GetMessage
HookTypes.SystemMessageFilter
六、 两种类型的钩子
在本节中,我将尽量解释为什么一些钩子类型被限制在一定的范畴内而另外一些则不受限制。如果我使用有点偏差术语的话,请原谅我。我还没有找到任何有关这部分题目的文档,因此,我编造了我自己的词汇。另外,如果你认为我根本就不对,请告诉我好了。
当Windows调用传递到SetWindowsHookEx()的回调函数时它们会因不同类型的钩子而被区别调用。基本上有两种情况:切换执行上下文的钩子和不切换执行上下文的钩子。用另一种方式说,也就是,在放钩子的应用程序进程空间执行钩子回调函数的情况和在被钩住的应用程序进程空间执行钩子回调函数的情况。
钩子类型例如鼠标和键盘钩子都是在被Windows调用之前切换上下文的。整个过程大致如下:
1. 应用程序X拥有焦点并执行。
2. 用户按下一个键。
3. Windows从应用程序X接管上下文并把执行上下文切换到放钩子的应用程序。
4. Windows用放钩子的应用程序进程空间中的键消息参数调用钩子回调函数。
5. Windows从放钩子的应用程序接管上下文并把执行上下文切换回应用程序X。
6. Windows把消息放进应用程序X的消息排队。
7. 稍微一会儿之后,当应用程序X执行时,它从自己的消息排队中取出消息并且调用它的内部按键(或松开或按下)处理器。
8. 应用程序X继续执行...
例如CBT钩子(window创建,等等。)的钩子类型并不切换上下文。对于这些类型的钩子,过程大致如下:
1. 应用程序X拥有焦点并执行。
2. 应用程序X创建一个窗口。
3. Windows用在应用程序X进程空间中的CBT事件消息参数调用钩子回调函数。
4. 应用程序X继续执行...
这应该说明了为什么某种类型的钩子能够用这个库结构工作而一些却不能。记住,这正是该库要做的。在上面第4步和第3步之后,分别插入下列步骤:
1. Windows调用钩子回调函数。
2. 目标回调函数在非托管的DLL中执行。
3. 目标回调函数查找它的相应托管的调用代理。
4. 托管代理被以适当的参数执行。
5. 目标回调函数返回并执行相应于指定消息的钩子处理。
第三步和第四步因非切换钩子类型而注定失败。第三步将失败,因为相应的托管回调函数不会为该应用程序而设置。记住,这个DLL使用全局变量来跟踪这些托管代理并且该钩子DLL被加载到每一个进程空间。但是这个值仅在放钩子的应用程序进程空间中设置。对于另外其它情况,它们全部为null。
Tim Sylvester在他的《Other hook types》一文中指出,使用一个共享内存区段将会解决这个问题。这是真实的,但是也如Tim所指出的,那些托管代理地址对于除了放钩子的应用程序之外的任何进程是无意义的。这意味着,它们是无意义的并且不能在回调函数的执行过程中调用。那样会有麻烦的。
因此,为了把这些回调函数使用于不执行上下文切换的钩子类型,你需要某种进程间的通讯。
我已经试验过这种思想-使用非托管的DLL钩子回调函数中的进程外COM对象进行IPC。如果你能使这种方法工作,我将很高兴了解到这点。至于我的尝试,结果并不理想。基本原因是很难针对各种进程和它们的线程(CoInitialize(NULL))而正确地初始化COM单元。这是一个在你可以使用 COM对象之前的基本要求。
我不怀疑,一定有办法来解决这个问题。但是我还没有试用过它们,因为我认为它们仅有有限的用处。例如,CBT钩子可以让你取消一个窗口创建,如果你希望的话。可以想像,为使这能够工作将会发生什么。
1. 钩子回调函数开始执行。
2. 调用非托管的钩子DLL中的相应的钩子回调函数。
3. 执行必须被路由回到主钩子应用程序。
4. 该应用程序必须决定是否允许这一创建。
5. 调用必须被路由回仍旧在运行中的钩子回调函数。
6. 在非托管的钩子DLL中的钩子回调函数从主钩子应用程序接收到要采取的行动。
7. 在非托管的钩子DLL中的钩子回调函数针对CBT钩子调用采取适当的行动。
8. 完成钩子回调函数的执行。
这不是不可能的,但是不算好的。我希望这会消除在该库中的围绕被允许的和受限制的钩子类型所带来的神秘。
七、 其它
・库文档:我们已经包含了有关ManagedHooks类库的比较完整的代码文档。当以"Documentation"构建配置进行编译时,这被经由Visual Studio.NET转换成标准帮助XML。最后,我们已使用NDoc来把它转换成编译的HTML帮助(CHM)。你可以看这个帮助文件,只需简单地在该方案的解决方案资源管理器中点击Hooks.chm文件或通过查找与该文相关的可下载的ZIP文件。
・增强的智能感知:如果你不熟悉Visual Studio.NET怎样使用编译的XML文件(pre-NDoc output)来为参考库的工程增强智能感知,那么让我简单地介绍一下。如果你决定在你的应用程序中使用这个类库,你可以考虑复制该库的一个稳定构建版本到你想参考它的位置。同时,还要把XML文档文件 (SystemHooks\ManagedHooks\bin\Debug\Kennedy.ManagedHooks.xml)复制到相同的位置。当你添加一个参考到该库时,Visual Studio.NET将自动地读该文件并使用它来添加智能感知文档。这是很有用的,特别是对于象这样的第三方库。
・单元测试:我相信,所有的库都应有与之相应的单元测试。既然我是一家公司(主要负责针对.NET环境软件的单元测试)的合伙人和软件工程师,任何人不会对此感到惊讶。因而,你将会在名为ManagedHooksTests的解决方案中找到一个单元测试工程。为了运行该单元测试,你需要下载和安装 HarnessIt-这个下载是我们的商业单元测试软件的一个自由的试用版本。在该单元测试中,我对这给予了特殊的注意-在此处,方法的无效参数可能导致 C++内存异常的发生。尽管这个库是相当简单的,但该单元测试确实能够帮助我在一些更为微妙的情况下发现一些错误。
・非托管的/托管的调试:有关混合解决方案(例如,本文的托管的和非托管的代码)最为技巧的地方之一是调试问题。如果你想单步调试该C++代码或在C++代码中设置断点,你必须启动非托管的调试。这是一个Visual Studio.NET中的工程设置。注意,你可以非常顺利地单步调试托管的和非托管的层,但是,在调试过程中,非托管的调试确实严重地减慢应用程序的装载时间和执行速度。
八、 最后警告
很明显,系统钩子相当有力量;然而,使用这种力量应该是有责任性的。在系统钩子出了问题时,它们不仅仅垮掉你的应用程序。它们可以垮掉在你的当前系统中运行的每个应用程序。但是到这种程度的可能性一般是很小的。尽管如此,在使用系统钩子时,你还是需要再三检查你的代码。
我发现了一项可以用来开发应用程序的有用的技术-它使用系统钩子来在微软的虚拟PC上安装你的喜爱的开发操作系统的一个拷贝和Visual Studio.NET。然后,你就可以在此虚拟的环境中开发你的应用程序。用这种方式,当你的钩子应用程序出现错误时,它们将仅退出你的操作系统的虚拟实例而不是你的真正的操作系统。我已经不得不重启动我的真正的OS-在这个虚拟OS由于一个钩子错误崩溃时,但是这并不经常。
安装键盘和鼠标钩子是什么意思
系统有自己的定时关机程序。点开始,运行输入
“at 22:00 Shutdown -s”,这样,到了22点电脑就会出现“系统关机”对话框,默认有30秒钟的倒计时并提示
你保存工作。如果你想以倒计时的方式关机,可以输入“Shutdown.exe -s -t 3600”,这
里表示60分钟后自动关机,“3600”代表60分钟。 设置好自动关机后,如果想取消的话,可以在运行中输入“shutdown -a”。另外输
入“shutdown -i”,则可以打开设置自动关机对话框,对自动关机进行设置。.
安装键盘和鼠标钩子是什么意思
系统有自己的定时关机程序。
点开始,运行输入
“at
22:00
Shutdown
-s”,这样,到了22点电脑就会出现“系统关机”对话框,默认有30秒钟的倒计时并提示
你保存工作。如果你想以倒计时的方式关机,可以输入“Shutdown.exe
-s
-t
3600”,这
里表示60分钟后自动关机,“3600”代表60分钟。
设置好自动关机后,如果想取消的话,可以在运行中输入“shutdown
-a”。另外输
入“shutdown
-i”,则可以打开设置自动关机对话框,对自动关机进行设置。.