开发中遇到的DLL问题思考及解决方法

Advertisement

最近在公司写一个外壳程序,调用DLL插件把FORM嵌入到EXE中的一个PANEL中,其中遇到了不少的问题,大部分已经解决,还有几个至今没有找到解决方法,有待研究,也希望知道解决方法的富翁共享一下研究成果.

  以下列出的问题及解决方法仅针对我写的程序(DLL插件把FORM嵌入到EXE中的一个PANEL中),和自己的解决方法.

  从遇到的问题看出,DELPHI封装了太多的东西,有时候直接使用API会有意想不到的效果.
  经验:DLL与EXE之间的通讯应该全部使用消息.
第一个问题:Tab键和Enter键在DLL的FORM中无效

原始程序:
//frmDll为DLL中的FORM,frmEXE为EXE主窗体,下同
//下面的代码为什么直接引用Exe中的Form又引用Dll中的Form?只是为了方便阅读,实际只是传递一个句柄,下同
//panWorkSpace为Exe中的一个TPanel,DLL中的窗体要嵌入其中
frmDll.WindowState := wsMaximized;
frmDll.BorderStyle := bsNone;
windows.SetParent(frmDll.Handle,frmExe.panWorkSpace.Handle);

发现Tab及Enter键在嵌入的FORM中无效,去掉
frmDll.BorderStyle := bsNone;
后正常,但我不需要标题,就用API解决
frmDll.WindowState := wsMaximized;
SetWindowLong(frmDll.Handle,GWL_STYLE,GetWindowLong(frmDll.Handle,GWL_STYLE) and not (WS_CAPTION or WS_THICKFRAME));
windows.SetParent(frmDll.Handle,frmExe.panWorkSpace.Handle);
其中WS_CAPTION和WS_THICKFRAME分别表示标题栏和边框,问题解决.

第二个问题:DLL窗体的Resize

EXE主窗体改变尺寸时,窗体中的Panel也会跟着变(Panel.Align设为了alClient),但其中嵌入的DLL窗体不会跟着变,解决方法:
//exe窗口接收消息并改变子窗体大小
//FChildWindowList为TList,子窗体的结构信息列表
Type
//子窗体一些信息的结构体
PFormInfo = ^TFormInfo;
TFormInfo = record
Handle : HWND;
Parent : HWND;
Style : HWND;
end;

TfrmExe = class(TForm)
private
procedure WMSize(var Message:TWMSize);message WM_Size;
end;

procedure TfrmExe.WMSize(var Message: TWMSize);
//ReSize消息
var
i : Integer;
rc : TRect;
begin
inherited;
if GetWindowRect(panWorkSpace.Handle,rc) then
if Assigned(FChildWindowList) then
for i := 0 to FChildWindowList.Count - 1 do
SetWindowPos(PFormInfo(FChildWindowList[i]).Handle, 0,
0, 0, rc.Right - rc.Left, rc.Bottom - rc.Top,
SWP_NOACTIVATE);
end;

第三个问题:焦点在DLL中的窗体时,切换到其它应用程序,再点击任务栏上Application对象的按钮,不能切换过来

焦点在DLL中的窗体时,切换到其它应用程序,再点击任务栏上Application对象的按钮,不能切换过来,EXE主窗体不最小化,切换到其它程序,直接点嵌入的DLL窗体,DLL窗体获得焦点,发现Application对象在任务栏上的按钮是被按下去了,但是EXE窗体并没有被提到最前,还有,DLL窗体得到焦点时,EXE窗体的标题栏变为灰色,这些都是不符合使用习惯的,虽然不影响使用,但我觉得还是要解决.

1.DLL窗体得到焦点时,EXE窗体的标题栏变为灰色的解决方法.
DLL窗体
TfrmDll=class(TForm)
private
procedure WMActivate(var Message : TMessage);message WM_ACTIVATE;
end;

procedure TfrmDll.WMActivate(var Message: TMessage);
begin
inherited;
SendMessage(frmEXE.Handle, WM_NCACTIVATE, Integer(True), 0);
end;

2.焦点的问题解决方法
把下面这个单元加入工程
//==============================================================================
// Unit Name: AppHandler
// Author : ysai
// Date : 2003-06-05
// Purpose : 处理焦点问题
// History :
//==============================================================================

unit AppHandler;

interface

uses
Windows, Messages, SysUtils,Forms;

implementation

var
OldWProc : TFNWndProc;

function NewWndProc(
Handle : HWND;
Msg : Integer;
wParam : Longint;
lParam : Longint
):Longint; stdcall;
begin
Result := 0;
case Msg of
WM_ACTIVATEAPP : //嵌入到主窗口的DLL中的窗口得到焦点不会把程序提前
begin
case wParam of
0 : //应用程序失去焦点
begin
if Assigned(Application.MainForm)
and (GetWindowLong(Application.Handle, GWL_EXSTYLE)
and WS_EX_TOOLWINDOW = 0) then
SendMessage(
Application.MainForm.Handle,
WM_NCACTIVATE,
Integer(False),
0);//失去焦点把标题栏变灰
end;
1 : //应用程序得到焦点
begin
if Assigned(Application.MainForm)
and (GetWindowLong(Application.Handle, GWL_EXSTYLE)
and WS_EX_TOOLWINDOW = 0) then
SendMessage(
Application.MainForm.Handle,
WM_ACTIVATE,
WA_ACTIVE,
1);//注意,这里设为1,后面会用到
end; //case wParam
end;
Result := CallWindowProc(OldWProc, Handle, Msg, wParam, lParam);
end; //msg : WM_ACTIVATEAPP
else
Result := CallWindowProc(OldWProc, Handle, Msg, wParam, lParam);
end; //case msg
end;

initialization
//取代应用程序的消息处理
OldWProc := TFNWndProc(SetWindowLong(Application.Handle, GWL_WNDPROC,
Longint(@NewWndProc)));

finalization
//还原消息处理过程
if OldWProc <> nil then
SetWindowLong(Application.Handle, GWL_WNDPROC, LongInt(OldWProc));

end.
//单元结束

//EXE程序主窗口
TfrmEXE = class(TForm)
private
procedure WMActivate(var Message : TMessage);message WM_ACTIVATE;
end;

procedure TfrmExe.WMActivate(var Message: TMessage);
//激话消息,Message.lParam=1时是OAAppHandler单元发来的,激活子窗口
var
hWindow : HWND;
begin
inherited;
if Message.lParam = 1 then //如果是1就是AppHander发出的消息,将焦点设到活动子窗体
begin
hWindow := GetActiveChildWindowHandle;//这个函数得到活动子窗体
//如果有子窗口而且不存在模态显示的窗体则把焦点移到子窗体上
if (hWindow > 0) and IsWindowEnabled(Application.Handle) then
windows.SetForegroundWindow(hWindow);
end;
end;

第四个问题:SpeedButton在DLL中鼠标离开不会恢复平面(ShowModal时不会出现)(未解决)

SpeedButton.Flat设为真时,在DLL中鼠标离开不会恢复平面状态,而ShowModal时不会出现,不知道原因,应该是消息处理得不好,不知道有没有人解决过

又一个焦点问题:焦点在DLL窗体时,按Alt+Tab,对话框里出来的程序中竟然没有EXE程序!

焦点在EXE窗体上时没问题,焦点在DLL窗体上时,用Alt+Tab不会出现EXE应用程序的图标,切换到其它任务后,也不能用Alt+Tab切换回来!这是个比较大的BUG,还未找到原因

用spy++看了一下,按下Alt+Tab键,窗体收到了一个WM_CANCELMODE消息,我想,既然焦点在exe窗体上时可以看到图标,而在dll上看不到,那么我在收到这个消息时把焦点给设到exe上不就可以了?
  事实证明这点是可行的,代码如下:
TDllForm = class(TForm)
private
procedure WMCancelMode(var Message : TMessage);message WM_CANCELMODE;
end;

procedure TDllForm.WMCancelMode(var Message: TMessage);
//处理Alt+Tab键弹出的对话框中没有应用程序图标问题
begin
SetForegroundWindow(exeForm.Handle); //把exe窗体设为当前有焦点的窗体
end;

  现在不论焦点在exe的窗体上还是dll的窗体上,按Alt+Tab出现的对话框中都有应用程序的图标,但不同的是,焦点在exe的窗体上时按Alt+Tab,默认激活的是下一个应用程序,而焦点在dll窗体上时按Alt+Tab,默认激活的是第一个,也就是应用程序本身,实际激活的是exe窗体.
  虽然还是不怎么习惯,但总算把它给弄出来了,以后有好的解决方法再贴上来.

Hint的问题(未解决)

焦点在Dll中的窗体时,鼠标移动到控件上不会显示控件的Hint,而且Application.OnHint事件也不会发生,但是焦点在Exe窗体上时,把鼠标放在Dll窗体中的控件上却能显示Hint.原因还未找到:(

ALT+TAB解决了,但是那是键盘,鼠标操作还是有问题

焦点在DLL中时,用鼠标点其它应用程序,失去焦点了,再按ALT+TAB,那个该死的应用程序图标又没了,焦虑中....

Similar Posts:

  • 开发中遇到的DLL问题思考及解决方法 2008-06-27 20:49:18

    开发中遇到的DLL问题思考及解决方法 2008-06-27 20:49:18 标签:delphi Dll 休闲 职场 最近在公司写一个外壳程序,调用DLL插件把FORM嵌入到EXE中的一个PANEL中,其中遇到了不少的问题,大部分已经解决,还有几个至今没有找到解决方法,有待研究,也希望知道解决方法的富翁共享一下研究成果. 以下列出的问题及解决方法仅针对我写的程序(DLL插件把FORM嵌入到EXE中的一个PANEL中),和自己的解决方法. 从遇到的问题看出,DELPHI封装了太多的东西,有时候直接

  • Win10电脑提示丢失libcurl.dll怎么办?win10系统丢失libcurl.dll的原因及解决方法

    在Windows10系统中运行程序的时候弹出了:无法启动此程序,因为计算机中丢失libcurl.dll.尝试重新安装该程序以解决此问题,该怎么办呢?下面本站的小编给大家介绍下解决方法. 原因分析: 出现这样的错误提示,表示系统中dll文件损坏或丢失导致的 解决方法: 1.从其他相同系统的计算机的C:\Windows\SysWOW64(64位win10)或C:\Windows\System32(32位 win10)录路径中复制libcurl.dll 动态链接库文件: 也可以从百度下载对应版本系统的

  • Win7系统运行游戏提示没有找到d3d11.dll的原因及解决方法图文教程

    在Win7系统中运行程序或游戏的时候弹出了"没有找到d3d11.dll"的提示,该如何解决?下面本站的小编给大家分享下解决方法. 原因分析: 出现该提示是由于系统中缺少dll文件导致的. 解决方法: 1.去网上下载d3d11.dll文件: 2.在下载好的压缩文件网上单击右键,选择"解压到XXX": 3.打开解压得到的文件夹,将"d3d11.dll"文件单击右键,复制起来: 4.打开计算机,依次打开:C:\Windows\System32 ,将该文

  • windows下IIS加载Rewrite.dll不成功的解决方法

    windows下IIS加载Rewrite.dll不成功的解决方法 症状:加载rewrite模块后,不显示向上的绿箭头,而是向下的红箭头. 结果:加载不成功! 这个多半都是目录权限的问题! 1.Rewrite文件夹一定要有users组的默认权限 网上也有说还要加上一下两个权限的,个人觉得没必要,尽是造成安全隐晦的! 1.给Rewrite文件夹添加everyone用户,给所有权限 2.给Rewrite文件夹加上IIS_WPG用户,给默认权限 我的就只有administrators,system,us

  • ios UITableView中Cell重用机制导致内容重复解决方法

    UITableView继承自UIScrollview,是苹果为我们封装好的一个基于scroll的控件.上面主要是一个个的 UITableViewCell,可以让UITableViewCell响应一些点击事件,也可以在UITableViewCell中加入 UITextField或者UITextView等子视图,使得可以在cell上进行文字编辑. UITableView中的cell可以有很多,一般会通过重用cell来达到节省内存的目的:通过为每个cell指定一个重用标识符 (reuseIdentif

  • IE8中的原生JSON对象乱码的解决方法 转

    IE8中的原生JSON对象乱码的解决方法 2010/03/19 16:30 最近用json2.js来做客户端的JSON提交,使用了JSON.stringify()方法,结果发送到服务器端的Json里的中文变成了乱码. 查了一下资料才知道IE8支持原生的JSON对象,自带了JSON.parse与JSON.stringify两个方法.当我使用json2里的Json.stringify方法里IE默认调用了IE8的stringify方法进行了uncode编码,致使传到服务器后中文变成了乱码. 解决办法:

  • Firefox和IE中浏览一些网页字体模糊的解决方法

    Firefox中浏览一些网页字体模糊的解决方法 现象:Firefox中浏览一些网页字体模糊,其他网页不会 猜测:这些网页字体定义为Windows里面的字体,而linux没有这些字体,采用默认字体后变模糊 解决方法:Firefox=>编辑=>首选项=>内容=>字体=>高级=>取消"允许页面选择字体而无须使用上面的 设置"选项 部分IE7及以上版本.以IE为内核的第三方浏览器(如傲游 Maxthon等),浏览网页可能会出现英文字体模糊的现象 解决方法如下

  • 手机中出现java软件无法安装的解决方法

    手机中出现java软件无法安装的解决方法对手机中出现java软件无法安装或者安装到接近80%后提示无法安装,给出解决方法供参考: 1.如果手机存储卡容量不大,推荐备份重要内容后在手机上将存储卡格式化后再安装,如果内存卡比较大,参照下面方法: 2.删除手机存储卡SysteminstallRegistry目录后,试试能否安装,如不行继续下一步: 3.进入存储卡,找到PRIVATE102033E6MIDlets目录,java软件就安装在此目录下,将其下以数字字母混合命名的文件夹如10132d43目录中

  • ios tableView那些事 (十六) UITableView中Cell重用机制导致内容重复解决方法

    转自 http://www.2cto.com/kf/201308/238449.html UITableView继承自UIScrollview,是苹果为我们封装好的一个基于scroll的控件.上面主要是一个个的UITableViewCell,可以让UITableViewCell响应一些点击事件,也可以在UITableViewCell中加入UITextField或者UITextView等子视图,使得可以在cell上进行文字编辑. UITableView中的cell可以有很多,一般会通过重用cell

  • Win10系统默认应用web浏览器设置中找不到Edge选项的解决方法图文教程

    Win10系统用户反映,电脑在默认应用设置中修改web浏览器时,却发现里面没有Edge选项,这种情况怎么办呢?下面本站的小编就给大家分享下该问题的解决方法. 解决方法: 1.按"Win+X"组合键打开系统快捷菜单,在菜单中点击"控制面板": 2.将控制面板的"查看方式"设置为"大图标",在下面点击"默认程序": 3.点击"设置默认程序": 4.在程序框中选中"Microsoft