程序开发中经常会用到一些图标、图片、光标、声音等,我们称它们为资源(Resource)。当多个窗口用到同样的资源时,可以将这些公共的资源放到一个dll文件里调用,这样,由于定位资源比在磁盘中定位文件花费时间少,所以应用程序执行会更快。多种资源放在一个文件中,减少了图标、图片、光标、声音等文件数量,从而可以减小应用程序的大小。不用怕用户在使用过程中的不小心而损坏了资源文件致使程序无法正常运行。当然也可以不编为dll,而和应用程序放一起,用到时再LoadFromFile,但这样容易丢失,一旦丢失了将影响程序的运行。

下面介绍如何将资源装入dll文件并在应用程序中调用。

一、创建资源文件

首先将要用到的资源放在同一个文件夹下,新建一记事本,将后缀名改为.rc(此处暂以rc.rc的文件名为例)。注意事项:创建的资源文件名不要和工程名相同,因为bcb创建工程时会自动创建一个和工程名相同的资源文件,并且最好将资源文件保存到和工程文件同一个文件夹中。打开创建的rc.rc文件并按照如下格式写入资源信息:

资源标识符 关键字 资源文件名

格式说明:

① 资源标识符:程序中调用资源时的特定标号,由自己定义。

② 关键字:标识资源文件类型;例如:

Wave : 资源文件是声音文件;

RCDATA: JPEG文件;

AVI : AVI动画;

ICON : 图标文件;

BITMAP: 位图文件;

CURSOR: 光标文件;

RMI : RMI音乐文件;

MIDI : MIDI音乐文件

EXEFILE:可执行文件

JPEG: jpg图片

EXEFILE: exe可执行文件

③ 资源文件名:加入的资源文件名(要带扩展名,可以带路径名构成全文件名);

④ 举例:假如有三个图形:“open.bmp”、“save.bmp”、“ico.ico”,奖在rc.rc文件里写下如下信息:

OPEN   BITMAP   open.bmp

SAVE   BITMAP   save.bmp

ICO    ICON      ico.ico

资源文件名可以不加引号,也可以加引号。保存rc.rc。

二、创建dll工程

1、在C++ Builder中新建DLL Wizard,在弹出的对话框上选择Use VCL,如下图:

 
点击“OK”后完成创建,并保存到上述资源文件所在文件夹。

2、点菜单上的“工程”/“添加到工程”(或Shift+F11),选择上述写好的rc.rc文件。

3、在Unit1.cpp里添加以下两个函数:

//-----------------------------------------------------------------------------

//加载bmp位图

extern  "C" __declspec(dllexport)  HBITMAP  __stdcall  GetBitmap(AnsiString   rcName);

HBITMAP  __stdcall  GetBitmap(AnsiString  rcName)

{ return   ::LoadBitmap(HInstance, rcName.c_str()); }

//加载ico图标

extern "C" __declspec(dllexport) HICON  __stdcall GetIcon(AnsiString);

HICON __stdcall GetIcon(AnsiString  rcName)

{ return   ::LoadIcon(HInstance, rcName.c_str());

}

//-----------------------------------------------------------------------

其中rcName为资源标识符。

4、保存工程,编译(Alt+F9),并生成Project1(Ctrl+F9)。现在便得到了Project1.dll。

三、调用dll中的资源

重新新建一工程(Application),在Form1上加两个BitBtn,并将其Caption属性分别设为“打开”和“存储”,在Form1的OnShow函数下写下如下代码:

//---------------------------------------------------------------------------

void __fastcall TForm1::FormShow(TObject *Sender)

{

HBITMAP __stdcall (*GetBitmap)(AnsiString); //定义函数原型

HICON __stdcall (*GetIcon)(AnsiString); //定义函数原型

HINSTANCE Hdl;

Hdl = ::LoadLibrary("Project1.dll"); //载入DLL

if(Hdl != NULL)

{

GetBitmap=(HBITMAP __stdcall (*)(AnsiString))::GetProcAddress(Hdl,"GetBitmap");

//取函数入口地址

if(GetBitmap!= NULL)

{BitBtn1->Glyph->Handle=GetBitmap("OPEN");

BitBtn2->Glyph->Handle=GetBitmap("SAVE");

}

GetIcon=(HICON  __stdcall (*)(AnsiString))::GetProcAddress(Hdl,"GetIcon");

//获取函数入口地址

if(GetIcon!= NULL)

{Icon->Handle= GetIcon("ICO"); }//改变窗体的图标

::FreeLibrary(Hdl);

}

else {MessageBox(Handle,"不能载入资源Project.dll!","错误",48);}

}

//---------------------------------------------------------------------------

然后运行,则窗体的图标变为资源中的图标,两个BitBtn也加载了图形。

到此已完成dll中资源的调用功能。

四、其它资源

上述只介绍了位图和图标的存取,分别用到LoadIcon和LoadBitmap,对于其它资源的存取如下:

位图:

mage1->Picture->Bitmap->Handle=LoadBitmap(HInstance,'资源标识符');

或Image1->Picture->Bitmap->LoadFromResourceName(HInstance,'资源标识符');

鼠标:

Screen->Cursors[1]=LoadCursor(HInstance,'资源标识符');

Screen->Cursors[2]=LoadCursor(HInstance,'资源标识符2');

Form1->Cursor=1; //仅用于Form1

Image1->Cursor=2;//仅用于Image1

Screen->Cursor=1;// 整个应用程序上都改变

在这里定义了两套鼠标,使用的话需要在rc文件种定义两次鼠标资源文件。

图标:

Application->Icon->Handle = LoadIcon(HInstance,'资源标识符');

AVI文件

在工程中添加一TAnimate控件(在Win32控件面板上),在需要的地方加入:

Animate1->ResName="MyAvi" ; //资源标识

Animate1->Active = True ;

实践中的一点结果:并不是所有的AVI资源都可以用TAnimate组件来播放,编定程序时要测试。遇到不能用TAnimate组件来播放的AVI资源,则可以把它从资源文件里分离出来,再使用相应的播放组件比如TMediaPlayer来播放。使用完再把分离出来的临时文件删除掉。

Wave文件

#Include"MMSystem.h"

char *wav_handle ;

HRSRC h = FindResource(HInstance,"MyWav","WAV");

HGLOBAL h1 = LoadResource(HInstance, h);

wav_handle = (char *)LockResource(h1);

PlaySound(wav_handle,NULL, SND_MEMORY | SND_ASYNC);

FreeResource(h1);

//PlaySound(wav_handle,NULL, SND_MEMORY | SND_ASYNC|SND_LOOP);

//重复播放

JPEG图片

#include"jpeg.hpp"

TJPEGImage *Fjpg=new TJPEGImage();

TResourceStream *FStream=new TResourceStream((int)HInstance,"MyJpg","JPEG");

Fjpg->LoadFromStream(FStream) ;

Image2->Picture->Bitmap->Assign(Fjpg);

EXE文件

先分离出来,再执行。

SetCurrentDir(path); //设置当前工作目录

TResourceStream &res = *new TResourceStream( (int)HInstance, AnsiString("process"),"EXEFILE" ) ;

String file=path+"//process.exe";

res.SaveToFile(file);

delete &res;

STARTUPINFO si;

PROCESS_INFORMATION pi;

ZeroMemory(&si,sizeof(si));

si.cb=sizeof(si);

ZeroMemory(&pi,sizeof(pi));

CreateProcess(file3.c_str(),NULL,NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&si,&pi);

注意,这里CREATE_NO_WINDOW为不显示窗口,根据需求设置不同的参数,请参照MSDN。

其它资源

可以把资源文件中的源文件分离出来,建立一个临时的物理文件存在于应用程序路径下,然后可以用相应类型的组件来或方法来使用该文件。当程序退出时再不忘把该临时文件删除掉。

例如:

string  tmpDirectory ;

TResourceStream  myres ;

tmpDirectory = ExtractFilePath(paramstr(0));

if (FileExists(tmpDirectory + "//Music1.RMI"))

myres = TResourceStream->Create(hinstance,"music1","RMI");

myres->SaveToFile(tmpDirectory + "Music1.RMI");//从资源文件中分离出来

myres->Free;

程序退出的时候删除:

if(FileExists(tempDirectory + '//music1.RMI'))

DeleteFile(tempDirectory + '//music1.RMI');

 
结论:这篇文章是网上的。我照着做了一遍,遇到以下问题:
1、创建DLL Wizard 的程序,编译时报错:invalid bitmap format
2、即便Remove 掉 rc资源,编译程序无错,但是没有dll 和 lib  文件生成 ,只有obj文件
3、测试dll 程序 编译报错:nonportable pointer comparsion
期待网友帮忙,非常感谢!

C++ Builder创建和调用dll中的资源的更多相关文章

  1. 在 C++Builder 工程里调用 DLL 函数

    调用 Visual C++ DLL 给 C++Builder 程序员提出了一些独特的挑战.在我们试图解决 Visual C++ 生成的 DLL 之前,回顾一下如何调用一个 C++Builder 创建的 ...

  2. 在VS2012中采用C++中调用DLL中的函数 (4)

    这两天因为需要用到VS2012来生成一个DLL代码,但是之前并没有用过DLL相关的内容,从昨天开始尝试调试DLL的文件调用,起初笔者在网络上找到了3片采用VSXXX版本进行调试的例子,相关的内容见本人 ...

  3. 在C++中调用DLL中的函数 (3)

    1.dll的优点 代码复用是提高软件开发效率的重要途径.一般而言,只要某部分代码具有通用性,就可将它构造成相对独立的功能模块并在之后的项目中重复使用.比较常见的例子是各种应用程序框架,ATL.MFC等 ...

  4. 在C++中调用DLL中的函数 (2)

    应用程序使用DLL可以采用两种方式: 一种是隐式链接,另一种是显式链接.在使用DLL之前首先要知道DLL中函数的结构信息. Visual C++6.0在VC\bin目录下提供了一个名为Dumpbin. ...

  5. 在C++中调用DLL中的函数

    如何在C++中调用DLL中的函数 应用程序使用DLL可以采用两种方式:一种是隐式链接,另一种是显式链接.在使用DLL之前首先要知道DLL中函数的结构信息.Visual C++6.0在VC\bin目录下 ...

  6. 【原创】在VS2012中采用C++中调用DLL中的函数(4)

    这两天因为需要用到VS2012来生成一个DLL代码,但是之前并没有用过DLL相关的内容,从昨天开始尝试调试DLL的文件调用,起初笔者在网络上找到了3片采用VSXXX版本进行调试的例子,相关的内容见本人 ...

  7. 在C++中调用DLL中的函数(3)

    1.dll的优点 代码复用是提高软件开发效率的重要途径.一般而言,只要某部分代码具有通用性,就可将它构造成相对独立的功能模块并在之后的项目中重复使用.比较常见的例子是各种应用程序框架,ATL.MFC等 ...

  8. 在C++中调用DLL中的函数(2)

    本文转自:http://blog.sina.com.cn/s/blog_53004b4901009h3b.html 应用程序使用DLL可以采用两种方式: 一种是隐式链接,另一种是显式链接.在使用DLL ...

  9. 在VS2012中采用C++中调用DLL中的函数(4)

    转自:http://www.cnblogs.com/woshitianma/p/3683495.html 这两天因为需要用到VS2012来生成一个DLL代码,但是之前并没有用过DLL相关的内容,从昨天 ...

随机推荐

  1. 京东云擎提供了免费的wordpress一键安装功能了

    1. 京东云擎(http://jae.jd.com)提供了免费的个人博客WordPress一键安装功能了,如下图,给开发者分享福利! 免费的应用,提供了源码,提供了数据库: 我之前把文章发到首页,遭到 ...

  2. js中如何删除json对象的某一个选项

    我有一个这样一个对象,getData, 但是我不想要每一项的id,那怎么去删除呢(使用delete)? getData.map((item) =>{ delete item["id&q ...

  3. js里面正则表示满足多个条件的写法

    实例,满足条件里面必须包含数字,字母和下划线组成 代码如下: var reg = /^([a-z]+\d+\_+)|([a-z]+\_+\d+)|(\_+[a-z]+\d+)|(\_+\d+[a-z] ...

  4. 微信开放平台全网发布时,检测失败 —— C#

    主要就是三个:返回API文本消息,返回普通文本消息,发送事件消息   --会出现失败的情况 (后续补充说明:出现检测出错,不一定是代码出现了问题,也有可能是1.微信方面检测时出现服务器请求失败,2.我 ...

  5. C/C++对Lu系统内置动态对象进行运算符重载

    欢迎访问Lu程序设计 C/C++对Lu系统内置动态对象进行运算符重载 1 说明 要演示本文的例子,你必须下载Lu32脚本系统.本文的例子需要lu32.dll.lu32.lib.C格式的头文件lu32. ...

  6. Fatal error Using $this when not in object context in

    大致意思是 $this 没有上下文,原因是没有对此类进行实例化. 出现此错误的原因是:在FileCommand.php中使用 $this->方法/属性. $this 不是不可以用,而是要看情况用 ...

  7. 基础概念 之 Hadoop Family

    Hadoop家族的技术,网上资料多如牛毛,但是还是那句老话——好脑瓜不如烂笔头,看的再多也不如自己动手写一写. Hadoop是一个分布式系统,有两个关键组件——HDFS和MapReduce,HDFS负 ...

  8. 记录用户操作历史命令history

    我们知道可以使用history命令,查看自己的操作记录,但如果你是root用户,如何查看其它用户的操作记录呢?   其实history命令只是把当前用户目录下的~/.bash_History文件内容列 ...

  9. 数据字典Data Dict

    数据字典 所有的数据表都属于数据库对象,每当创建一张数据表的时候,会自动在指定的数据字典表执行一个增加语句(这个增加语言我们是不知道的),数据字典的数据操作只能通过命令完成,不能直接使用SQL完成. ...

  10. Oracle管理监控之使用utl_mail自动邮件报警配置

    --代发邮件存储过程源码如下: CREATE OR REPLACE PROCEDURE send_mail(p_recipient VARCHAR2, -- 邮件接收人                 ...