Delphi Dll 消息处理
转载:http://blog.csdn.net/lailai186/article/details/8770643
事情的导火线是GIF图片的显示. 在应用程序中, 利用三方的GIFImage.pas可以很好的显示GIF图片.
这次, 要在一个DLL中显示一个GIF图片. 还是像往常一样拖个TImage放到窗体上, 打开一个动态GIF图片. 编译, 运行.
怪了: GIF图片显示是静态的. 还以为Delphi又出Bug了. 于是又把图片放到程序主窗体上一运行, 动的. 这下头可大了!
找相关的资料, 没有.
看来事情还得自己解决: 于是专心研究起GIFImage.pas, 首先看的当然是重画部分的代码了( 呵呵, 这是我一贯的风格: 觉得是哪里出问题就先看哪里, 不管是谁的代码 ). 经过一番搜索.
把目标定位在线程上. GIFImage.pas的重画其实就是调用一个线程, 在线程内读取文件中相应的图像数据画到目标位置.
在线程内重画是调用线程的Synchronize过程. 以前知道这个过程是为了避免多个线程同时访问同一个数据或对象的. 现在得对它的执行方法做一番了解才行.
经过一翻摸索, 找到了解决方法. 在DLL的窗体上放一个TTimer控件. Interval尽量小. OnTimer只添加一行代码: CheckSynchronize;
运行. OK. 图片动起来了......( 这种方法所存的问题就不用再多说了吧. )
但接下来的一个问题却很恼火的: 在DLL的窗体上放一个TSpeedButton控件, Flat属性设置为True. 运行. 当鼠标从TSpeedButton上移过时, TSpeedButton怎么也还原不了. 试着调用它的重画等功能. 全部没用. 好几天的时间一直在思考这个问题.
后来在处理应用程序的消息的时候, 突然想到: DLL虽然有自己Application, 但它并没有自己的消息循环, 而线程的Synchronize不能执行, TSpeedButton不能还原都是因为有些消息没有得到相应的处理而导致的.
也就是说, 只要给DLL加上一个消息循环, 上面的这些问题都会全部解决.
刚开始的时候想从主程序发送消息给DLL. 可消息截取的结果是: 很多DLL里产生的消息并没有发送给主程序. 看来这个方法是行不通的. 只得另寻方法.
在看到以下几行大家很熟悉的代码后想到.
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
可不可以给DLL也加上这们的代码呢?
动手实验, 创建一个DLL, DLL里包含一个窗体DLLForm. 从DLL里导出一个函数. 加上上面的代码. 如下:
procedure InitDLL; stdcall;
begin
Application.Initialize;
Application.CreateForm(TDLLForm, DLLForm);
Application.Run;
end;
再到主程序窗体的创建事件代码如下:
procedure TForm1.FormCreate(Sender: TObject);
begin
InitDLL;
end;
运行, 结果不对. 它是先打开主窗体了... :( 郁闷. 并且 InitDLL; 也不是立即返回, 而是当DLL里主窗体关闭后才返回. 其实早就应该想到了.
把OnCreate的代码放到一个TTimer控件里. Interval为1. OnTimer的代码如下.
procedure TForm1.Timer1Timer(Sender: TObject);
begin
TTimer(Sender).Enabled := False;
InitDLL;
end;
这下可以了. 但不能让DLL里的窗体一开始就显示出来吧. 得. 再改改InitDLL. 如下:
procedure InitDLL; stdcall;
begin
Application.Initialize;
Application.ShowMainForm := False;
Application.CreateForm(TDLLForm, DLLForm);
Application.Run;
end;
主窗体不显示了, 得加上一个, 看看效果:)
再到DLL里加上一个Form( 命名为 DLLChildForm ), 在窗体上放一个TSpeedButton控件.
再给DLL导出一个函数, 如下:
procedure CreateChildForm; stdcall;
begin
with TDLLChildForm.Create(Application) do
begin
Show;
end;
end;
再到主窗体中添加一个按钮. 点击事件代码如下.
procedure TForm1.Button1Click(Sender: TObject);
begin
CreateChildForm;
end;
运行. 结果理想: TSpeedButton在鼠标移过后能还原了. 呵呵...... 真爽!
不过, 问题又来了. 程序退出时报异常了. 想一下, 哦. DLL里的窗体资源还没有释放呢. 得, 再从DLL里导出一个过程, 代码如下:
- procedure DestoryDLL; stdcall;
- var
- i: Integer;
- begin
- for i := Application.ComponentCount - 1 downto 0 do
- begin
- if Application.Components[i].ClassNameIs('TDLLChildForm') then
- begin
- TDLLChildForm(Application.Components[i]).Release;
- end;
- end;
- if DLLForm = nil then
- begin
- Exit;
- end;
- DLLForm.Release;
- DLLForm := nil;
- end;
再给主程序主窗体的OnCloseQuery添加代码如下:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
DestoryDLL;
end;
运行. 靠, 虽然DLL里的窗体全关闭了, 可主程序还是退不出啊. 换换方法, 把 DLLForm.Release; 这里改成Application.Terminate; 试试. 还是不行. 咋回事?
反复调试, 发现虽然Terminate了, 可Run仍在循环. 并没有结束.
再研究Run的代码. 呵呵. 有了.
把Application.Terminate;换成PostMessage(Application.Handle, WM_QUIT, 0, 0);
运行, 还是不行. 但Run是循环是退出了. 那哪里还会有问题呢? 该不会是窗体没有释放吧. 好, 在PostMessage前加上DLLForm.Release;这时, DestoryDLL过程的代码如下:
- procedure DestoryDLL; stdcall;
- var
- i: Integer;
- begin
- for i := Application.ComponentCount - 1 downto 0 do
- begin
- if Application.Components[i].ClassNameIs('TDLLChildForm') then
- begin
- TDLLChildForm(Application.Components[i]).Release;
- end;
- end;
- if DLLForm = nil then
- begin
- Exit;
- end;
- DLLForm.Release;
- // Application.Terminate;
- PostMessage(Application.Handle, WM_QUIT, 0, 0);
- DLLForm := nil;
- end;
运行. OK. 完美解决...
再加上线程试试( 这时InitDLL过程要改成如下, 这样才能真正的处理所有的消息 ) . 真爽. 与想像的一样.
- procedure InitDLL(AHandle: Thandle); stdcall;
- begin
- Application.Initialize;
- Application.ShowMainForm := False;
- Application.CreateForm(TDLLForm, DLLForm);
- // 保存原来的句柄
- DLLForm.Tag := Application.Handle;
- // DLL 从属的句柄 ( 如果没有此行, 线程的执行不能达到理想效果 )
- // 并且这样才能真正的让消息循环处理它应处理的所有消息
- Application.Handle := AHandle;
- Application.Run;
- Application.Handle := DLLForm.Tag;
- end;
Delphi Dll 消息处理的更多相关文章
- 在.net中调用Delphi dll的Pchar转换
Pchar是非托管代码,要在.net中调用Delphi dll中的功能,请使用MarshalAs属性告知.net调用PInvoke去转换.net中标准的string类型.如果Delphi dll是De ...
- Delphi Dll 动态调用例子(3)-仔细看一下
http://blog.163.com/bxf_0011/blog/static/35420330200952075114318/ Delphi 动态链接库的动态和静态调用 为了让人能快速的理解 静态 ...
- C# 调用Delphi dll
delphi dll 源码: library dllres; type char10 = ..] of char; TMydata = packed record id: Integer; name: ...
- Borland.Delphi.dll
Borland.Delphi.dll Borland Delphi Runtime for .NET Imports Borland.DelphiImports Borland.Delphi.Unit ...
- vb6如何调用delphi DLL中的函数并返回字符串?
1,问题描述 最近发现vb6调用delphi DLL中的函数并返回字符串时出现问题,有时正常,有时出现?号,有时干脆导致VB程序退出 -- :: 将金额数字转化为可读的语音文字:1转化为1元 ???? ...
- delphi dll调用问题
dll传递string实现方法 delphi中dll传递string的实现方法: dll项目uses第一个引用sharemem单元; 调用的项目uses第一个引用sharemem单元; 调用的单元us ...
- Delphi DLL的创建、静态及动态调用
转载:http://blog.csdn.net/welcome000yy/article/details/7905463 结合这篇博客:http://www.cnblogs.com/xumenger/ ...
- Visual Studio 调用 Delphi DLL 会退出的解决方案
新写了一个 Delphi 的 dll 供 C# 程序调用,却发现在使用 Visual Studio 2012 进行调试时,程序会在调用后自动退出. 经过对比,只需要将工程属性中“调试”一页下的“启用 ...
- C#调用Delphi DLL获取字符串(C# IntPtr 与 string互转 )
前因后果 调用一门锁的dll实现读取酒店IC卡数据,直接用Readme里的方法出错. 函数声明: 一.读卡函数 ************************ Delphi 调用 ****** ...
随机推荐
- PHP ob系列函数详解
一. 相关函数简介: 1.Flush:刷新缓冲区的内容,输出. 函数格式:flush() 说明:这个函数经常使用,效率很高. 2.ob_start :打开输出缓冲区 函数 ...
- ecshop 后台-》广告
1.后台广告宽度限制不能超过1024,高度大于1,admin/ad_position.php 第236行 || $ad_width < ) { make_json_error($_LANG['w ...
- FPS
游戏的FPS跟什么有关 http://zhidao.baidu.com/link?url=jZJoN_-MTC9fWCBSBaL5vezBp13MRSv8PdCcQMbwX5tiFGzxNEHe7UB ...
- MyEclipse for linux 破解方法
1.安装MyEclipse: uu@pc:~/desktop$ chmod +x myeclipse-pro-2014-GA-offline-installer-linux.run uu@pc:~/d ...
- JavaScript 面向对象程序设计(下)——继承与多态 【转】
JavaScript 面向对象程序设计(下)--继承与多态 前面我们讨论了如何在 JavaScript 语言中实现对私有实例成员.公有实例成员.私有静态成员.公有静态成员和静态类的封装.这次我们来讨论 ...
- 【phpcms-v9】phpcms-v9二次开发所必须知道的步骤(转载)
一.做phpcms-v9二次开发时,我们经常需要用到如下代码,所以有必须在这里注释说明一下 defined('IN_PHPCMS') or exit('No permission resources. ...
- springmvc 注解总结
1.@RequestMapping@RequestMappingRequestMapping是一个用来处理请求地址映射的注解(将请求映射到对应的控制器方法中),可用于类或方法上.用于类上,表示类中的所 ...
- [EWS]在exchange中的标识符
摘要 最近在用ews的方式开发邮箱服务,包括写邮件,查看某封邮件的详情,回复,全部回复及转发功能.在获取收件箱的时候,关于唯一标识符的问题.也有点困惑,在每个邮件item中,存在一个changeKey ...
- css使 同一行内的 文字和图片 垂直居中对齐?
设置父容器, 使 父容器 div 下的所有元素 都 垂直对齐: father-container *{ vertical-align:middle 找回密码
- Vim 的 tab 设置
文章转自:http://blog.csdn.net/shell_picker/article/details/6033023 摘自 Vim 手册: 选项:1. tabstop:表示一个 tab 显示出 ...