(孙鑫 二十) HOOK和数据库访问

1.HOOK
The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. You would install a hook procedure to monitor the system for certain types of events. These events are associated either with a specific thread or with all threads in the system. 
//最后安装的HOOK总排在HOOK链的前面
HHOOK SetWindowsHookEx(
  int idHook,        // type of hook to install:WH_MOUSE/WH_……
  HOOKPROC lpfn,     // address of hook procedure
  HINSTANCE hMod,    // handle to application instance
  DWORD dwThreadId   // identity of thread to install hook for如果是0,则与所有已存在线程相关
);
//若dwThreadId是0或者其他进程建立的线程,则lpfn必须指向一个dll中的hook过程;否则lpfn指向与当前进程相关的代码中定义的钩子过程。&&&
//hMod是包含lpfn指向的hook过程的dll句柄。如果dwThreadId指定了一个被当前进程创建的线程(and if hook过程是在当前进程所定义的代码中),则hMod必须设置为NULL。

The GetCurrentThreadId function returns the thread identifier of the calling thread. 
DWORD GetCurrentThreadId(VOID)

新建一个MFC exe工程:InnerHook 基于对话框的程序。
  在Dlg类的OnInitDialog中:
	SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());


The HOOKPROC type defines a pointer to this callback function. MouseProc is a placeholder for the application-defined or library-defined function name. 

LRESULT CALLBACK MouseProc(
  int nCode,      // hook code:HC_ACTION/NOREMOVE(鼠标消息没有从消息队列移除)
  WPARAM wParam,  // message identifier
  LPARAM lParam   // mouse coordinates(MOUSEHOOKSTRUCT)
);

//返回值:若nCode<0,则hook过程必须返回CallNextHookEx返回的值;若它>=0,而且hook过程没有处理消息,强烈建议你调用CallNextHookEx而且返回它返回的值。否则,其他安装了WH_MOUSE hooks的程序就不会收到通知,就可能工作错误。若hook过程处理了消息,它会返回一个非0值来阻止系统传递消息到目标窗口过程。

The CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain. A hook procedure can call this function either before or after processing the hook information. 

LRESULT CallNextHookEx(
  HHOOK hhk,      // handle to current hook
  int nCode,      // hook code passed to hook procedure
  WPARAM wParam,  // value passed to hook procedure
  LPARAM lParam   // value passed to hook procedure
);


  在OnInitDialog前面:
LRESULT CALLBACK MouseProc(
  int nCode,      // hook code
  WPARAM wParam,  // message identifier
  LPARAM lParam   // mouse coordinates
)
{
	return 1;		//表示已经处理了,就不传递了 
}

  键盘钩子:
	g_Keyboard=SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());
  钩子函数:
LRESULT CALLBACK KeyboardProc(
  int code,       // hook code
  WPARAM wParam,  // virtual-key code按键代码VK_开头
  LPARAM lParam   // keystroke-message information
)
{	
	return 1;
}

  在上面的过程中修改:
HHOOK g_Keyboard=NULL;   //定义全局Hook句柄
	if(VK_SPACE==wParam)
		return 1;
	else
		return CallNextHookEx(g_Keyboard,code,wParam,lParam); //这样就只屏蔽了空格键
  还可修改条件同时屏蔽回车键:VK_SPACE==wParam || VK_RETURN==wParam

lParam 
Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag. This parameter can be a combination of the following values:

Value 	Description 
0–15 	Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user's holding down the key. 
16–23 	Specifies the scan code. The value depends on the original equipment manufacturer (OEM). 
24 	Specifies whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is 1 if the key is an extended key; otherwise, it is 0. 
25–28 	Reserved. 
29 	Specifies the context code. The value is 1 if the alt key is down; otherwise, it is 0. &&&
30 	Specifies the previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up. 
31 	Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released. 
//上面列出了32位各自代表的信息

  屏蔽ALT+F4:
	if(VK_F4==wParam && 1==(lParam>>29 & 1))    //lParam第29位测试Alt位
或者:VK_F4==wParam && (lParam & (1<<29))   //但这样没有上面好

  按下F2键使程序退出:(也先定义一个全局变量HWND g_hWnd=NULL;在OnInitDialog中初始化g_hWnd=m_hWnd;)
	if(VK_F2==wParam)
	{
		::SendMessage(g_hWnd,WM_CLOSE,0,0);
	}
	else
		return CallNextHookEx(g_Keyboard,code,wParam,lParam);

The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindowsHookEx function. 
BOOL UnhookWindowsHookEx(
  HHOOK hhk   // handle to hook procedure to remove
);
  
  再定义一个鼠标钩子句柄:HHOOK g_Mouse=NULL;
(修改开始处g_Mouse=SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());)
	if(VK_F2==wParam)
	{
		::SendMessage(g_hWnd,WM_CLOSE,0,0);
		UnhookWindowsHookEx(g_Mouse);	//移除钩子
		UnhookWindowsHookEx(g_Keyboard);
	}
	return 1;    //用F2关闭窗口

2.全局钩子(必须在dll中)
  新建一个win32 Dll工程:Hook.

#include <windows.h>  //先加

HHOOK g_hMouse=NULL;
//然后编写SetHook函数,为了获得dll句柄,可用DllMain主函数:
HINSTANCE g_hInst;

BOOL WINAPI DllMain(
  HINSTANCE hinstDLL,  // handle to DLL module
  DWORD fdwReason,     // reason for calling function
  LPVOID lpvReserved   // reserved
)
{
	g_hInst=hinstDll;
}

  也可用GetModuleHandle获取模块句柄:
The GetModuleHandle function returns a module handle for the specified module if the file has been mapped into the address space of the calling process. 
HMODULE GetModuleHandle(
  LPCTSTR lpModuleName   // address of module name to return handle 
                         // for
);
If the filename extension is omitted, the default library extension .DLL is appended.//默认扩展名是dll

void SetHook()
{
	SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("Hook"),0);
}   //这样钩子函数就和所有运行在桌面下的线程相关了。

  再写一个模块定义文件避免函数名被更改:在源文件目录下新建一个Hook.def,然后添加到工程中编辑:
LIBRARY Hook

EXPORTS
SetHook		@2 	//2是函数导出的序号

  再添加一个MouseProc:
LRESULT CALLBACK MouseProc(
  int nCode,      // hook code
  WPARAM wParam,  // message identifier
  LPARAM lParam   // mouse coordinates
)
{
	return 1;
}

  用一个exe加载这个Hook.dll,然后调用SetHook添加全局钩子。然后当一个窗口将收到消息的时候,windows会检查该窗口是否已安装了钩子,这里已安装了全局钩子,所以windows将Hook.dll映射到该进程的地址空间中,调用该钩子过程函数。

  再新建一个过程MFC EXE:HookTest 基于对话框的程序。
  在DLg的OnInitDialog前声明:_declspec(dllimport) void SetHook();
  这时又要修改连接选项:在对象/库模块中添加..\Hook\debug\Hook.dll。
  在OnInitDialog中添加:SetHook();   //复制Hook.dll到当前目录

  这时运行程序,钩子函数就起作用了。

3.全局键盘钩子:
  在上面的dll中复制修改相关的代码:
	HHOOK g_hKeyboard=NULL;

LRESULT CALLBACK KeyboardProc(
  int code,       // hook code
  WPARAM wParam,  // virtual-key code
  LPARAM lParam   // keystroke-message information
)
{
	return 1;
}
  SetHook中:
	g_hKeyboard=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,GetModuleHandle("Hook"),0);

  而为了实现按F2之后关闭调用hook的窗口,需要指定该窗口的句柄,所以可在SetHook函数中增加一个HWND hwnd参数。
  再定义一个全局的:HWND g_hWnd=NULL;然后在SetHook中赋值g_hWnd=hwnd;
  在键盘钩子函数中:
	if(VK_F2==wParam)
	{
		SendMessage(g_hWnd,WM_CLOSE,0,0);
		UnhookWindowsHookEx(g_hMouse);
		UnhookWindowsHookEx(g_hKeyboard);
	}
	return 1;
  注意在HookTest中声明和调用的地方,要添加窗口句柄参数m_hWnd,否则就不能退出程序了。
  然后再复制dll过去,运行test程序。但这时只能关闭运行的这个MFC程序。

  可用SetWindowPos将程序设置成平面大小且置顶;可用GetSystemMetrics来获取屏幕宽度和高度。
CWnd::SetWindowPos
BOOL SetWindowPos( const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags );

The GetSystemMetrics function retrieves various system metrics (widths and heights of display elements) and system configuration settings. All dimensions retrieved by GetSystemMetrics are in pixels. &&&
int GetSystemMetrics(
  int nIndex   // system metric or configuration setting to retrieve
);
//这里可用SM_CXSCREEN/SM_CYSCREEN

  在OnInitDialog中SetHook之前,先定义两个int cxScreen,cyScreen;
	cxScreen=GetSystemMetrics(SM_CXSCREEN);
	cyScreen=GetSystemMetrics(SM_CYSCREEN);   //获取屏幕大小
	SetWindowPos(&wndTopMost,0,0,cxScreen,cyScreen,SWP_SHOWWINDOW);   
  但这时若切换到其他窗口,则F2不能结束test程序了(test没有激活了)。我们可以新建一个节,把g_hWnd放到该节中,然后将节设置为共享节,这样就可以在多个进程中共享。

  可用dumpbin -heads Hook.dll查看dll的节:每一个标准节都是以.开始,如.idata等。

  在dll中创建一个新的节:#pragma data_seg("MySec")   //节名不能超过8个字符
  然后后面是:	HWND g_hWnd;
		#pragma data_seg() 		//原先的节
  然后将它设为共享节(在上面的后面添加):#pragma comment(linker,"/section:MySec,RWS")  //S=share
  这时用dumpbin -headers 查看,MySec就是Shared的了。
  也可在模块定义文件中写入:
SEGMENTS
MySec	READ WRITE SHARED 	//可小写

  这时运行test就可以实现在其他进程的时候关闭test窗口了。(注意要把修改后的dll文件复制到test目录)。

4.数据库基本概念
		数据库访问技术
ODBC(Open Database Connectivity),开放数据库互连。ODBC是上个世纪八十年代末九十年代初出现的技术,它为编写关系数据库的客户软件提供了一种统一的接口。ODBC提供一个单一的API,可用于处理不同数据库的客户应用程序。使用ODBC API的应用程序可以与任何具有ODBC驱动程序的关系数据库进行通信。
DAO(Data Access Object),数据访问对象。DAO就是一组Microsoft Access/Jet数据库引擎的COM自动化接口。 DAO不像ODBC那样是面向C/C++程序员的,它是微软提供给Visual Basic开发人员的一种简单的数据访问方法,用于操纵Access数据库。 
RDO(Remote Data Object),远程数据对象。由于RDO直接调用ODBC API(而不是像DAO那样通过Jet引擎),所以,可以为使用关系数据库的应用程序提供更好的性能。

		ODBC体系架构
  我们编写的客户程序《--》ODBC驱动程序管理器《--》ODBC驱动程序(有好多小分支)《--》各种关系数据库。

		数据库访问技术
OLE DB,对象链接与嵌入数据库。 OLE DB在两个方面对ODBC进行了扩展。首先, OLE DB提供了一个数据库编程的COM接口;第二, OLE DB提供了一个可用于关系型和非关系型数据源的接口。 OLE DB的两个基本结构是OLE DB提供程序(Provider)和OLE DB用户程序(Consumer)。&&
ADO(ActiveX Data Object),ActiveX数据对象,它建立在OLE DB之上。ADO是一个OLE DB用户程序。使用ADO的应用程序都要间接地使用OLE DB。ADO简化了OLE DB,提供了对自动化的支持,使得像VBScript这样的脚本语言也能够使用ADO访问数据库。

		OLE DB体系架构
					使用ADO的客户程序
		OLE DB用户程序
使用OLE DB访问数据库的程序		ADO

			OLE DB提供程序
ODBC	ODBC数据库	电子表格	电子邮件	其他非关系型存储
ODBC数据库

		ADO的三个核心对象&&&

Connection对象
	Connection对象表示了到数据库的连接,它管理应用程序和数据库之间的通信。 Recordset和Command对象都有一个ActiveConnection属性,该属性用来引用Connection对象。

Command对象
	Command对象被用来处理重复执行的查询,或处理需要检查在存储过程调用中的输出或返回参数的值的查询。

Recordset对象
	Recordset对象被用来获取数据。 Recordset对象存放查询的结果,这些结果由数据的行(称为记录)和列(称为字段)组成。每一列都存放在Recordset的Fields集合中的一个Field对象中。

5.VB演示,选择MS ADO Data Control 6部件,右键--ADODC属性--点击 使用连接字符串右边的生成--选择提供程序的数据库:这里选MS OLE DB Provider for SQL Server。
  在连接上,若是连接远程服务器要输入服务器名称(本地可省)。这里用户名称为sa,空白密码。在服务器上选择数据库,这里选择pubs(我连不上,没装SQL)。测试连接成功。
  然后切换到RecordSource,类型选择2-adCmdTable,表选择Authors。
  再添加一个MS DataGrid Controls 6.0。数据网格控件。修改其DataSource属性为Adodc1(即前一个控件),这时运行在网格中就可以显示数据了。
  在DataGrid属性页上勾选上运行添加新的、运行删除。

  新建一个VB工程,添加ADO对象,选择工程--引用--MS ActiveX Data Objects 2.6 Library。
  选择视图--对象浏览器,查看ADODB。
  在窗体上放一个列表框,放一个按钮。编辑按钮click过程:
Dim conn As New ADODB.Connection    'new表示已经初始化了
Dim rst As ADODB.Recordset  '没有NEW所以不能直接访问
'复制刚才控件的连接字符串
conn.ConnectionString = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;User ID=adfan;Initial Catalog=pubs"
conn.Open

Set rst = conn.Execute("select * from authors")
Do Until rst.EOF
    List1.AddItem rst("address")
    rst.MoveNext
Loop		'这时列表框就列出了address字段了

  也可直接用rst去实现:
修改上面的代码,new一个rst,然后把conn.Execute注释起来,再添加:
rst.ActiveConnection = conn		'激活的连接
rst.Open "select * from authors"	'打开……资源

  把上面两句注释起来,再定义一个:Dim cmd As New ADODB.Command
cmd.ActiveConnection = conn
cmd.CommandText = "select * from authors"
Set rst = cmd.Execute		'这样执行结果也一样

6.新建一个MFC EXE工程:Ado 基于对话框的。
  在C:\Program Files\Common Files\System\ado找到msado15.dll(这是2.6版本),拷贝文件的完整路径名(可用拖放到运行去获取),然后编写导入代码:
  在StdAfx.h后面添加:
#import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF","rsEOF")
//不要命名空间,可直接访问conn那些接口;将EOF改为rsEOF。
//利用ADO库来访问数据库,这时编译后debug中生成了msado15.tlh/tli文件。(h看成头文件;i看出源文件),可以导入它们利于查看。

  在对话框上摆放一个列表框,添加一个按钮,IDC_BTN_QUERY 查询。编辑按钮代码:
//在访问COM组件时要调用CoInitialize,用完后要用CoUninitialize。&&&
	CoInitialize(NULL);
	_ConnectionPtr pConn(__uuidof(Connection));  //uuidof获取pConn全局唯一标识符
	_RecordsetPtr pRst(__uuidof(Recordset));
//设置连接字符串
	pConn->ConnectionString="Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;User ID=adfan;Initial Catalog=pubs";
	pConn->Open("","","",adConnectUnspecified);	//前面已经设置,所以空就可以,但不能为NULL
//在asp中没有adConnectUnspecified,直接用-1即可。
	pRst=pConn->Execute("select * from authors",NULL,adCmdText);  //执行命令 返回查询记录集
	
	while(!pRst->rsEOF)
	{
		(CListBox*)GetDlgItem(IDC_LIST1)->AddString(
			(_bstr_t)pRst->GetCollect("address")); 
 //获取收集的,(_bstr_t)类中重载了char*操作符&&&
		pRst->MoveNext();
	}
	pRst->Close();
	pConn->Close();
	pRst.Release();
	pConn.Release();   //释放对象(com接口)

	CoUninitialize();

  //直接用pRst:注释掉pRst=pConn->Execute(……);
pRst->Open("select * from authors",_variant_t((IDispatch*)pConn),adOpenDynamic,adLockOptimistic,adCmdText);
	//添加这一句

  //注释掉上面的,然后用pCmd对象,再定义它:
	_CommandPtr pCmd(__uuidof(Command));
	
	pCmd->PutActiveConnection(_variant_t((IDispatch*)pConn));  //这里跟put_Active……一样的效果
	pCmd->CommandText="select * from authors";
	pRst=pCmd->Execute(NULL,NULL,adCmdText);

	pCmd.Release();  //直接Release,没有Close。

  用VC来进行ADO访问数据库,最好有COM方面的知识。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值