編譯dll依賴另一個dll-ag真人国际官网
① 用vs2015編寫c 程序,但是調用了vs2008生成的dll,有問題嗎
如何dll是用純c語言寫的,調用不會有問題;如果用dll是用c 寫的並且用到了一些依賴於編譯器實現的特徵,調用就有可能出問題。
舉個例子:
假如這個dll要你傳遞一個std::string對象,而你的代碼使用不同版本的編譯器編寫的,那麼傳遞就有可能出現運行時錯誤。這是因為不同版本的編譯器, std::string的內部實現可能不一致,所以混用會導致運行時錯誤。
② 會做hook的進!不會的別打擾 !急!!!
鉤子的本質是一段用以處理系統消息的程序,通過系統調用,把它掛入系統。鉤子的種類很多,每種鉤子可以截獲並處理相應的消息,每當特定的消息發出,在到達目的窗口之前,鉤子程序先行截獲該消息、得到對此消息的控制權。此時鉤子函數可以對截獲的消息進行加工處理,甚至可以強制結束消息的傳遞。這有點類似與mfc中的pretranslatemessage函數,所不同的是該函數只能用於攔截本進程中的消息,而對系統消息則無能為力。
二、win32系統鉤子的實現
每種類型的鉤子均由系統來維護一個鉤子鏈,最近安裝的鉤子位於鏈的開始,擁有最高的優先順序,而最先安裝的鉤子則處在鏈的末尾。要實現win32的系統鉤子,首先要調用sdk中的api函數setwindowshookex來安裝這個鉤子函數,其原型是:
hhook setwindowshookex(int idhook,
hookproc lpfn,
hinstance hmod,
dword dwthreadid);
其中,第一個參數是鉤子的類型,常用的有wh_mouse、wh_keyboard、wh_getmessage等;第二個參數是鉤子函數的地址,當鉤子鉤到任何消息後便調用這個函數;第三個參數是鉤子函數所在模塊的句柄;第四個參數是鉤子相關函數的id用以指定想讓鉤子去鉤哪個線程,為0時則攔截整個系統的消息此時為全局鉤子。如果指定確定的線程,即為線程專用鉤子。
全局鉤子函數必須包含在dll(動態鏈接庫)中,而線程專用鉤子則可包含在可執行文件中。得到控制權的鉤子函數在處理完消息後,可以調用另外一個sdk中的api函數callnexthookex來繼續傳遞該消息。也可以通過直接返回true來丟棄該消息,阻止該消息的傳遞。
使用全局鉤子函數時需要以dll為載體,vc6中有三種形式的mfc dll可供選擇,即regular statically linked to mfc dll(標准靜態鏈接mfc dll)、regular using the shared mfc dll(標准動態鏈接mfc dll)以及extension mfc dll(擴展mfc dll)。第一種dll在編譯時把使用的mfc代碼鏈接到dll中,執行程序時不需要其他mfc動態鏈接類庫的支持,但體積較大;第二種dll在運行時動態鏈接到mfc類庫,因而體積較小,但卻依賴於mfc動態鏈接類庫的支持;這兩種dll均可被mfc程序和win32程序使用。第三種dll的也是動態連接,但做為mfc類庫的擴展,只能被mfc程序使用。
三、win32 dll
win32 dll的入口和出口函數都是dllmain這同win16 dll是有區別的。只要有進程或線程載入和卸載dll時,都會調用該函數,其原型是:
bool winapi dllmain(hinstance hinstdll,dword fdwreason, lpvoid lpvreserved);其中,第一個參數表示dll的實例句柄;第三個參數系統保留;第二個參數指明了當前調用該動態連接庫的狀態,它有四個可能的值:dll_process_attach(進程載入)、dll_thread_attach(線程載入)、dll_thread_detach(線程卸載)、dll_process_detach(進程卸載)。在dllmain函數中可以通過對傳遞進來的這個參數的值進行判別,根據不同的參數值對dll進行必要的初始化或清理工作。由於在win32環境下,所有進程的空間都是相互獨立的,這減少了應用程序間的相互影響,但大大增加了編程的難度。當進程在動態載入dll時,系統自動把dll地址映射到該進程的私有空間,而且也復制該dll的全局數據的一份拷貝到該進程空間,每個進程所擁有的相同的dll的全局數據其值卻並不一定是相同的。當dll內存被映射到進程空間中,每個進程都有自己的全局內存拷貝,載入dll的每一個新的進程都重新初始化這一內存區域,也就是說進程不能再共享dll。因此,在win32環境下要想在多個進程中共享數據,就必須進行必要的設置。一種方法便是把這些需要共享的數據單獨分離出來,放置在一個獨立的數據段里,並把該段的屬性設置為共享,建立一個內存共享的dll。
四、全局共享數據的實現
可以用#pragma data_seg建立一個新的數據段並定義共享數據,其具體格式為:
#pragma data_seg ("shareddata")
hwnd sharedwnd=null;//共享數據
#pragma data_seg()
所有在data_seg pragmas語句之間聲明的變數都將在shareddata段中。僅定義一個數據段還不能達到共享數據的目的,還要告訴編譯器該段的屬性,有兩種方法可以實現該目的(其效果是相同的),一種方法是在.def文件中加入如下語句:
setctions
shareddata read write shared
另一種方法是在項目設置鏈接選項中加入如下語句:
/section:shareddata,rws
五、滑鼠鉤子程序示例
本示常式序用到全局鉤子函數,程序分兩部分:可執行程序mousedemo和動態連接庫mousehook。首先編制mfc擴展動態連接庫mousehook.dll:
(一)選擇mfc appwizard(dll)創建項目mousehook;
(二)選擇mfc extension dll(mfc擴展dll)類型;
(三)通過project菜單的addtoproject子菜單的"new…"添加頭文件mousehook.h。
(四)在頭文件中建立鉤子類:
class afx_ext_class cmousehook:public cobject
{
public:
cmousehook(); //鉤子類的構造函數
~cmousehook(); //鉤子類的析構函數
bool starthook(hwnd hwnd); //安裝鉤子函數
bool stophook(); //卸載鉤子函數
};
(五)在mousehook.cpp文件中加入#include"mousehook.h"語句;
(六)加入全局共享數據變數:
#pragma data_seg("mydata")
hwnd glhprevtarwnd=null; //上次滑鼠所指的窗口句柄
hwnd glhdisplaywnd=null; //顯示目標窗口標題編輯框的句柄
hhook glhhook=null; //安裝的滑鼠勾子句柄
hinstance glhinstance=null; //dll實例句柄
#pragma data_seg()
(七)在def文件中定義段屬性:
sections
mydata read write shared
(八)在主文件mousehook.cpp的dllmain函數中加入保存dll實例句柄的語句:
extern "c" int apientry
dllmain(hinstance hinstance, dword dwreason, lpvoid lpreserved)
{
unreferenced_parameter(lpreserved);
if (dwreason == dll_process_attach)
{
if (!afxinitextensionmole(mousehookdll, hinstance))
return 0;
new cdynlinklibrary(mousehookdll);
glhinstance=hinstance; //插入保存dll實例句柄
}
else if (dwreason == dll_process_detach)
{
afxtermextensionmole(mousehookdll);
}
return 1; // ok
}
這個函數最重要的部分是調用afxinitextensionmole(),它初始化dll使它在mfc框架中正確的工作。它需要傳遞給dllmain()的dll實例句柄和afx_extension_module結構,結構中存在著對mfc有用的信息。
(九) 類cmousehook的成員函數的具體實現:
cmousehook::cmousehook() //類構造函數
{
}
cmousehook::~cmousehook() //類析構函數
{
stophook();
}
bool cmousehook::starthook(hwnd hwnd) //安裝鉤子並設定接收顯示窗口句柄
{
bool bresult=false;
glhhook=setwindowshookex(wh_mouse,mouseproc,glhinstance,0);
if(glhhook!=null)
bresult=true;
glhdisplaywnd=hwnd; //設置顯示目標窗口標題編輯框的句柄
return bresult;
}
bool cmousehook::stophook() //卸載鉤子
{
bool bresult=false;
if(glhhook)
{
bresult= unhookwindowshookex(glhhook);
if(bresult)
{
glhprevtarwnd=null;
glhdisplaywnd=null;//清變數
glhhook=null;
}
}
return bresult;
}
(十) 鉤子函數的實現
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); //取目標窗口標題
if(iswindow(glhdisplaywnd))
sendmessage(glhdisplaywnd,wm_settext,0,(lparam)(lpctstr)szcaption);
glhprevtarwnd=glhtargetwnd; //保存目標窗口
}
}
return callnexthookex(glhhook,ncode,wparam,lparam); //繼續傳遞消息
}
編譯完成便可得到運行時所需的滑鼠鉤子的動態連接庫mousehook.dll和鏈接時用到的mousehook.lib。
六、集成
下面新建一調用滑鼠鉤子動態連接庫的鉤子可執行程序:
(一) 用mfc的appwizard(exe)創建項目mousedemo;
(二) 選擇"基於對話應用",其餘幾步均為確省;
(三) 在對話框上加入一個編輯框idc_edit1;
(四) 在mousedemo.h中加入對mousehook.h的包含語句:#include"mousehook.h";
(五) 在cmousedemodlg.h的cmousedemodlg類定義中添加私有數據成員:cmousehook m_hook;
(六) 在oninitdialog函數的"todo注釋"後添加:
cwnd * pwnd=getdlgitem(idc_edit1); //取得編輯框的類指針
m_hook.starthook(pwnd->getsafehwnd()); //取得編輯框的窗口句柄並安裝鉤子
(七)鏈接dll庫,即把mousehook.lib加入到項目設置鏈接標簽中;
(八)把mousehook.h和mousehook.lib復制到mousedemo工程目錄中,mousehook.dll復制到debug目錄下。編譯執行程序即可。當滑鼠滑過窗口時便會在編輯框中將此窗口的標題顯示出來。
結論:
系統鉤子具有相當強大的功能,通過這種技術可以對幾乎所有的windows
系統消息進行攔截、監視、處理。這種技術可以廣泛應用於各種軟體,尤其是需要
有監控、自動記錄等對系統進行監測功能的軟體。本程序只對滑鼠消息進行攔截,
相應的也可以在win32環境下對鍵盤、埠等應用此技術完成特定的功能。