DLL动态链接库如何共享数据和如何创建纯资源DLL
1个回答
展开全部
一、DLL动态链接库如何共享数据
上次有人问起一个关于DLL编写的问题:他创建了一个DLL动态链接库,里面写了一个鼠标钩子,用于监视鼠标左键的点击;另外创建了一个普通MFC应用程序,里面可以通过点击按钮加载这个DLL库并安装钩子。钩子的效果是:当用户在屏幕的任何地方点击鼠标左键,都会导致MFC应用程序里面的计数器的加一。可是,程序编写完后,问题出现了:当他在MFC应用程序窗口内单击鼠标左键,计数器能够成功自增;可是一旦在窗口之外的地方左击,则不能自增,即使他把那个MFC应用程序设置为了“顶级窗口”——即无论是否有焦点,始终在桌面最前端。
我开始也很不解,怀疑他是否正确创建了钩子。钩子(hook)有两种,即进程相关钩子,和全局钩子。进程相关钩子只对指定的进程起作用,例如:
SetWindowsHookEx(WH_GETMESSAGE,HookProc, hMod, dwThreadId);
而全局钩子则对所有进程起作用,例如:
SetWindowsHookEx(WH_GETMESSAGE,HookProc, hMod, NULL);
仔细查看他的代码后,发现钩子编写是正确的,将这种可能排除。
最后终于发现——这主要得益于网友Hc1的提醒,在这里说一声谢谢!——原来是在DLL工程中,有一个和计数器密切相关的变量i没有共享,也就是说,对于不同的进程,他所看到的i是不同的。我们知道,动态链接库最大的好处是不同的进程可以共享,节省内存。但是,这种共享是有条件的,也就是说,被允许共享的代码和变量才能真正被共享,否则默认的是不共享。所以在这里我们需要将i设置为共享:
#pragma data_seg(“.MyData”)
int i=0;
#pragma data_seg()
注意,被共享的变量一定要初始化,否则,编译器仍然会把它作为非共享变量。
最后,在DEF文件中添加如下语句:
SECTIONS
.MyData READ WRITE SHARED
“.MyData”表示这段共享数据的名字,可以任意,甚至是中文。
编译结束后,我们可以通过命令行运行dumpbin命令查看dll的导出情况,可以发现确实导出了数据段“.MyData”。
二、如何创建纯资源DLL
有时候,我们需要创建纯资源的DLL文件,用来储存一些资源,例如我们可以通过创建纯资源DLL来解决软件的国际化问题(DLL里面包含多国语言资源,就可以实现安装时选择用户所使用的语言这一个性化功能)。编写纯资源DLL要比编写一般的DLL简单的多,例如不需要编写DEF导出文件等。
首先新建一个Win32 DLL工程。然后用“新建”命令创建一个“Resource Script”文件,在出现的RS编辑窗口中,单击鼠标右键,就可以添加各种资源,并可以对资源进行编辑。接着,在通过“新建”创建一个Cpp文件。虽然,后面我们会看到,我们可以不对这个空白的Cpp源文件进行任何操作,但是我们仍然需要新建一个Cpp,原因我不太清除,是实验测试的时候发现的。最后,单击“Project”,再“Settings”,再“Link”,在“Project Options”编辑框里面,添加“/noentry”,以避免编译器自动为我们的资源DLL文件添加默认的_main或者DllMain入口函数。事实上,经过测试,不设置这个“noentry”,工程照样可以成功编译,也可以在其他工程中使用正常,但是大小却要增加很多,对于纯资源的DLL文件来说,这些增加的体积毫无必要,所以我们还是需要手动添加这么一个命令。
如何在在普通MFC应用程序工程中使用我们写好的纯资源DLL呢?首先,需要定义资源宏。例如,在纯资源的DLL里面有一张名为:IDB_BITMAP1的位图,那么一般VC编译器默认的资源宏定义是从100开始的,所以在纯资源DLL里面有这样的宏:
#define IDB_BITMAP1 101
这句宏定义是在Resource.h头文件当中的。
那么我们也要在MFC应用程序中定义同样的宏,否则无法加载这个位图。
然后,我们需要加载DLL文件(在这里,我们认为开始时创建的动态链接库为A.dll):
HINSTANCE hDll=LoadLibrary("A.dll");
if(hDll==NULL)
{
MessageBox(“Load Error!”);
return;
}
加载并测试是否成功,否则返回。
然后,我们就可以像在正常MFC应用程序里面添加资源一样加载DLL里面的资源了:
HBITMAP hBit=(HBITMAP)::LoadImage(hDll,
MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP,
0, 0,
LR_DEFAULTCOLOR);
if(hBit==NULL)
{
MessageBox("hBit is NULL");
return;
}
CBitmap bitmap;
bitmap.Attach(hBit);
CClientDC dc(this);
CDC dcCom;
dcCom.CreateCompatibleDC(&dc);
dcCom.SelectObject(&bitmap);
dc.BitBlt(0, 0, 500, 500, &dcCom, 0, 0, SRCCOPY);
ReleaseDC(&dcCom);
当然,最后在使用完DLL之后,不要忘了卸载DLL:
FreeLibrary(hDll);
这样就完成了。
上次有人问起一个关于DLL编写的问题:他创建了一个DLL动态链接库,里面写了一个鼠标钩子,用于监视鼠标左键的点击;另外创建了一个普通MFC应用程序,里面可以通过点击按钮加载这个DLL库并安装钩子。钩子的效果是:当用户在屏幕的任何地方点击鼠标左键,都会导致MFC应用程序里面的计数器的加一。可是,程序编写完后,问题出现了:当他在MFC应用程序窗口内单击鼠标左键,计数器能够成功自增;可是一旦在窗口之外的地方左击,则不能自增,即使他把那个MFC应用程序设置为了“顶级窗口”——即无论是否有焦点,始终在桌面最前端。
我开始也很不解,怀疑他是否正确创建了钩子。钩子(hook)有两种,即进程相关钩子,和全局钩子。进程相关钩子只对指定的进程起作用,例如:
SetWindowsHookEx(WH_GETMESSAGE,HookProc, hMod, dwThreadId);
而全局钩子则对所有进程起作用,例如:
SetWindowsHookEx(WH_GETMESSAGE,HookProc, hMod, NULL);
仔细查看他的代码后,发现钩子编写是正确的,将这种可能排除。
最后终于发现——这主要得益于网友Hc1的提醒,在这里说一声谢谢!——原来是在DLL工程中,有一个和计数器密切相关的变量i没有共享,也就是说,对于不同的进程,他所看到的i是不同的。我们知道,动态链接库最大的好处是不同的进程可以共享,节省内存。但是,这种共享是有条件的,也就是说,被允许共享的代码和变量才能真正被共享,否则默认的是不共享。所以在这里我们需要将i设置为共享:
#pragma data_seg(“.MyData”)
int i=0;
#pragma data_seg()
注意,被共享的变量一定要初始化,否则,编译器仍然会把它作为非共享变量。
最后,在DEF文件中添加如下语句:
SECTIONS
.MyData READ WRITE SHARED
“.MyData”表示这段共享数据的名字,可以任意,甚至是中文。
编译结束后,我们可以通过命令行运行dumpbin命令查看dll的导出情况,可以发现确实导出了数据段“.MyData”。
二、如何创建纯资源DLL
有时候,我们需要创建纯资源的DLL文件,用来储存一些资源,例如我们可以通过创建纯资源DLL来解决软件的国际化问题(DLL里面包含多国语言资源,就可以实现安装时选择用户所使用的语言这一个性化功能)。编写纯资源DLL要比编写一般的DLL简单的多,例如不需要编写DEF导出文件等。
首先新建一个Win32 DLL工程。然后用“新建”命令创建一个“Resource Script”文件,在出现的RS编辑窗口中,单击鼠标右键,就可以添加各种资源,并可以对资源进行编辑。接着,在通过“新建”创建一个Cpp文件。虽然,后面我们会看到,我们可以不对这个空白的Cpp源文件进行任何操作,但是我们仍然需要新建一个Cpp,原因我不太清除,是实验测试的时候发现的。最后,单击“Project”,再“Settings”,再“Link”,在“Project Options”编辑框里面,添加“/noentry”,以避免编译器自动为我们的资源DLL文件添加默认的_main或者DllMain入口函数。事实上,经过测试,不设置这个“noentry”,工程照样可以成功编译,也可以在其他工程中使用正常,但是大小却要增加很多,对于纯资源的DLL文件来说,这些增加的体积毫无必要,所以我们还是需要手动添加这么一个命令。
如何在在普通MFC应用程序工程中使用我们写好的纯资源DLL呢?首先,需要定义资源宏。例如,在纯资源的DLL里面有一张名为:IDB_BITMAP1的位图,那么一般VC编译器默认的资源宏定义是从100开始的,所以在纯资源DLL里面有这样的宏:
#define IDB_BITMAP1 101
这句宏定义是在Resource.h头文件当中的。
那么我们也要在MFC应用程序中定义同样的宏,否则无法加载这个位图。
然后,我们需要加载DLL文件(在这里,我们认为开始时创建的动态链接库为A.dll):
HINSTANCE hDll=LoadLibrary("A.dll");
if(hDll==NULL)
{
MessageBox(“Load Error!”);
return;
}
加载并测试是否成功,否则返回。
然后,我们就可以像在正常MFC应用程序里面添加资源一样加载DLL里面的资源了:
HBITMAP hBit=(HBITMAP)::LoadImage(hDll,
MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP,
0, 0,
LR_DEFAULTCOLOR);
if(hBit==NULL)
{
MessageBox("hBit is NULL");
return;
}
CBitmap bitmap;
bitmap.Attach(hBit);
CClientDC dc(this);
CDC dcCom;
dcCom.CreateCompatibleDC(&dc);
dcCom.SelectObject(&bitmap);
dc.BitBlt(0, 0, 500, 500, &dcCom, 0, 0, SRCCOPY);
ReleaseDC(&dcCom);
当然,最后在使用完DLL之后,不要忘了卸载DLL:
FreeLibrary(hDll);
这样就完成了。
本回答被提问者和网友采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
网易云信
2023-12-06 广告
2023-12-06 广告
网易云信提供一站式的 1 对 1 UIKit 组件库,可以更快地搭建 1 对 1 社交平台,能够快速实现音视频呼叫、音视频通话、1对1消息发送、美颜和礼物功能,直接可以复用我们的组件源码就可以了。优势:1、全套1对1 UI组件,接入更快;2...
点击进入详情页
本回答由网易云信提供
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询