轉自: https://blog.csdn.net/u014162133/article/details/46573873數據庫
經過安裝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 same desktop as the calling thread.windows
Syntaxapp
HHOOK SetWindowsHookEx(異步
int idHook,ide
HOOKPROC lpfn,函數
HINSTANCE hMod,測試
DWORD dwThreadId //爲零表示和全部安裝的線程相關ui
);spa
1、下面咱們來建立一個屏蔽鼠標過程的hook:
1.建立基於MFC的一個InnerHook工程項目
2.在BOOL CInnerHookerDlg::OnInitDialog()中添加hook
SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());
要得到當前線程句柄,使用函數DWORD GetCurrentThreadId(void);
3.實現鼠標過程MouseProc爲:
LRESULT CALLBACK MouseProc(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
return 1; //返回值爲一表示屏蔽鼠標過程
}
2、若是要屏蔽鍵盤消息,能夠添加以下代碼
1.在CPP文件中添加一個變量:HHOOK g_hKeyBoard;
2.在CInnerHookerDlg::OnInitDialog()中添加hook
g_hKeyBoard=SetWindowsHookEx(WH_KEYBOARD,KeyBoardProc,NULL,GetCurrentThreadId());
3.實現鍵盤過程keybroadProc爲(只屏蔽空格鍵):
4.下邊添加代碼使程序在F2鍵按下後退出。
要關閉窗口,首先要得到窗口的句柄,先聲明一個全局變量Hwnd g_hWnd,
在OnInitDialog()中把窗口句柄傳給它:
g_hWnd=m_hWnd;
接下來爲鍵盤鉤子過程添加代碼:
這時咱們只能屏蔽主線程的鍵盤消息,若是要屏蔽全部消息,就得把代碼放到動態連接庫中實現。
3、屏蔽全部線程的消息
首先要建立一個動態連接庫
1.新建一個Win32 Dynamic-Link Library項目工程Hook
獲得動態連接庫模塊的句柄有兩種方式:
方法1。DllMain函數方式:
HMODULE和HINSTANCE能夠通用
方法2。GetModuleHandle函數方式
SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("Hook"),0);
這樣咱們所安裝的鉤子過程就和運行在同一個桌面上的全部進程相關了
2.編寫MouseProc()
3.以後新建一個模塊文件Hook.def,添加代碼:
LIBRARY Hook
EXPORTS
SetHook @2 //@2用來指定序號。
4.編譯生成dll文件
接下來新建一個工程,用來測試剛纔的DLL
首先安裝一個鼠標Hook屏蔽全部的鼠標消息。
1.新建一個基於MFC對話框的項目工程HookTest
2.在BOOL CHookTestDlg::OnInitDialog()前聲明SetHook函數
_declspec(dllimport) void SetHook();
3.在Setting對話框的Link選項卡的,添加庫文件:..\Hook\Debug\Hook.lib
4.在OnInitDialog()中調用 SetHook();
5.將生成好的動態連接庫拷貝到測試程序項目工程目錄下面。
調試運行,你會發現你的鼠標壞了,全部的鼠標操做都被屏蔽了。
而後安裝一個鍵盤Hook,咱們能夠按照剛纔所作鍵盤Hook的過程在動態連接庫中也作一個Hook,
這是須要給SetHook帶上參數HWND hwnd.
在測試程序中要把函數也帶上參數,並給SetHook傳入窗口句柄 SetHook(m_hWnd)。
接着,讓程序窗口始終在其餘窗口以前,並且將它最大化,從而使用戶不能切換到窗口。
可使用SetWindowPos函數
BOOL SetWindowPos(
HWND hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
UINT uFlags
);
A window can be moved to the top of the Z-order either by setting the pWndInsertAfter parameter to &wndTopMost and ensuring that the SWP_NOZORDER flag is not set or by setting a window’s Z-order so that it is above any existing topmost windows. When a nontopmost window is made topmost, its owned windows are also made topmost. Its owners are not changed.
獲得窗口的大小,可使用函數GetSystemMetrics
int GetSystemMetrics(int nIndex);
代碼:
int cxScreen,cyScreen;
cxScreen=GetSystemMetrics(SM_CXSCREEN);
cyScreen=GetSystemMetrics(SM_CYSCREEN);
SetWindowPos(&wndTopMost,0,0,cxScreen,cyScreen,SWP_SHOWWINDOW);
SetHook(m_hWnd);
由於第一個參數設置爲&wndTopMost,這時程序始終處於頂層窗口,
無論怎樣切換窗口,咱們的窗口顯示在最前面。
4、如何實如今切換到其餘線程時,也能響應F2退出程序
在程序中,咱們屏蔽了鼠標和鍵盤,可是咱們留下了一個退出程序的後門(F2)。
前面講過動態連接庫共享性的原理,多個進程能夠共享同一份代碼與數據頁,
按道理切換到其它線程以後,按下F2應該也能夠退出程序纔對,
可是發現當切換到其餘程序後,再按F2 程序不會退出,
這是由於系統的頁面拷貝機制,若是系統發現被某線程要修改某個數據頁面,
它就會先拷貝一份頁面數據,再對新的頁面數據進行修改,
其它沒有更新數據的線程繼續使用舊的頁面數據。
好比:SetHook(HWND hwnd)中將形參傳遞給了一個全局變量g_hWnd
,那麼調用SetHook的線程將使用新的存放了hwnd的數據頁面,
而其它的線程繼續使用舊的數據頁面,因此在其它線程成爲活動窗口的時候,
按下F2時,由於沒有g_hWnd沒有傳遞到hwnd窗口,因此按下F2沒有反應。
咱們能夠經過建立一個新的節,將全局變量放到這個節當中,而後將這個節設置爲一個共享的節,
這樣全局變量就能夠在多個線程間共享,從而使切換到其餘線程時也能按下F2退出程序。
要顯示動態連接庫的節,可使用命令行: dumpbin -headers Hook.dll
如何建立一個新的節?
若是確實想在其餘程序窗口下關閉咱們的程序窗口,能夠把共享窗口句柄,使系統再也不進行頁面拷貝,方法是使用下面語句把窗口句柄設爲共享:
#pragma data_seg("MySec")//MySec是新建立的節的名字(不能超過8個字節)
HWND g_hWnd=NULL; //新變量必須初始化,不然沒有新建節的信息
#pragma data_seg() //以上爲新建節
新建立的節共享之後纔有效,共享節有兩種方法:
1.#pragma comment(linker,"/section:MySec,RWS") //設置節的屬性,讀,寫,共享
2.也能夠把#pragma comment(linker,"/section:MySec,RWS")省略。
在Hook.def中添加以下代碼:
SEGMENTS
MySec read write shared
也能對節的屬性進行設置
把SetWindowsHookEx函數的第一個參數設爲WH_GETMESSAGE,可以破解密碼。
使用Hook時要當心。
1.Hook簡介:做用是攔截某些消息,關鍵函數是SetWindowsHookEX()
2.示例程序:
1.新建一基於對話框工程,InnerHook,此過程的鉤子是隻攔截本進程的。
2.在OnInitDialog()中添加代碼:
g_hWnd=m_hWnd;
g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());設置了鼠標鉤子
g_hKeyboard=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,NULL,GetCurrentThreadId());設置了鍵盤鉤子
3.完成鉤子函數的編寫:
HHOOK g_hKeyboard=NULL;
HHOOK g_hMouse;
HWND g_hWnd=NULL;LRESULT CALLBACK MouseProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam // mouse coordinates
)
{
return 1;
}LRESULT CALLBACK KeyboardProc(
int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
)
{
//if(VK_SPACE==wParam || VK_RETURN==wParam)若是是空格鍵
/*if(VK_F4==wParam && (1==(lParam>>29 & 1)))攔截ALT+F4按鍵!
return 1;
else
return CallNextHookEx(g_hKeyboard,code,wParam,lParam);*/
if(VK_F2==wParam)按F2時程序能夠退出,這是留的後門。不然程序沒法關閉,只能用任務管理器來關閉它了。
{
::SendMessage(g_hWnd,WM_CLOSE,0,0);
UnhookWindowsHookEx(g_hKeyboard);當程序退出時最好將鉤子移除。
UnhookWindowsHookEx(g_hMouse);
}
return 1;
}
3.編寫一個屏屏蔽全部進程和全部線程的鉤子程序。聳閉飧齬匙穎匭氚滄霸贒LL中,而後被某個程序調用才行。
1.新建一個DLL工程名爲Hook
2.增長Hook.cpp
3.代碼以下:
#include <windows.h>包含頭文件HHOOK g_hMouse=NULL;
HHOOK g_hKeyboard=NULL;#pragma data_seg("MySec")新建了一個節,用於將下 面的這個變量設爲全局共享。
HWND g_hWnd=NULL;這個變量是全局共享的。
#pragma data_seg()//#pragma comment(linker,"/section:MySec,RWS")
/*HINSTANCE g_hInst;BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to the DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved // reserved
)
{
g_hInst=hinstDLL;
}*/LRESULT CALLBACK MouseProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam // mouse coordinates
)
{
return 1;攔截了鼠標消息。
}LRESULT CALLBACK KeyboardProc(
int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
)
{
if(VK_F2==wParam)若是是F2鍵,則退出。
{
SendMessage(g_hWnd,WM_CLOSE,0,0);
UnhookWindowsHookEx(g_hMouse);當退出時將鉤子卸掉。
UnhookWindowsHookEx(g_hKeyboard);
}
return 1;
}void SetHook(HWND hwnd)此函數設置了鉤子。
{
g_hWnd=hwnd;注意這種傳遞調用它的進程的句柄的方法,比較巧妙!
g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("Hook"),0);
g_hKeyboard=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,GetModuleHandle("Hook"),0);
}Hook.DEF的代碼以下:
LIBRARY Hook
EXPORTS
SetHook @2
SEGMENTS
MySec READ WRITE SHARED 也能夠設置節的屬性。
4.新建一個工程調用此鉤子函數。工程名爲HookTest,基於對話框的。在OnInitDialog()中調用SetHook(),要事先聲明_declspec(dllimport) void SetHook(HWND hwnd);
而後在Project->Setting->Link->加入..\Hook\Debug\Hook.lib,並將Hook.Dll拷貝到當前目錄。
int cxScreen,cyScreen;
cxScreen=GetSystemMetrics(SM_CXSCREEN);
cyScreen=GetSystemMetrics(SM_CYSCREEN);
SetWindowPos(&wndTopMost,0,0,cxScreen,cyScreen,SWP_SHOWWINDOW);將窗口保持在最前面。
SetHook(m_hWnd);
5.DLL的調試方法,設置斷點,而後運行時斷點時,step into便可。
4.數據庫編程
1.ODBC,ADO簡介:ADO能夠認爲是創建在ODBC上的。
ADO的三個核心對象
Connection對象
Connection對象表示了到數據庫的鏈接,它管理應用程序和數據庫之間的通訊。 Recordset和Command對象都有一個ActiveConnection屬性,該屬性用來引用Connection對象。
Command對象
Command對象被用來處理重複執行的查詢,或處理須要檢查在存儲過程調用中的輸出或返回參數的值的查詢。
Recordset對象
Recordset對象被用來獲取數據。 Recordset對象存放查詢的結果,這些結果由數據的行(稱爲記錄)和列(稱爲字段)組成。每一列都存放在Recordset的Fields集合中的一個Field對象中。
2.演示在VB中使用ADO的方法,方法比較簡單,使用方便。另外在VB中演示了Connection和Command和Recordset的方法,用這三種方法均可以執行SQL語句。
3.在VC中利用ADO訪問數據庫。
1.新建一個基於對話框的工程,名爲ADO。
2.在對話框中放一ListBox和一個Button控件。
3.在使用時須導入MSADO15.dll,方法是在StdAfx.h中#import "D:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF","rsEOF")
至少於將EOF更名爲rsEOF,是爲了不與文件中的EOF重名。而後編譯程序,將產生的debug目錄下的兩個文件MSADO15.tlh和MSADO15.tli加到工程中,其目的只是方便咱們查看而已。並非編譯須要它。
ADO也是COM組件,須初始化COM庫方法是CoInitialize(NULL);使用完後須CoUninitialize();
代碼以下:
void CAdoDlg::OnBtnQuery()
{
// TOD Add your control notification handler code here
CoInitialize(NULL);初始化
_ConnectionPtr pConn(__uuidof(Connection));產生connection智能指針
_RecordsetPtr pRst(__uuidof(Recordset));產生recordset智能指針
_CommandPtr pCmd(__uuidof(Command));產生command智能指針pConn->ConnectionString="Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initial Catalog=pubs";數據庫信息
pConn->Open("","","",adConnectUnspecified);打開數據庫//pRst=pConn->Execute("select * from authors",NULL,adCmdText);用記錄集查詢數據
//pRst->Open("select * from authors",_variant_t((IDispatch*)pConn),
// adOpenDynamic,adLockOptimistic,adCmdText);
pCmd->put_ActiveConnection(_variant_t((IDispatch*)pConn));
pCmd->CommandText="select * from authors";用這種方法也能夠查詢數據
pRst=pCmd->Execute(NULL,NULL,adCmdText);
while(!pRst->rsEOF)將查詢到的數據加到列表框咯。
{
((CListBox*)GetDlgItem(IDC_LIST1))->AddString(
(_bstr_t)pRst->GetCollect("au_lname"));
pRst->MoveNext();
}pRst->Close();
pConn->Close();
pCmd.Release();
pRst.Release();
pConn.Release();
CoUninitialize();
}
本文來自CSDN博客http://blog.csdn.net/huahuamoon/archive/2007/12/29/2002855.aspx
數據庫編程:
COM
[計] 小型可執行程序的擴展名, 串行通信端口
[域] Commercial organizations,商業組織,公司
The Component Object Model組件對象模型
ADO的三個核心對象
Connection對象
Connection對象表示了到數據庫的鏈接,它管理應用程序和數據庫之間的通訊。Recordest和Command對象都有一個ActiveConnection屬性,該屬性用來飲用Connection對象。
Command對象
Command對象被用來處理重複執行的查詢,或處理須要檢查在存儲過程調用中的輸出或返回參數的值的查詢。
Recordset對象
Recordset對象被用來獲取數據。Recordset對象存放查詢的結果,這些結果又數據的行(稱爲記錄)和列(成爲字段)組成。每一列都存放在Recordset的Fields集合中的一個Filed對象中
關於ADO數據庫鏈接方面知識的總結
一、導入庫文件
使用ADO前必須在工程的stdafx.h文件最後用直接引入符號#import引入ADO庫文件,以使編譯器能正確編譯。代碼以下:
#import "C:\Program Files\common files\system\ado\msado15.dll" no_namespace rename("EOF","EndOfFile") rename("BOF","FirstOfFile")
ADO類的定義是做爲一種資源存儲在ADO DLL(msado15.dll)中,在其內部稱爲類型庫。
類型庫描述了自治接口,以及C++使用的COM vtable接口。
當使用#import指令時,在運行時Visual C++須要從ADO DLL中讀取這個類型庫,
並以此建立一組C++頭文件。這些頭文件具備.tli 和.tlh擴展名,#import引入ADO庫文件的代碼編譯後,在項目的目錄下生成了這兩個文件。在C++程序代碼中調用的ADO類要在這些文件中定義。
程序的第三行指示ADO對象不使用名稱空間,在有些應用程序中,
因爲應用程序中的對象與ADO中的對象之間可能會出現命名衝突,因此有必要使用名稱空間。
若是要使用名稱空間,則可把第三行程序修改成: rename_namespace("AdoNS")。
第四行代碼將ADO中的EOF(文件結束)改名爲adoEOF,由於文件的結尾也是以EOF結尾的,是爲了不與定義了本身的EOF的其餘庫衝突。 至於改成什麼名字,能夠根據本身的命名習慣本身肯定。
二、初始化COM環境
OLE DB 是基於COM技術編寫的,ADO是OLE DB基礎之上的用戶程序,
OLE DB是一個COM組件,在訪問COM組件的時候須要初始化COM庫,方法以下:
(1) ::CoInitialize(NULL); //初始化OLE/COM庫環境
//對數據庫的訪問在上下代碼之間寫,下面第三步就應該寫在這裏
::CoUninitialize();//既然初始化了環境,固然必定要記得釋放他了
(2)也能夠調用MFC全局函數
AfxOleInit();
三、三大指針對象的定義和建立實例
(1)
_ConnectionPtr pConnection("ADODB.Connection");
_RecordsetPtr pRecordset("ADODB.Recordset");
_CommandPtr pCommand("ADODN.Command");
(2)
_ConnectionPtr pConnection;
_RecordsetPtr pRecordset;
_CommandPtr pCommand;
pConnection.CreateInstance(__uuidof(Connection));
pRecordset.CreateInstance(__uuidof(Recordset));
pCommand.CreateInstance(__uuidof(Command));
要產生一個智能指針對象,其實在定義的同時也能夠初始化,如:
_ConnectionPtr pConnection(__uuidof(Connection));
_ConnectionPtr 是智能指針
__uuidof() 用來獲取Connection全局惟一標識符
(3)
_ConnectionPtr pConnection;
_RecordsetPtr pRecordset;
_CommandPtr pCommand;
pConnection.CreateInstance("ADODB.Connection");
pRecordset.CreateInstance("ADODB.Recordset");
pCommand.CreateInstance("ADODB.Command");
四、打開一個鏈接
pConnection->ConnectionString = "這裏的字符串有下面四種寫法";//對鏈接字符串賦值
pConnection->Open(ConnectionString,"","",adModeUnknown); //鏈接數據庫
第二三個參數分別爲用戶的ID與密碼,
由於在鏈接字符串ConnectionCstring中已經設置好了,這裏能夠爲空。
第四個參數能夠取下面兩個參數:
adAsyncConnect
異步打開數據庫,在ASP中直接用16
adConnectUnspecified
同步打開數據庫,在ASP中直接用-1
ConnectionString根據不一樣的數據源,分別對應不一樣的寫法
(要記下來很困難,能夠在VB中利用ADO控件先鏈接好,再將其拷貝在VC中,這樣不容易出錯)
1)
訪問Access 2000
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=databaseName;User ID=userName;Password=userPassWord"
2)
訪問ODBC數據
"Provider=MADASQL;DSN=dsnName;UID=userName;PWD=userPassword;"
3)
訪問Oracle數據庫
「Provider=MSDAORA;Data Sourse=serverName;User ID=userName;Password=userPassword;"
4)
訪問MS SQL數據庫
"Provider=SQLOLEDB,Data Source=serverName;Initial Catalog=databaseName;User ID=userName;Password=userPassword;"
五、執行SQL命令,獲得數據
方法1:
pRecordset = pConnection->Execute("Select * from authors",NULL,adCmdText);
方法2:
pRecordset ->Open("Select * from authors",_
variant_t((Idispacth*) pConnection), //設置活動鏈接
adOpenDynamtic,
//遊標類型
adLockOptimistic,
//鎖的類型
adCmdText);
方法3:
pCommand->put_ActiveConnection(_variant_t((Idispatch *) pConn);
pCommand->CommandText = "Select * from authors";
pRecordset = pCmd->Execute(NULL,NULL,adCmdText);
獲得數據以後,作一個循環取得數據:
While (!pRecordset ->adoEOF)
{
Str = pRecordset->GetCollect("au_lname"));
pRst->MoveNext();
}
SQL命令比較多,可是不去考慮細節,這裏只說出通用的方法
CString strSQL;//定義SQL命令串,用來保存SQL語句
strSQL.Format("SQL statement");
而後在每一個要用到SQL命令串的方法中,使用strSQL.AllocSysString()的方法進行類型轉換
六、com的專用數據類型
variant ,bstr ,SafeArray
variant變量的範圍包括不少,它是一種變體類型,主要用於支持自動化的語言訪問,
從而在VB中很是方便地使用,可是VC中比較複雜,它使用_variant_t 進行管理
bstr是一種字符串變量,使用_bstr_t進行管理,這個類重載了char *操做符
七、關閉鏈接
if(pConnection->State); //不能屢次關閉,不然會出現錯誤
pConnection->Close();
pRecordset->Close();
pCommand.Release();
pConnection.Release();
//釋放引用計數
pRecordset.Release();
注意:調用Close()時用"->",調用Release()時要用".",爲何?
由於智能指針,_ConnectionPtr是一個重載了->運算符的類
_ConnectionPtr:它是一個接口指針模板。'.'是模板_com_ptr的函數。->是'接口函數'調用。
//forexample:
_ConnectionPtr m_Conn;
m_Conn.CreateInstance(....);//Createinterfaceinstance.
m_Conn->Open(...);//Openaconnectiontodatabase.
'->'是_com_ptr重載了的運算符.目的就是爲了讓你調用模板參數的函數.
八、結構化異常處理
ADO封裝了COM接口,因此須要進行錯誤處理
以下例:
HRESULT hr;
try
{
hr = m_pConnection.CreateInstance("ADODB.Connection");///建立Connection對象
if(SUCCEEDED(hr))
{
hr = m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb","","",adModeUnknown);///鏈接數據庫
///上面一句中鏈接字串中的Provider是針對ACCESS2000環境的,對於ACCESS97,須要改成:Provider=Microsoft.Jet.OLEDB.3.51; }
}
catch(_com_error e)///捕捉異常
{
CString errormessage;
errormessage.Format("鏈接數據庫失敗!\r\n錯誤信息:%s",e.ErrorMessage());
AfxMessageBox(errormessage);///顯示錯誤信息
}
這裏介紹了三種對象經過ADO訪問數據庫,它們均可以執行SQL語句獲取數據,但不是管那種方法獲取數據,最終都將數據放置到記錄集對象當中。