转了人家转的文章,觉得不错,留下参考。
转载地址:http://bigpower.blog.51cto.com/209892/84395
最近在公司写一个外壳程序,调用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,那个该死的应用程序图标又没了,焦虑中....
分享到:
相关推荐
尽管本文详细介绍了Eclipse下Steps开发环境的配置,但在实际开发中,可能还会遇到各种具体问题,如不同版本的Eclipse或Tomcat的兼容性问题,或是特定项目需求下的定制化配置。因此,保持学习和适应新技术的态度,...
整本书籍将理论与实践紧密结合,通过案例学习和工具使用,使读者能够在实际工作中迅速定位问题、分析原因,并找到解决问题的方法。书中不仅提供了排错的基本技巧,还深入探讨了诸如条件断点、远程调试、调试器扩展等...
文档不仅提供了理论知识,更重要的是通过大量的案例研究,帮助读者掌握实际操作技能,从而提高排错效率和解决问题的能力。对于希望深入了解Windows平台开发的程序员来说,《Windows用户态程序高效除错》是一份不可或...
此外,文章还讨论了在开发曲线拟合软件过程中可能遇到的技术挑战和解决方法。例如,在使用LabVIEW和MATLAB进行项目开发时,团队成员需要具备跨学科的知识和技能,不仅需要了解LabVIEW和MATLAB的操作,还要具备与...
【VC007b】是针对Microsoft Visual C++编程...记得在观看教程时,结合实际动手操作,遇到问题时多思考,这样才能更好地吸收和掌握知识。建议根据自己的学习进度和兴趣,选择性地观看和下载部分视频,以便更有效地学习。
同时,解决实例中遇到的问题也能锻炼问题解决技巧和独立思考的能力。 在学习过程中,建议读者先理解书中的理论知识,然后对照光盘中的实例,一步一步地实践。同时,不要忽视错误和异常,它们往往能揭示出编程中的...
《一键修复...在遇到与Cool Edit Pro临时文件相关的错误时,用户可以依赖这个工具快速解决问题,继续无阻地进行音频创作。同时,这也反映出软件开发者对用户体验的关注,以及对软件问题解决的深度思考。
例如,尽管故事中的狐狸妹妹无法直接支持ActiveX,但主人可以通过其他方法(如使用虚拟机运行Windows系统)来解决问题。 #### 4. 技术适应与创新 - **技术创新的重要性**:随着技术的发展,新的解决方案不断出现,...
这类问题通常被称作“估算题”,它旨在考察应聘者分析问题、解决问题的能力和逻辑思维过程。应聘者需要说明自己会进行哪些调研,并基于这些调研提出合理的假设和推导过程。这类问题没有标准答案,但考察应聘者能否...
描述中提到的文章链接指向了CSDN上的一个详细教程,该文章可能介绍了如何使用chkmatch.exe工具进行校验,包括下载、安装、使用步骤以及可能遇到的问题和解决方法。通常,使用这类工具的过程可能包括以下步骤: 1. ...
本书既考虑到实际开发中经常遇到的困惑和难题,也分析了解决问题的思路和方法,更总结出项目开发中不可或缺的技术点及思想。读者可以在欣赏一个个有趣例子的过程中,不知不觉具备开发真正商业项目的能力。 本书集...
本书既考虑到实际开发中经常遇到的困惑和难题,也分析了解决问题的思路和方法,更总结出项目开发中不可或缺的技术点及思想。读者可以在欣赏一个个有趣例子的过程中,不知不觉具备开发真正商业项目的能力。 本书集...
实验报告应详细记录每一步操作,包括遇到的问题和解决方案,以及对实验结果的分析。思考题可能会引导学生深入理解中间件的原理,例如,RPC如何处理网络延迟,COM对象的生命周期是如何管理的,以及CORBA如何实现跨...
操作系统实验报告——操作系统启动与...在实验中遇到问题时,与老师和同学的交流使我学会了如何解决问题,提升了问题解决能力。同时,实验报告的撰写锻炼了我的书面表达能力,使我在理论知识与实践操作上都有所进步。
4. **技术支持**:遇到问题时,可以随时联系客服获得帮助。 #### 七、学习建议 1. **循序渐进**:按照课程安排依次学习每个章节,不要急于求成。 2. **动手实践**:理论结合实践才能真正掌握所学知识。 3. **积极...
虽然作者表示,尽管市场上有几本Delphi编程书籍,但以Delphi/Object Pascal来专门讲解面向对象编程方法学的书籍却很少,自己在寻找资料的过程中也遇到了困难,因此本书希望能填补这一空缺。 尽管本书旨在帮助寻求...
在Visual Studio 2017中使用C#调用Python脚本的实现涉及到.NET环境与Python语言之间的交互操作。...7. 遇到问题时,深入理解问题本质,分析逻辑关系,而不是盲目复制代码,以达到快速有效解决问题的目的。
3. **坑人游戏**:这类游戏往往具有一定的难度和欺骗性,可能需要玩家打破常规思维来解决问题,增加了游戏的可玩性和重玩价值。 【标签】"游戏"表明了这是一个娱乐软件,主要用于休闲和消遣,可能包含分数系统、...
**7.1 调试报告**:记录了在开发过程中遇到的问题及解决方法。 **7.2 测试结果**:展示了各种测试场景下的游戏表现,包括在不同难度级别的下用户的得分情况等。 **7.3 关键源代码**:提供了实现关键功能的源代码...