FindResource在DLL中的正确用法
场景
我在写MFC应用程序的时候,假设程序名字叫做MyApp。我在MyApp的resource.h文件中定义了一个资源的ID,如下所示
#define IDR_FILES_MYZIPFILE 3000
然后在相应的MyApp.rc文件中定义了这个资源ID所指向的资源的位置,如下:
IDR_FILES_MYZIPFILE FILES "res\\MyZip.zip"
然后我在编写我的程序的时候,我通过以下方式想要加载DLL中的资源,也就是上面所述的资源,代码如下:
HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(wResName), szResType);
if (NULL == hRes){
DWORD dErrorCode = GetLastError();
return FALSE;
}
却发现我的MyApp程序找不到这个资源。因为调试代码的时候发现hRes,为空,并且dErrorCode返回1814。1814是一个Windows自己定义的错误号,其定义在WinError.h
中,我把1814的错误解释贴出来:
//
// MessageId: ERROR_RESOURCE_NAME_NOT_FOUND
//
// MessageText:
//
// The specified resource name cannot be found in the image file.
//
#define ERROR_RESOURCE_NAME_NOT_FOUND 1814L
然后我就开始了我的面向google编程,打开chrome,搜索“FindResource调用失败”,查到的原因大致是一样的,即FindResource
这个函数在exe中传入的第一个参数为NULL时,加载的是exe这个模块本身的资源(在exe程序对应的resource.h中定义,在exe程序对应的rc文件中指定资源位置),所以是能够找到的,但是在DLL中,传入第一个参数为NULL时,其加载的资源也是exe模块的资源,所以在dll中代码调用的是这个函数其实是去exe的资源文件中找对应的资源,如果没有找到就失败,返回NULL。这里 有一种情况即使资源号在exe中有,但是szResType不匹配是不是算没找到请读者自己验证。很显然我的目的是想加载DLL中的资源,于是上网搜了FindResource在DLL的正确用法,找到结果无外乎以下这种方式:
不知道别人对这种处理方法怎么看的,我的想法如下:
- 第一、我猜想这里直接把路径写死应该是不对的,你怎么知道某个应用程序在调用你的dll的时候,二者的相对位置路径呢(当然我没有对此进行验证,有兴趣的自己验证)
- 第二、
FindResource
函数的调用是作为你Dll的一部分,直接将Dll的名字写死在这里并不合适吧。假如某一天,另外一个编写应用程序的人调用了你的DLL,然后将其改名为另外一个名字,那么就悲催了,这时候是找得到还是找不到呢,读者自己验证,。
究其以上两点,我认为以上这种处理方式是有问题的,我是不会采用的。所以后面从FindResource
的第一个参数着手,既然exe加载的是自己模块的句柄,那么我DLL的代码调用这个函数时不用exe的句柄,用自己的句柄不就好了,所以就想到了DLL程序自己有一个自己模块的句柄。
class CMyApp: public CWinApp
{
public:
CMyApp();
// 重写
public:
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
virtual int ExitInstance();
ULONG_PTR GetGdiplusToken();
protected:
GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_gdiplusToken;
};
extern CMyApp theApp;
theApp不就是代表DLL程序自己本身吗,那么找其内部的成员变量,应该就能找到这个代表本身的值: theApp.m_hInstance
。
然后我的调用如下:
HRSRC hRes = FindResource(theApp.m_hInstance, MAKEINTRESOURCE(wResName), szResType);
然后运行程序,资源果然被加载进来了。
以上是我对“FindResource在DLL中的正确用法”的一点浅薄看法,既做个人记录,也为大家提供参考,认为我所说有问题的,请告知我,文明留言。