当前位置:C++技术网 > 精选软件 > 在dll中实现一个完整的功能窗口

在dll中实现一个完整的功能窗口

更新时间:2016-06-23 20:04:19浏览次数:1+次

    写这篇文章,又让我想起了刚毕业哪会,经理叫我写一个MFC的CView继承类,这个类完成完整的数据库管理功能,整个数据库管理功能就在dll中,dll提供给他的框架程序调用并启动数据库管理功能的执行。而且dll里的功能完全由dll控制,外部程序不干扰控制,最多就是加载dll和卸载dll这两个控制。
    然而那时我非常的菜鸟,不知道这个功能,经理明知道我是新人一个,也懒得说明一下,只是心里觉得我当时不行,不能干事情。他不说,我也不敢多问,他脾气太暴躁了,而且本来就对我就成见,所以我最后就做成了一个EXE形式的程序。最后他埋怨说,dll那个很简单呀,我很快就做好了。一直都不愿意跟我多说一句话,这个实现方法在我心里一直都是一个心结。或者说是技术阴影吧。
    在我技术提高到一定地步之后,这个技术对我来说,显然不是什么问题了。不过,一直没有总结过一篇文章。而这个实现方法,对于很多的新手来说,也一样是不知所措的,所以在此就分享出来,给新手们参考。希望你们能够快点成长,少一点打击。
    在文章《教你创建一个dll项目,非MFCdll项目》中,我已经详细的介绍了在VS中如何创建一个dll项目,而且是图文并茂的,相信你一看就懂了。不过还是需要自己创建一下。否则终究只是停留于理论而已。
    那么这里就介绍一下如何在dll中创造一个世界。当然,为了简单起见,我只是简单创建一个窗口而已。整个过程清楚了,我相信勤劳的你,可以尽可能发挥的。dll技术太常用了,不会dll开发的话,那都不好意思说自己是Windows程序员。
    我们在创建好的项目中,一个是dll的入口函数,如同main、WinMain函数一样的,代码如下:
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include <Windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH://进程第一次加载dll
        break;
    case DLL_THREAD_ATTACH://线程创建的时候做初始化工作
        break;
    case DLL_THREAD_DETACH://线程结束的时候做清理工作
        break;
    case DLL_PROCESS_DETACH://进程卸载dll
        break;
    }
    return TRUE;
}

    这段代码也是VS帮我们自动创建好的,你不需要记忆,只要理解就行了。我们简单的使用dll,则不需要在这里写代码,所以简单说一下就行了。要深入的了解,看MSDN,有很详细的解释。
    DllMain就是一个入口函数,dll加载和卸载的时候,我们经常需要对dll做一些初始化或者清理工作。我们就可以在这里执行一些代码。我们的dll都是加载到进程空间的,dll本身就是一段代码或者数据或者代码和数据,dll本身是没有办法运行的,所以要让dll里的代码运行起来,就要借助进程的线程来执行。第一步就是要进入进程空间,而这个由系统完成。
    从DllMain可以看出,不同时机执行DllMain会做不同的工作。初始化工作都做好后,进程就可以顺利的执行dll里的代码了。我们写代码时调用的各种系统函数,都是调用的dll里的函数。这个对于写过代码的人来说,太常见了。然而我们现在要做的就是在dll中写代码,让其他项目代码来调用。自然,我们在dll中,也可以调用其他dll里的代码,比如Windows函数。
    入口函数也就这么回事,简单说了一下,就是让你熟悉一下这个东西,了解一下dll入口函数的存在。这里说的东西并不多。也不是本文的重点。
    那么我们提供的函数,就在另外的cpp文件里提供,这样比较好,不要在DllMain所在的文件写,比较乱。在其他文件写的函数,只要你函数定义前加上导出修饰符就可以了,如:
extern "C" __declspec( dllexport ) void showUI(){}

    这里不讲述更多的导出方式,主要是讲解整个流程,整体上了解一下。我们现在开始写showUI这个函数。我们想在这个函数调用的时候,显示一个窗口。至于窗口的各种消息处理,这是Windows编程的事情了,我们这里只是建立一个整体流程,不做细致的功能编写。有兴趣可以自己扩展。
#include <Windows.h>
extern "C" __declspec( dllexport ) void showUI()
{
    //创建窗口
    HWND hWnd = CreateWindow("button","Dll里的窗口",WS_POPUPWINDOW | WS_CAPTION,100,100,400,300,NULL,NULL,GetModuleHandle(NULL),NULL);
    //显示窗口
    ShowWindow(hWnd,SW_SHOWNORMAL);
    MSG  msg;
    //消息循环
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

    那么showUI()的定义就是这样了。先包含Windows.h头文件,这样就可以调用Windows的API函数了,然后使用CreateWindow函数创建一个窗口。为了偷懒,我这里就使用系统的按钮窗口类创建一个按钮窗口。在实例句柄参数中,我们获取模块的句柄,使用函数GetModuleHandle即可。其他参数就不多说了。然后用ShowWindow显示我们创建好的窗口。再创建一个消息循环,整个窗口就完成了。
    当然,如果你觉得这个没有窗口过程,比较简单的话,你可以自己在这个函数里注册窗口类,然后用自己的窗口类关联窗口过程并创建窗口,在自己的窗口过程中,编写各种消息处理,从而可以完成完整的自定义的窗口。比如文件保存对话框、文件选择对话框、文件夹选择对话框都是写好的窗口组件,和我们这里写的窗口原理差不多。因为窗口相关的基本功能在窗口内部就自己完成了。
    你不止可以写一个窗口,甚至可以将一个管理系统,写在dll里。然后调用run函数,整个游戏基本骨架就出来了。然后程序员用脚本给你的dll提供的函数传递各种参数,就可以让游戏实现各种逻辑。这样也就是脚本开发游戏的大概思路了。
    写好了这个函数,我们编译dll项目,这样就产生了一个dll和lib文件。我们再创建一个控制台程序,导入lib,将dll放入源码文件夹中。然后写一个main函数,代码如下:
extern "C" void showUI();//声明外部导入函数
#pragma comment(lib,"dll_win.lib")//链接dll的lib导入库
void main()
{
    showUI();
}

    下面是程序的效果截图,在控制台程序中调用showUI显示一个窗口:

在控制台程序中调用showUI显示一个窗口

【在控制台程序中调用showUI显示一个窗口】
    是不是很简单。想窗口更加复杂,功能更加完成,那么这个是Win32编程的事情了。我们这里就是提供一个整体过程的分析。
    说到这里,算是正式为当年的问题一个正式的答复吧。在未来的日子里,我们将会攻克各种各样的问题,还会遇见更多的问题。加油吧。