zoukankan      html  css  js  c++  java
  • DLL初步和钩子入门


    1
    首先来个静态链接库的。

    //文件:lib.h
    #ifndef LIB_H
    #define LIB_H
    extern "C" int add(int x,int y); //声明为C编译、连接方式的外部函数
    #endif
    //文件:lib.cpp
    #include "lib.h"
    int add(int x,int y)
    {
    return x + y;
    }

    这个静态链接库就一个加法操作,以后的例子都一样。extern "C" int add(int x,int y);这一句表示这个函数要被外部调用,且编译的时候以C的方式进行编译。这样外部就可以直接调用add了,如果不声明“C”,并且这个文件为CPP的,则编译的时候add函数会被编译器加上其他东西。这样调用可能出问题。

    下面是如何调用静态链接库:

    #include ".."lib.h"
    #pragma comment( lib, "..""debug""libTest.lib" )
     //指定与静态库一起连接,这句可以用包含库文件取代
    int main(int argc, char* argv[])
    {
    printf( "2 + 3 = %d", add( 2, 3 ) );
    }

    看到了吧,包括头文件,然后加入静态链接库。So easy

     

     

    2OK下面来看看,动态链接库,首先是非MFC的,就是VC6建立的时候选动态链接库,别选MFCdll

    库文件:

    extern "C" int __declspec(dllexport)add(int x, int y); 注意这个就行了,说明这是个导出函数,其他和上面一样。

    接下来是使用:

    typedef int(*lpAddFun)(int, int); //宏定义函数指针类型,lpaddfun 就代表了函数地址,不陌生吧

    int main(int argc, char *argv[])

    {
    HINSTANCE hDll;
    //DLL句柄 句柄的意思就是指向当前实例。代表了当前实例
    lpAddFun addFun; //
    函数指针
    hDll = LoadLibrary("..""Debug""dllTest.dll");
     //接下来要用dll,我们就手动加载。(即动态加载)
    if (hDll != NULL)
    {
    addFun = (lpAddFun)GetProcAddress(hDll, "add");
     //根据句柄取到函数名。addFun的类型为lpAddFun
    if (addFun != NULL)
    {
    int result = addFun(2, 3);
    printf("%d", result);
    }
    FreeLibrary(hDll);      
     //
    用完之后就释放。这就是动态加载DLL 明白了吧?
    }
    return 0;}

    加载dll-à-使用à 释放dll 3步都在程序中自己调用就是动态加载dll

    这个程序我试验了一下,如果把“C”去掉,则连接出错,找不到add,原因就是DLL连接的时候默认吧addc++连接了。连接成了形如add@fff的形式,所以GetProcAddress(hDll, "add");就找不到add了。

    还有一个很重要的问题,首先我们应该知道,一个动态链接库其实所有的实现函数都在DLL里面,同时生成的lib文件不过是指明了DLL里面有哪些可以调用的函数而已。调用DLL的工程没有加DLL的头文件和lib,他就加载了DLL,这个DLL里面已经包含了要调用的函数的实现,而我们之后在知道这个DLLADD函数的情况下直接找他,当然就不需要LIB文件了! 下面那个例子就需要加入lib,因为我们直接使用了add,就需要Libdll中找add的函数原型

    3下面来看静态调用,静态调用方式的特点是由编译系统完成对DLL的加载和应用程序结束时 DLL 的卸载。当调用某DLL的应用程序结束时,若系统中还有其它程序使用该 DLL,则WindowsDLL的应用记录减1,直到所有使用该DLL的程序都结束时才释放它。

    只看使用就行了。

    #pragma comment(lib,"dllTest.lib")
    //.lib
    文件中仅仅是关于其对应DLL文件中函数的重定位信息
    extern "C" __declspec(dllimport) add(int x,int y); //这句一般在.h文件
    int main(int argc, char* argv[])
    {
    int result = add(2,3);
    printf("%d",result);
    return 0;
    }

    就这么简单,注意要手动把dll放到该程序目录中。

    如果是导入类的话,要用class __declspec(dllimport) point

    {

    Public add();

    ………………

    }; //即类声明

    总结一下前面2个DLL,我不得不把省略的地方拿出来说一下:

    1 我省略了 DLLmain 其实每个DLL里面都应该有他,(事实上我只写了实现函数add)

    BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)

    {                                                                                           switch (ul_reason_for_call)                                                                    {
     case DLL_PROCESS_ATTACH:break; //
    进程加载这个dll时运行这里
     case DLL_THREAD_ATTACH:break;
     case DLL_THREAD_DETACH:break;
     case DLL_PROCESS_DETACH:break;
    }
    return TRUE;
    }
    这个函数就是DLL的入口点,当外面有进程或者线程调用这个DLL的时候就会执行DLLMain

    还有一个就是一般是写一个def文件来代替__declspec(dllimport)声明的导出函数。他们作用一样

    3 DLL定义的全局变量可以被调用进程访问;DLL也可以访问调用进程的全局数据,我们来看看在应用工程中引用DLL中变量的例子

    MFC DLL我暂时不讲,先来看看钩子!很牛的东西。钩子分为系统钩子和线程钩子。先看线程钩子,很简单,在一个程序里就可以搞定(普通main或者单文档或者对话框程序)

    1:初始化钩子hHook=SetWindowsHookEx(WH_MOUSE,MouseProc,0,GetCurrentThreadId());           参数说明 1 为要钩的消息类别,2为消息处理函数(回调函数) 3 后面再说 4 当前线程id 就是我们的主线程Id。。。。。。。。。。。这个钩子可以钩到该线程的所有消息!

    2:钩子消息处理函数

    LRESULT CALLBACK MouseProc (int nCode, WPARAM wParam, LPARAM lParam)
    {
    if(wParam==WM_MOUSEMOVE||wParam ==WM_NCMOUSEMOVE)  //
    是鼠标移动消息
     { /*
    随便做点什么,比如*/ }
     return CallNextHookEx(hHook,nCode,wParam,lParam); //
    传递钩子信息
    }

    3:释放钩子

    if(hHook)
    UnhookWindowsHookEx(hHook);

    下来是系统钩子,难一点,必须在一个DLL中创建系统钩子,然后其他线程调用这个DLL的钩子来截获自身的消息。所以要2个程序来实现

      1.建立钩子Mousehook.DLL 

    (1)     选择MFC AppWizard(DLL) MFC Extension DLL(共享MFC拷贝)类型

    (2)     新建一个钩子类,完成初始化钩子和停止钩子  

    类中有初始化钩子:glhHook =SetWindowsHookEx(WH_MOUSE,MouseProc,glhInstance,0);   // glhInstance为钩子函数所在的DLL句柄dwThreadId 最后一个参数指定钩子所监视的线程的线程号。对于全局钩子,该参数为NULL

     BOOL stophook(); //卸载钩子函数 (注意定义类前面要加导出还是导入,用宏做开关) 注:导入 __declspec(dllimport)

    (3)     这段代码就定义了2个共享变量,即所有调用这个DLL的线程都访问时同一个变量,而不是将变量给每一个线程拷贝一份!    #pragma data_seg("mydata")    //说明底下的是共享变量
      HHOOK glhHook=NULL;
      //安装的鼠标钩子句柄
      HINSTANCE glhInstance=NULL;
      //DLL实例句柄
      #pragma data_seg()
      在DEF文件中定义段属性:
      SECTIONS
      mydata READ WRITE SHARED  //说明mydata是共享变量

      2.建立调用系统钩子的程序

    (1)    CWnd * pwnd=GetDlgItem(IDC_EDIT1); //取得编辑框的类指针

    (2)    m_hook.starthook(pwnd->GetSafeHwnd()); //取得编辑框的窗口句柄并安装钩子 ,之后上面的钩子DLL根据这个传入的句柄来发送消息给该应用程序。                                                                                    就这么简单,超乎想象。。首先取得编辑框的指针,然后通过指针获取编辑框的句柄,当参数传给hook 即钩子。这个在dll中的类函数完成了所有要做的事情。Starthook中调用MouseProc我们就来认真看下他。

    LRESULT WINAPI MouseProc(int nCode,WPARAM wparam,LPARAM lparam)

    {

    LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *) lparam;

    if (nCode>=0)

     {

           HWND glhTargetWnd=pMouseHook->hwnd; //调用这个DLL的进程的窗口的句柄!我的理解。不能肯定

            HWND ParentWnd=glhTargetWnd;

            while (ParentWnd !=NULL)

            {

            glhTargetWnd=ParentWnd;

            ParentWnd=GetParent(glhTargetWnd); //取应用程序主窗口句柄

            }

           if(glhTargetWnd!=glhPrevTarWnd)   //如果不是新窗口就什么都不做

           {

            char szCaption[100];

           GetWindowText(glhTargetWnd,szCaption,100);     //取目标窗口标题

       if(IsWindow(glhDisplayWnd))   // glhDisplayWnd就是调用这个钩子DLL的窗口句柄。就是上面传的参数

           SendMessage(glhDisplayWnd,WM_SETTEXT,0,(LPARAM)(LPCTSTR)szCaption); //

           glhPrevTarWnd=glhTargetWnd; //保存目标窗口

           }

           }

    return CallNextHookEx(glhHook,nCode,wparam,lparam); //继续传递消息

    }

    总结一下:进程启动DLL中的设置HOOK(钩子),根据hook的设置,它就开始等待鼠标消息的到来,当线程的鼠标消息一来,hook就先于线程截获该消息,然后根据lparam结构的hwnd参数判断鼠标现在是否在一个新的窗口,如果是在一个新的窗口就将该窗口的标题发送给线程,作为文本输出。

        大家应该看到,这个钩子被设置为了全局钩子(SetWindowsHookEx的最后一个参数为0),即这个钩子是可以监视该电脑的所有鼠标消息的。只要有鼠标消息,不管是来自哪个线程,都回被我们这个可爱的钩子截获进行处理!

    具体见:http://dev.csdn.net/author/js333/75a96924e6904cd68a0a527bebe5f78c.html     钩子的类型和实现 csdn

    http://hi.baidu.com/zhanglei_186/blog/item/09e6490704a666c97a89474a.html     VC++动态链接库(DLL)编程深入浅出

  • 相关阅读:
    OO第二单元架构随笔
    OO第二单元小结
    OO第一单元小结
    OO第四单元总结
    oo第三单元总结
    OO第二单元总结
    OO第一单元总结
    OO第四单元及课程总结
    OO第三单元总结
    OO第二单元总结
  • 原文地址:https://www.cnblogs.com/SuperXJ/p/1575259.html
Copyright © 2011-2022 走看看