2005年4月13日 #
VB.NET代码 |
---|
|
C#代码 |
J#代码 |
|
JScript.NET代码 |
2005年4月4日 #
2005年4月1日 #
1. What is AspectJ?
AspectJ(tm) is a simple and practical extension to the Java(tm) programming language that adds to Java aspect-oriented programming (AOP) capabilities. AOP allows developers to reap the benefits of modularity for concerns that cut across the natural units of modularity. In object-oriented programs like Java, the natural unit of modularity is the class. In AspectJ, aspects modularize concerns that affect more than one class.
You compile your program using the AspectJ compiler (perhaps using the supported development environments) and then run it, supplying a small (< 100K) runtime library.
The AspectJ technologies include a compiler (ajc), a debugger (ajdb), a documentation generator (ajdoc), a program structure browser (ajbrowser), and integration with Eclipse, Sun-ONE/Netbeans, GNU Emacs/XEmacs, JBuilder, and Ant.
2. What are the benefits of using AspectJ?
AspectJ can be used to improve the modularity of software systems.
Using ordinary Java, it can be difficult to modularize design concerns such as
system-wide error-handling
contract enforcement
distribution concerns
feature variations
context-sensitive behavior
persistence
testing
The code for these concerns tends to be spread out across the system. Because these concerns won't stay inside of any one module boundary, we say that they crosscut the system's modularity.
AspectJ adds constructs to Java that enable the modular implementation of crosscutting concerns. This ability is particularly valuable because crosscutting concerns tend to be both complex and poorly localized, making them hard to deal with.
3. Can AspectJ work with any Java program?
AspectJ has been designed as a compatible extension to Java. By compatible, we mean
upward compatible | All legal Java programs are legal AspectJ programs. |
platform compatible | All legal AspectJ programs run on standard Java virtual machines. |
tool compatible | Existing tools can be extended to work with AspectJ. |
programmer compatible | Programming in AspectJ feels natural to Java programmers. |
The AspectJ tools run on any Java 2 Platform compatible platform. The AspectJ compiler produces classes that run on any Java 1.1 (or later) compatible platform.
4. How is AspectJ licensed?
AspectJ 1.1 source code and documentation is available under the Common Public License 1.0.
The AspectJ 1.0 tools are open-source software available under the Mozilla Public License 1.1. That documentation is available under a separate license that precludes for-profit or commercial redistribution.
Most users only want to use AspectJ to build programs they distribute. There are no restrictions here. When you distribute your program, be sure to include all the runtime classes from the aspectjrt.jar for that version of AspectJ. When distributing only the runtime classes, you need not provide any notice that the program was compiled with AspectJ or includes binaries from the AspectJ project, except as necessary to preserve the warranty disclaimers in our license.
5. What is the AspectJ Project?
AspectJ is based on over ten years of research at Xerox Palo Alto Research Center as funded by Xerox, a U.S. Government grant (NISTATP), and a DARPA contract.
It has evolved through open-source releases to a strong user community and now operates as an open source project at http://eclipse.org/aspectj The AspectJ team works closely with the community to ensure AspectJ continues to evolve as an effective aspect-oriented programming language and tool set.
The latest release is 1.2 which can be downloaded from the AspectJ project page, including sources as described Q:How do I get and compile the source code for AspectJ?. Development is focused on supporting applications, improving quality and performance, enhancing integration with IDE's, and building the next generations of the language.
1. What Java versions does AspectJ require and support?
The AspectJ compiler produces programs for any released version of the Java platform (jdk1.1 and later). When running, your program classes must be able to reach classes in the small (< 100K) runtime library (aspectjrt.jar) from the distribution. The tools themselves require J2SE 1.3 or later to run, but the compiler can produce classes for any 1.1-compliant version of the Java platform.
2. How do I download and install AspectJ?
From AspectJ's web page , download the AspectJ distribution. The jar file is installed by executing
java -jar jar file name
Do not try to extract the jar file contents and then attempt to execute java org.aspectj.tools.Main. (A NoClassDefFoundError exception will be thrown.) The AspectJ distribution is not designed to be installed this way. Use the java -jar form shown above.
To uninstall, remove the files the installer wrote in your file system. In most cases, you can delete the top-level install directory (and all contained files), after you remove any new or updated files you want to keep. On Windows, no registry settings were added or changed, so nothing needs to be undone. Do not install over prior versions, which might have different files. Delete the prior version first.
3. How should I start using AspectJ?
Many users adopt AspectJ incrementally, first using it to understand and validate their systems (relying on it only in development) and then using it to implement crosscutting concerns in production systems. AspectJ has been designed to make each step discrete and beneficial.
In order of increasing reliance, you may use AspectJ:
In the development process Use AspectJ to trace or log interesting information. You can do this by adding simple AspectJ code that performs logging or tracing. This kind of addition may be removed ("unplugged") for the final build since it does not implement a design requirement; the functionality of the system is unaffected by the aspect.
As an ancillary part of your system Use AspectJ to more completely and accurately test the system. Add sophisticated code that can check contracts, provide debugging support, or implement test strategies. Like pure development aspects, this code may also be unplugged from production builds. However, the same code can often be helpful in diagnosing failures in deployed production systems, so you may design the functionality to be deployed but disabled, and enable it when debugging.
As an essential part of your system Use AspectJ to modularize crosscutting concerns in your system by design. This uses AspectJ to implement logic integral to a system and is delivered in production builds.
一:总揽
1什么是AspectJ
AspectJ是JAVA程序语言的简单并且实用的一种扩充。它增加了JAVA aspect-oriented progamming(AOP)即面向方面编程的工能。它能使程序员从模块单元的横切关系上获知益。像面向对象编语言JAVA,模块之间的一种自然的关联是建立在类。也就是class上的。在AspectJ中,这种关联会涉及到一多个模块。
你可以用aspectJ进行你的程序开发(不包括运行环境),一个运行库大约不到100k.
AspectJ 技术包括一个编译器ajc,一个调式器ajdb,一个通用文档ajdoc,一个程序结构浏览器ajbrowser,还有一个支持这个架构的运行环境,Eclipse,SUN-ONE/Netbeans,GUNEmacs/XEmacs,JBuilder,和Ant.
2使用AspectJ的好处
AspectJ可以用于改进软件模块的性能。
使用JAVA语言,在 处理系统异常(system-wide error-handling),契约式编程(contract enforcement),分布式(distribution concerns),可变性(feature variations),上下文相关行为(context-sensitive behavior),持久化(persistence),测试(testing)在这些方面,模块之间的关联很难设计。在这些方面,代码不能分布在整个系统中,而不能封装在一个类中,这便是系统中的一种横切关系。
AspectJ提供的构架使模块能够实现横切关系。实现系统中的横切关系是很有价值并且必要的,因为系统中这些分散于各个模块的代码,使我们的设计变得复杂,局部混乱,并且乱于管理与维护。
3AspectJ能应该于任何系统中吗?
AspectJ可以和任何JAVA程序兼容。这种兼容是包括以下几个方面
向上兼容:所有标准的JAVA程序,都是标准的Aspect程序。
平台兼容:所有标准的Aspect程序,都是运行于JAVA虚拟机上。
工具兼容:现有工具可以被延用到AspectJ中使用。
程序兼容:在AspectJ中编写的程序,对于JAVA程序来说,感觉也会很自然,很熟悉。
二:快速入门
1.AspectJ要求并支持的JAVA版本?
AspectJ可以为JAVA平台1.1以后的版本发布代码。运行时,你要使自己程序的类可以访问到AspectJ运行类aspectj.jar(这个包小于100k).
2.怎样下载AspectJ的安装文件?
从AspectJ的网页上,下载AspectJ的正式版。java-jar×××解压后,安装。
不要尝试分解jar文件的内容,或者分离工具包中的类。(NoClassDefFoundError exception 没有创建的类 这个异常会被抛出。 )不能这样安装.还是要按着解压后安装的方式,进行安装。
卸载时,要删除掉已经写入的文件。在大多情况下,再你把要保存的新的或刚刚更新过的文件移开时,你可以删除最上层的安装目录。在windows下,不用注册,所以不用做什么其它事情就可以正常使用了。不要覆盖安装当前版本,因为可能出现新的文件。安装新版本前,请删除原来的文件。
3怎样开始使用AspectJ
许多用户常常会先用AspectJ来了解验证自己的系统,然后再去用AspectJ去执行横切。AspectJ设计本意使设计阶段连续不间段的获利。
在以下几个方面你可以自信的使用AspectJ:
1在系统开发过程中:使用AspectJ来描述或记录特殊信息。你可以通过简单的AspectJ代码来实现日志记录和信息描述。如果系统不需要执行这些功能的时候,也可以把这个新增的功能最终的系统中拿掉,而原来的系统不会受任何的影响。
2系统的辅助部分:使用AspectJ来完善并且精确的测试你的系统。AspectJ增加了精典的代码来检查系统规范,支持检查系统漏洞,或者执行系统测试。就像AOP的本质一样,这些代码一样可以被从最终的系统中删除。这些代码在检查现有系统的问题的时候还是很有帮助的,所以我们可以把这功能设计出来,但是不在系统运行时,有实际的作用,而只在测试时产生作用。
3系统核心部分:使用AspectJ来对模块进行横切设计。这种使用AspectJ来对系统执行的逻辑规范将被包括在系统中。
2005年3月30日 #
引言
Windows操作系统是建立在事件驱动机制之上的,系统各部分之间的沟通也都是通过消息的相互传递而实现的。但在通常情况下,应用程序只能处理来自进程内部的消息或是从其他进程发过来的消息,如果需要对在进程外传递的消息进行拦截处理就必须采取一种被称为HOOK(钩子)的技术。钩子是Windows操作系统中非常重要的一种系统接口,用它可以轻松截获并处理在其他应用程序之间传递的消息,并由此可以完成一些普通应用程序难以实现的特殊功能。基于钩子在消息拦截处理中的强大功能,本文即以VC++ 6.0为编程背景对钩子的基本概念及其实现过程展开讨论。为方便理解,在文章最后还给出了一个简单的有关鼠标钩子的应用示例。
钩子的基本原理
钩子的本质是一段用以处理系统消息的程序,通过系统调用,将其挂入到系统。钩子的种类有很多,每一种钩子负责截获并处理相应的消息。钩子机制允许应用程序截获并处理发往指定窗口的消息或特定事件,其监视的窗口即可以是本进程内的也可以是由其他进程所创建的。在特定的消息发出,并在到达目的窗口之前,钩子程序先行截获此消息并得到对其的控制权。此时在钩子函数中就可以对截获的消息进行各种修改处理,甚至强行终止该消息的继续传递。
任何一个钩子都由系统来维护一个指针列表(钩子链表),其指针指向钩子的各个处理函数。最近安装的钩子放在链的开始,最早安装的钩子则放在最后,当钩子监视的消息出现时,操作系统调用链表开始处的第一个钩子处理函数进行处理,也就是说最后加入的钩子优先获得控制权。在这里提到的钩子处理函数必须是一个回调函数(callback function),而且不能定义为类成员函数,必须定义为普通的C函数。在使用钩子时可以根据其监视范围的不同将其分为全局钩子和线程钩子两大类,其中线程钩子只能监视某个线程,而全局钩子则可对在当前系统下运行的所有线程进行监视。显然,线程钩子可以看作是全局钩子的一个子集,全局钩子虽然功能强大但同时实现起来也比较烦琐:其钩子函数的实现必须封装在动态链接库中才可以使用。
钩子的安装与卸载
由于全局钩子具有相当的广泛性而且在功能上完全覆盖了线程钩子,因此下面就主要对应用较多的全局钩子的安装与使用进行讨论。前面已经提过,操作系统是通过调用钩子链表开始处的第一个钩子处理函数而进行消息拦截处理的。因此,为了设置钩子,只需将回调函数放置于链首即可,操作系统会使其首先被调用。在具体实现时由函数SetWindowsHookEx()负责将回调函数放置于钩子链表的开始位置。SetWindowsHookEx()函数原型声明如下:
HHOOK SetWindowsHookEx(int idHook;
HOOKPROC lpfn;
HINSTANCE hMod;
DWORD dwThreadId);
其中:参数idHook 指定了钩子的类型,总共有如下13种:
WH_CALLWNDPROC 系统将消息发送到指定窗口之前的"钩子"
WH_CALLWNDPROCRET 消息已经在窗口中处理的"钩子"
WH_CBT 基于计算机培训的"钩子"
WH_DEBUG 差错"钩子"
WH_FOREGROUNDIDLE 前台空闲窗口"钩子"
WH_GETMESSAGE 接收消息投递的"钩子"
WH_JOURNALPLAYBACK 回放以前通过WH_JOURNALRECORD"钩子"记录的输入消息
WH_JOURNALRECORD 输入消息记录"钩子"
WH_KEYBOARD 键盘消息"钩子"
WH_MOUSE 鼠标消息"钩子"
WH_MSGFILTER 对话框、消息框、菜单或滚动条输入消息"钩子"
WH_SHELL 外壳"钩子"
WH_SYSMSGFILTER 系统消息"钩子"
参数lpfn为指向钩子处理函数的指针,即回调函数的首地址;参数hMod则标识了钩子处理函数所处模块的句柄;第四个参数dwThreadId 指定被监视的线程,如果明确指定了某个线程的ID就只监视该线程,此时的钩子即为线程钩子;如果该参数被设置为0,则表示此钩子为监视系统所有线程的全局钩子。此函数在执行完后将返回一个钩子句柄。
虽然对于线程钩子并不要求其象全局钩子一样必须放置于动态链接库中,但是推荐其也在动态链接库中实现。因为这样的处理不仅可使钩子可为系统内的多个进程访问,也可以在系统中被直接调用,而且对于一个只供单进程访问的钩子,还可以将其钩子处理过程放在安装钩子的同一个线程内,此时SetWindowsHookEx()函数的第三个参数也就是该线程的实例句柄。
在SetWindowsHookEx()函数完成对钩子的安装后,如果被监视的事件发生,系统马上会调用位于相应钩子链表开始处的钩子处理函数进行处理,每一个钩子处理函数在进行相应的处理时都要考虑是否需要把事件传递给下一个钩子处理函数。如果要传递,就通过函数CallNestHookEx()来解决。尽管如此,在实际使用时还是强烈推荐无论是否需要事件传递而都在过程的最后调用一次CallNextHookEx( )函数,否则将会引起一些无法预知的系统行为或是系统锁定。该函数将返回位于钩子链表中的下一个钩子处理过程的地址,至于具体的返回值类型则要视所设置的钩子类型而定。该函数的原型声明如下:
LRESULT CallNextHookEx(HHOOK hhk;int nCode;WPARAM wParam;LPARAM lParam);
其中,参数hhk为由SetWindowsHookEx()函数返回的当前钩子句柄;参数nCode为传给钩子过程的事件代码;参数wParam和lParam 则为传给钩子处理函数的参数值,其具体含义同设置的钩子类型有关。
最后,由于安装钩子对系统的性能有一定的影响,所以在钩子使用完毕后应及时将其卸载以释放其所占资源。释放钩子的函数为UnhookWindowsHookEx(),该函数比较简单只有一个参数用于指定此前由SetWindowsHookEx()函数所返回的钩子句柄,原型声明如下:
BOOL UnhookWindowsHookEx(HHOOK hhk);
鼠标钩子的简单示例
最后,为更清楚展示HOOK技术在VC编程中的应用,给出一个有关鼠标钩子使用的简单示例。在钩子设置时采用的是全局钩子。下面就对鼠标钩子的安装、使用以及卸载等过程的实现进行讲述:
由于本例程需要使用全局钩子,因此首先构造全局钩子的载体--动态链接库。考虑到 Win32 DLL与Win16 DLL存在的差别,在Win32环境下要在多个进程间共享数据,就必须采取一些措施将待共享的数据提取到一个独立的数据段,并通过def文件将其属性设置为读写共享:
#pragma data_seg("TestData") HWND glhPrevTarWnd=NULL; // 窗口句柄 HWND glhHook=NULL; // 鼠标钩子句柄 HINSTANCE glhInstance=NULL; // DLL实例句柄 #pragma data_seg() …… SECTIONS // def文件中将数据段TestData设置为读写共享 TestData READ WRITE SHARED |
在安装全局鼠标钩子时使用函数SetWindowsHookEx(),并设定鼠标钩子的处理函数为MouseProc(),安装函数返回的钩子句柄保存于变量glhHook中:
void StartHook(HWND hWnd) { …… glhHook=(HWND)SetWindowsHookEx(WH_MOUSE,MouseProc,glhInstance,0); } |
鼠标钩子安装好后,在移动、点击鼠标时将会发出鼠标消息,这些消息均经过消息处理函数MouseProc()的拦截处理。在此,每当捕获到系统各线程发出的任何鼠标消息后首先获取当前鼠标所在位置下的窗口句柄,并进一步通过GetWindowText()函数获取到窗口标题。在处理函数完成后,通过CallNextHookEx()函数将事件传递到钩子列表中的下一个钩子处理函数:
LRESULT WINAPI MouseProc(int nCode,WPARAM wParam,LPARAM lParam) { LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *) lParam; if(nCode>=0) { HWND glhTargetWnd=pMouseHook->hwnd; //取目标窗口句柄 HWND ParentWnd=glhTargetWnd; while(ParentWnd !=NULL) { glhTargetWnd=ParentWnd; //取应用程序主窗口句柄 ParentWnd=GetParent(glhTargetWnd); } if(glhTargetWnd!=glhPrevTarWnd) { char szCaption[100]; //取目标窗口标题 GetWindowText(glhTargetWnd,szCaption,100); …… } } //继续传递消息 return CallNextHookEx((HHOOK)glhHook,nCode,wParam,lParam); } |
最后,调用UnhookWindowsHookEx()函数完成对钩子的卸载:
void StopHook() { …… UnhookWindowsHookEx((HHOOK)glhHook); } |
现在完成的是鼠标钩子的动态链接库,经过编译后需要经应用程序的调用才能实现对当前系统下各线程间鼠标消息的拦截处理。这部分同普通动态链接库的使用没有任何区别,在将其加载到进程后,首先调用动态链接库的StartHook()函数安装好钩子,此时即可对系统下的鼠标消息实施拦截处理,在动态链接库被卸载即终止鼠标钩子时通过动态链接库中的StopHook()函数卸载鼠标钩子。
经上述编程,在安装好鼠标钩子后,鼠标在移动到系统任意窗口上时,马上就会通过对鼠标消息的拦截处理而获取到当前窗口的标题。实验证明此鼠标钩子的安装、使用和卸载过程是正确的。
小结
钩子,尤其是系统钩子具有相当强大的功能,通过这种技术可以对几乎所有的Windows系统消息和事件进行拦截处理。这种技术广泛应用于各种自动监控系统对进程外消息的监控处理。本文只对钩子的一些基本原理和一般的使用方法做了简要的探讨,感兴趣的读者完全可以在本文所述代码基础之上用类似的方法实现对诸如键盘钩子、外壳钩子等其他类型钩子的安装与使用。本文所述代码在Windows 98下由Microsoft Visual C++ 6.0编译通过。
#include "stdafx.h"
#include "APIHook_Dll.h"
#include
#include
#pragma comment(lib,"ImageHlp") //定义全局共享数据段
#pragma data_seg("Shared")
HMODULE hmodDll=NULL;
HHOOK hHook=NULL;
#pragma data_seg()
#pragma comment(linker,"/Section:Shared,rws") //设置全局共享数据段的属性
/ DllMain 函数 /
//dll的入口点
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//if(sHook)
case DLL_PROCESS_DETACH:
UnInstallHook();
break;
}
hmodDll=hModule;
return TRUE;
}
/ HookOneAPI 函数 /
//进行IAT转换的关键函数,其参数含义:
//pszCalleeModuleName:需要hook的模块名
//pfnOriginApiAddress:要替换的自己API函数的地址
//pfnDummyFuncAddress:需要hook的模块名的地址
//hModCallerModule:我们要查找的模块名称,如果没有被赋值,
// 将会被赋值为枚举的程序所有调用的模块
void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
{
ULONG size;
//获取指向PE文件中的Import中IMAGE_DIRECTORY_DESCRIPTOR数组的指针
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData(hModCallerModule,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);
if (pImportDesc == NULL)
return;
//查找记录,看看有没有我们想要的DLL
for (;pImportDesc->Name;pImportDesc++)
{
LPSTR pszDllName = (LPSTR)((PBYTE)hModCallerModule+pImportDesc->Name);
if (lstrcmpiA(pszDllName,pszCalleeModuleName) == 0)
break;
}
if (pImportDesc->Name == NULL)
{
return;
}
//寻找我们想要的函数
PIMAGE_THUNK_DATA pThunk =
(PIMAGE_THUNK_DATA)((PBYTE)hModCallerModule+pImportDesc->FirstThunk);//IAT
for (;pThunk->u1.Function;pThunk++)
{
//ppfn记录了与IAT表项相应的函数的地址
PROC * ppfn= (PROC *)&pThunk->u1.Function;
if (*ppfn == pfnOriginApiAddress)
{
//如果地址相同,也就是找到了我们想要的函数,进行改写,将其指向我们所定义的函数
WriteProcessMemory(GetCurrentProcess(),ppfn,&(pfnDummyFuncAddress),
sizeof(pfnDummyFuncAddress),NULL);
return;
}
}
}
//查找所挂钩的进程所应用的dll模块的
BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
{
if (pszCalleeModuleName == NULL)
{
return FALSE;
}
if (pfnOriginApiAddress == NULL)
{
return FALSE;
}
//如果没传进来要挂钩的模块名称,枚举被挂钩进程的所有引用的模块,
//并对这些模块进行传进来的相应函数名称的查找
if (hModCallerModule == NULL)
{
MEMORY_BASIC_INFORMATION mInfo;
HMODULE hModHookDLL;
HANDLE hSnapshot;
MODULEENTRY32 me = {sizeof(MODULEENTRY32)};
//MODULEENTRY32:描述了一个被指定进程所应用的模块的struct
VirtualQuery(HookOneAPI,&mInfo,sizeof(mInfo));
hModHookDLL=(HMODULE)mInfo.AllocationBase;
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0);
BOOL bOk = Module32First(hSnapshot,&me);
while (bOk)
{
if (me.hModule != hModHookDLL)
{
hModCallerModule = me.hModule;//赋值
//me.hModule:指向当前被挂钩进程的每一个模块
HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,
pfnDummyFuncAddress,hModCallerModule);
}
bOk = Module32Next(hSnapshot,&me);
}
return TRUE;
}
//如果传进来了,进行查找
else
{
HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,
pfnDummyFuncAddress,hModCallerModule);
return TRUE;
}
return FALSE;
}
UnhookAllAPIHooks 函数 /
//通过使pfnDummyFuncAddress与pfnOriginApiAddress相等的方法,取消对IAT的修改
BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
{
PROC temp;
temp = pfnOriginApiAddress;
pfnOriginApiAddress = pfnDummyFuncAddress;
pfnDummyFuncAddress = temp;
return HookAllAPI(pszCalleeModuleName,pfnOriginApiAddress,
pfnDummyFuncAddress,hModCallerModule);
}
// GetMsgProc 函数
//钩子子程。与其它钩子子程不大相同,没做什么有意义的事情,继续调用下一个钩子子程,形成循环
LRESULT CALLBACK GetMsgProc(int code,WPARAM wParam,LPARAM lParam)
{
return CallNextHookEx(hHook,code,wParam,lParam);
}
InstallHook 函数 /
//安装或卸载钩子,BOOL IsHook参数是标志位
//对要钩哪个API函数进行初始化
//我们这里装的钩子类型是WH_GETMESSAGE
void __declspec(dllexport) WINAPI InstallHook(BOOL IsHook,DWORD dwThreadId)
{
if(IsHook)
{
hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)GetMsgProc,hmodDll,dwThreadId);
//GetProcAddress(GetModuleHandle("GDI32.dll"),"ExtTextOutA"):取得要钩的函数在所在dll中的地址
HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"TextOutW"),(PROC)&H_TextOutW,NULL);
HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"TextOutA"),(PROC)&H_TextOutA,NULL);
}
else
{
UnInstallHook();
UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"TextOutW"),(PROC)&H_TextOutW,NULL);
UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"TextOutA"),(PROC)&H_TextOutA,NULL);
}
}
/ UnInstallHook 函数
//卸载钩子
BOOL WINAPI UnInstallHook()
{
UnhookWindowsHookEx(hHook);
return TRUE;
}
/ H_TextOutA 函数 /
//我们的替换函数,可以在里面实现我们所要做的功能
//这里我做的是显示一个对话框,指明是替换了哪个函数
BOOL WINAPI H_TextOutA(HDC hdc,int nXStart,int nYStart,LPCSTR lpString,int cbString)
{
MessageBox(NULL,"TextOutA","APIHook_Dll ---rivershan",MB_OK);
TextOutA(hdc,nXStart,nYStart,lpString,cbString);//返回原来的函数,以显示字符
return TRUE;
}
/ H_TextOutW 函数 /
//同上
BOOL WINAPI H_TextOutW(HDC hdc,int nXStart,int nYStart,LPCWSTR lpString,int cbString)
{
MessageBox(NULL,"TextOutW","APIHook_Dll ---rivershan",MB_OK);
TextOutW(hdc,nXStart,nYStart,lpString,cbString);//返回原来的函数,以显示字符
return TRUE;
}
**********************************************************************************************
**********************************************************************************************
APIHook_Dll.h
// rivershan写于2002.9.23 //
/
//dll头文件,用于声明函数
void __declspec(dllexport) WINAPI InstallHook(BOOL,DWORD);
BOOL WINAPI UnInstallHook();
LRESULT CALLBACK GetMsgProC(int code,WPARAM wParam,LPARAM lParam);
void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule);
BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule);
BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule);
BOOL WINAPI H_TextOutA(HDC, int, int, LPCSTR, int);
BOOL WINAPI H_TextOutW(HDC, int, int, LPCWSTR, int);
BOOL WINAPI H_ExtTextOutA(HDC, int, int, UINT, CONST RECT *,LPCSTR, UINT, CONST INT *);
BOOL WINAPI H_ExtTextOutW(HDC, int, int, UINT, CONST RECT *,LPCWSTR, UINT, CONST INT *);
**********************************************************************************************
**********************************************************************************************
;APIHook_Dll之def文件
LIBRARY APIHook_Dll
EXPORTS
InstallHook @1
二、APIHOOK之exe部分
APIHook_EXEDlg.cpp /
// rivershan写于2002.9.23 //
/
#include "stdafx.h"
#include "APIHook_EXE.h"
#include "APIHook_EXEDlg.h"
#include "APIHook_Dll.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// CAPIHook_EXEDlg dialog
CAPIHook_EXEDlg::CAPIHook_EXEDlg(CWnd* pParent /*=NULL*/)
: CDialog(CAPIHook_EXEDlg::IDD, pParent)
{
//{ {AFX_DATA_INIT(CAPIHook_EXEDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CAPIHook_EXEDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{ {AFX_DATA_MAP(CAPIHook_EXEDlg)
// DDX_Control(pDX, IDC_EDIT1, m_Edit);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAPIHook_EXEDlg, CDialog)
//{ {AFX_MSG_MAP(CAPIHook_EXEDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_OUT, OnButtonOut)
ON_BN_CLICKED(IDC_BUTTON_BEGIN, OnButtonBegin)
ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CAPIHook_EXEDlg message handlers
BOOL CAPIHook_EXEDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CAPIHook_EXEDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CAPIHook_EXEDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
/ OnButtonOut 函数 //
//使用TextOut函数
void CAPIHook_EXEDlg::OnButtonOut()
{
// TODO: Add your control notification handler code here
HDC hdc = ::GetDC(GetSafeHwnd());
::TextOutA(hdc,0,0,"APIHOOK_EXE ---rivershan",30);
UpdateWindow();
}
/ OnButtonBegin 函数
//开始挂钩,这里我们挂的是自身这个APIHook_EXE这个程序
void CAPIHook_EXEDlg::OnButtonBegin()
{
DWORD dwThreadId = GetWindowThreadProcessId(m_hWnd,NULL);//获得自身进程ID
InstallHook(TRUE,dwThreadId);
}
/ OnButtonStop 函数
//取消挂钩
void CAPIHook_EXEDlg::OnButtonStop()
{
InstallHook(FALSE,0);
}
三、APIHOOK之集成
1. 用 VC++新建一个 Win32 Dynamic-Link Library 程序,命名为 APIHook_Dll。接下来选择第二项 A Simple DLL Project;
2. 新建一头文件,命名为 APIHook_Dll.h。删除工程中 APIHook_Dll.cpp文件中原来的内容,然后把上面的 APIHook_Dll.cpp 和 APIHook_Dll.h文件的内容全部复制到新建的这个工程的 .cpp及 .h文件中来;
3. 新建一 Text文件,命名为 APIHook_Dll.def。复制上面的def文件内容。
4. 编译;
5. 新建一 MFC APPWizard(exe)程序,命名为 APIHook_EXE。接着选择第三项,基于对话框的程序,其它默认;
6. 删除原来对话框上的控件,然后新建三个按钮ID分别为:IDC_BUTTON_BEGIN、IDC_BUTTON_STOP、IDC_BUTTON_OUT,Caption分别为:Bigin Hook、Stop Hook、Text Out。不要让这三个按钮出于对话框客户区的最上面就行;
7. 拷贝 APIHook_Dll.h文件到 APIHook_EXE程序目录下,然后加到 APIHook_EXE的头文件夹中。
8. 删除工程中 APIHook_EXEDlg.cpp文件中原来的内容,然后把上面的 APIHook_EXEDlg.cpp文件的内容全部复制到新建的这个工程的 .cpp文件中来;
9. 打开 Project->Setting菜单,选择第四项link,在 Object/library moduls里添加我们的dll的lib文件的路径:../APIHook_Dll/Debug/APIHook_Dll.lib;
10. 编译;
11. 把 APIHook_Dll.dll文件放在 APIHook_Dll.exe程序的同一个文件夹内;
12. 运行程序,点击 Bigin Hook按钮,开始挂钩。再点击 Text Out按钮会跳出对话框并且会在程序中显示所要显示的字。点击 Stop Hook然后在点击 Text Out按钮就没有对话框出现了。
四、一些说明
1、我这个 HookAPI是使用了 Jeffrey Richter的改写程序的 IAT来实现的,也可以用跳转函数入口点的方法来实现,这个我没做研究。:)
2、我的一些心得:
所谓 HookAPI,就是改写程序的 IAT,再调用我自己写的用于替换原API函数的函数。在我们自己写的API函数中,我们可以进行我们想要的工作。之后呢,可以把原来的函数传回去,也可以不传回去,只要你设计好了就行。
而所谓调用自己的函数,就是把原函数参数都传给我的替换函数。我们就可以利用这些参数去干我们想做的事。而系统呢,我想由于微软设置的这个钩子的目的(我这么认为的),所以不会去检查替换函数是否就是原函数,只要参数、返回值符合条件就行,要不会出错。替换函数的返回值最好是原函数,否则有可能会出错
HookAPI时,exe程序起到的作用就是进行Hook,把dll注入到要Hook的程序,并且传回要挂接的进程的ID或者全局钩子,以便查询所要挂接的模块的IAT。如果不注入进去,系统不会让你去查询IAT的。DLL做的事情是确定要挂接哪个函数和这个函数在哪个DLL中等。
2005年3月29日 #
很多朋友都用虚拟主机来做网站,将网页文件存放在虚拟空间上,但是页面内容一多,网站打开的速度就显得特别慢,如果您碰到这种情况,与其寻求更好的空间,不如通过优化网页代码来取得满意的速度。笔者总结了一些切实可行的方法,制作主页时,以下的方法可以令你的网页速度大大提高。
一、记得帮页面减肥
我们浏览网页实际上是将虚拟主机中的网页内容下载到本地硬盘,再用浏览器解释查看的。下载网页的快慢在显示速度上占了很大比重,所以,网页本身所占的空间越小,那么浏览速度就会越快。这就要求在做网页的时候遵循一切从简的原则,如:不要使用太大的Flash动画、图片等试础8删弧⒓蚪嗟囊趁婊岣艘恢炙悸访骼实母芯酢?BR>
二、如没必要,尽量使用静态HTML页面
众所周知,ASP、PHP、JSP等程序实现了网页信息的动态交互,运行起来的确非常方便,因为它们的数据交互性好,能很方便地存取、更改数据库的内容,使网站“动”起来,如:论坛、留言板等。但是这类程序必须先由服务器执行处理后,生成HTML页面,然后再“送”往客户端浏览,这就不得不耗费一定的服务器资源。如果在虚拟主机上过多地使用这类程序,网页显示速度肯定会慢,所以没有必要,请尽量使用静态的HTML页面。
三、不要将整个页面内容塞到一个Table中
这是网页设计的问题了,很多站长为了追求页面统一对齐,将整个页面的内容都塞进了一个Table(表格)里,然后再由单元格td来划分各个“块”的布局,这种网站的显示速度是绝对慢的。因为Table要等里面所有的内容都加载完毕后才显示出来的,如果某些内容无法访问,就会拖延整个页面的访问速度。正确的做法是:将内容分割到几个具有相同格局的Table中去,不要全都塞到一个Table里。
四、将ASP、ASPX、PHP等文件的访问改为.js引用
这在ASP、ASPX、PHP等程序设计时应该注意的,如果你要在静态的HTML页面里嵌入动态的数据,而这些动态的数据是由ASP、PHP等程序来提供的话,会使用以下的语句引用: < script src="http://image.ccidnet.com/ad_files/network_index.asp?orders=1">< /script>
这样的话,每次有一个人访问你的网站,服务器就要执行并处理一次network_index.asp文件,从数据库抽取相应的数据,再输出给网页显示,如果有几万个人同时访问,就要执行几万次,后果就可想而知。建议在这些程序中将数据动态生成到一个network_index.js文件中去,然后在首页通过
>
这样的代码来引用该network_index.js文件。这样,数据显示的任务就交给客户端的浏览器去做,不会耗费服务器的资源,显示速度自然就很快;前者所花的时间几乎是后者的几倍!
五、使用iframe嵌套另一页面
如果你要在网站上插入一些广告代码,又不想让这些广告网站影响速度的话,那么,使用iframe最合适不过了。方法是:将这些广告代码放到一个独立的页面去,然后在首页用如下的代码将该页面嵌入即可,这样就不会因为广告页面的延迟而拖了整个首页的显示,代码如下:
< iframe frameborder=0
leftmargin=0
marginheight=0
marginwidth=0
scrolling=no src="http://www.179job.com/pub/123.html"
topmargin=0 width=700 height=440 >
< /iframe>
其中http://www.179job.com/pub/123.html是被引用文件的路径。
2005年3月28日 #