◆◆主程序调用DLL中的非模式窗口,怎样才能让这个非模式窗口自己关闭,并释放掉DLL,而不是从主窗口使其关闭◆◆(50分)

  • 主题发起人 主题发起人 小笨苯
  • 开始时间 开始时间

小笨苯

Unregistered / Unconfirmed
GUEST, unregistred user!
主程序以动态引入的方式调用DLL,并打开DLL中的一个非模式窗口。我现在想通过点击这个<br>非模式窗口右上角的关闭按钮(也就是那个“X”按钮)将非模式窗口自己关闭,并释放资源,<br>并使得主程序释放掉DLL。请问应该怎么做?谢谢!(最好是给出代码)<br>
 
难道没人帮我吗?[:(]
 
主程序调用DLL时将自己的句柄用参数方式传给DLL,<br>然后窗口结束时可以发送自定义消息给主程序。<br>主窗口接到消息后就释放DLL。
 
谢谢DarwinZhang大哥,我按照你的思路做了,但是又遇到新的问题啦,就是DLL中的窗口关闭了,<br>可主程序也跟着关闭了,你帮我看看,到底是怎么回事,我把代码贴出来。<br>//主程序代码<br>unit MainForm;<br><br>interface<br><br>uses<br>&nbsp; Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,<br>&nbsp; StdCtrls, AppEvnts;<br><br>type<br>&nbsp; TShowForm = function(AHandle: THandle; UniqueMsgID: Cardinal): THandle; stdcall;<br>&nbsp; TCloseForm = procedure(FormHandle: THandle); stdcall;<br><br>&nbsp; TfrmMain = class(TForm)<br>&nbsp; &nbsp; Button1: TButton;<br>&nbsp; &nbsp; Button2: TButton;<br>&nbsp; &nbsp; procedure Button1Click(Sender: TObject);<br>&nbsp; &nbsp; procedure Button2Click(Sender: TObject);<br>&nbsp; &nbsp; procedure FormCreate(Sender: TObject);<br>&nbsp; private<br>&nbsp; &nbsp; { Private declarations }<br>&nbsp; &nbsp; UniqueMsgID: Cardinal;<br>&nbsp; &nbsp; DLLHandle, FormHandle: THandle; //DLL的地址,要显示的Form的句柄<br>&nbsp; &nbsp; ShowForm: TShowForm;<br>&nbsp; &nbsp; CloseForm: TCloseForm;<br>&nbsp; public<br>&nbsp; &nbsp; { Public declarations }<br>&nbsp; &nbsp; procedure WndProc(var Msg: TMessage); override;<br>&nbsp; end;<br><br>var<br>&nbsp; frmMain: TfrmMain;<br><br>implementation<br><br>{$R *.DFM}<br><br>procedure TfrmMain.Button1Click(Sender: TObject);<br>begin<br>&nbsp; { 动态调用的过程 }<br>&nbsp; if DLLHandle = 0 then<br>&nbsp; begin<br>&nbsp; &nbsp; DLLHandle := LoadLibrary('TestDLL.dll');<br>&nbsp; &nbsp; try<br>&nbsp; &nbsp; &nbsp; if DLLHandle = 0 then<br>&nbsp; &nbsp; &nbsp; &nbsp; raise Exception.Create('装入动态链接库DLLFile.dll失败!');<br>&nbsp; &nbsp; &nbsp; { 在这里,将本次要用到的例程全部引入。对于某些必须成功装入的例程来说,如果<br>&nbsp; &nbsp; &nbsp; &nbsp; 装入失败,则立即释放DLL }<br>&nbsp; &nbsp; &nbsp; @ShowForm := GetProcAddress(DLLHandle, 'ShowForm');<br>&nbsp; &nbsp; &nbsp; if @ShowForm = nil then<br>&nbsp; &nbsp; &nbsp; &nbsp; Abort;<br>&nbsp; &nbsp; &nbsp; @CloseForm := GetProcAddress(DLLHandle, 'CloseForm');<br>&nbsp; &nbsp; &nbsp; if @CloseForm = nil then<br>&nbsp; &nbsp; &nbsp; &nbsp; Abort;<br>&nbsp; &nbsp; &nbsp; FormHandle := ShowForm(Application.Handle, UniqueMsgID);<br>&nbsp; &nbsp; except<br>&nbsp; &nbsp; &nbsp; FreeLibrary(DLLHandle);<br>&nbsp; &nbsp; &nbsp; DLLHandle := 0;<br>&nbsp; &nbsp; end;<br>&nbsp; end;<br>end;<br><br>procedure TfrmMain.Button2Click(Sender: TObject);<br>begin<br>&nbsp; if DLLHandle &lt;&gt; 0 then<br>&nbsp; begin<br>&nbsp; &nbsp; CloseForm(FormHandle);<br>&nbsp; &nbsp; FreeLibrary(DLLHandle);<br>&nbsp; &nbsp; DLLHandle := 0;<br>&nbsp; end;<br>end;<br><br>procedure TfrmMain.FormCreate(Sender: TObject);<br>begin<br>&nbsp; DLLHandle := 0;<br>&nbsp; UniqueMsgID := RegisterWindowMessage('shiwei is a girl 10:50:20');<br>end;<br><br>procedure TfrmMain.WndProc(var Msg: TMessage);<br>begin<br>&nbsp; if Msg.Msg = UniqueMsgID then<br>&nbsp; &nbsp; if DLLHandle &lt;&gt; 0 then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; CloseForm(FormHandle);<br>&nbsp; &nbsp; &nbsp; FreeLibrary(DLLHandle);<br>&nbsp; &nbsp; &nbsp; DLLHandle := 0;<br>&nbsp; &nbsp; end;<br>&nbsp; inherited WndProc(Msg);<br>end;<br><br>end.<br>//-----------------------------------------------------------------------------<br>//DLL单元代码<br>unit NonModalForm;<br><br>interface<br><br>uses<br>&nbsp; Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;<br><br>type<br>&nbsp; TfrmNonModal = class(TForm)<br>&nbsp; private<br>&nbsp; &nbsp; { Private declarations }<br>&nbsp; &nbsp; procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;<br>&nbsp; public<br>&nbsp; &nbsp; { Public declarations }<br>&nbsp; end;<br><br>function ShowForm(AHandle: THandle; UniqueMsgID: Cardinal): THandle; stdcall;<br>procedure CloseForm(FormHandle: THandle); stdcall;<br><br>exports<br>&nbsp; ShowForm, CloseForm;<br><br>var<br>// &nbsp;frmNonModal: TfrmNonModal;<br>&nbsp; UniMsgID: Cardinal;<br>//var<br>&nbsp; FormHandle: THandle;<br><br>implementation<br><br>{$R *.DFM}<br><br>function ShowForm(AHandle: THandle; UniqueMsgID: Cardinal): THandle;<br>begin<br>&nbsp; Application.Handle := AHandle;<br>&nbsp; UniMsgID := UniqueMsgID;<br>&nbsp; FormHandle := THandle(TfrmNonModal.Create(Application));<br>&nbsp; Result := FormHandle; //将新建窗体的句柄返回给主程序<br>&nbsp; with TfrmNonModal(FormHandle) do<br>&nbsp; try<br>&nbsp; &nbsp; Show;<br>&nbsp; except<br>&nbsp; &nbsp; Free;<br>&nbsp; &nbsp; Result := 0;<br>&nbsp; end;<br>end;<br><br>procedure CloseForm(FormHandle: THandle);<br>begin<br>&nbsp; if FormHandle &lt;&gt; 0 then //FormHandle &lt;&gt; 0,表示已经建立的实例,则可以执行关闭、释放<br>&nbsp; begin<br>&nbsp; &nbsp; with TfrmNonModal(FormHandle) do<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; Close;<br>&nbsp; &nbsp; &nbsp; Free;<br>&nbsp; &nbsp; end;<br>&nbsp; end;<br>end;<br><br>{ TfrmNonModal }<br><br>procedure TfrmNonModal.WMSysCommand(var Msg: TWMSysCommand);<br>begin<br>&nbsp; if Msg.CmdType = SC_CLOSE then<br>&nbsp; &nbsp; SendMessage(HWND_BROADCAST, UniMsgID, 0, 0)<br>&nbsp; else<br>&nbsp; &nbsp; inherited;<br>end;<br><br>end.
 
是不是因为在<br>function ShowForm(AHandle: THandle; UniqueMsgID: Cardinal): THandle;<br>begin<br>&nbsp; Application.Handle := AHandle;<br>.....这个函数里把DLL的Application指向了EXE主程序的Handle,而在退出DLL时<br>没有把DLL 的Application恢复过来?? 呵呵,我也不懂。你的这个DLL和EXE的调用<br>和实现我学了很多东西。谢谢!
 
wqthai:<br>&gt;&gt;而在退出DLL时没有把DLL 的Application恢复过来??<br>为什么要恢复过来呢?没有必要啊!
 
&nbsp;UniqueMsgID := RegisterWindowMessage('shiwei is a girl 10:50:20');<br>在2000下运行时没注册成功<br><br>
 
我看过别人的调用DLL窗体的过程:<br>Library单元的初始化部分先执行自定义的DLLProc<br>begin<br>&nbsp; DLLProc := @DLLEnterPoint;<br>&nbsp; DllEnterPoint(DLL_PROCESS_ATTACH);<br>&nbsp; DLLHandle := Application.Handle; &nbsp;//保存DLL的Application的Handle<br>end.<br><br>而DLLProc定义为:<br>procedure DllEnterPoint(dwReason: DWORD);<br>dwReason参数有四种类型:<br>DLL_PROCESS_ATTACH:进程进入时<br>DLL_PROCESS_DETACH进程退出时<br>DLL_THREAD_ATTACH 线程进入时<br>DLL_THREAD_DETACH 线程退出时<br>if dwReason = DLL_PROCESS_ATTACH then<br>&nbsp; Application.Handle := DLLHandle; &nbsp;//恢复<br><br>具体说我也不晓得此Application与Dll中的Application都有什么区别。<br>感觉如果不恢复过来,释放DLL时是不是将EXE的Application对象给Free掉了!<br>猜的。有没有高手给讲讲EXE和DLL的知识阿?<br>
 
jackyzhang:<br>成功了
 
是因为消息注册没有成功的原因??
 
SENDMESSAGE是要等主程序处理完释放那段过程才返回,而那时DLL已经被释放掉了,所以程序出错了<br>不能用这种发送消息的办法!
 
wqthai:<br>我这里调用DLL时不需要做什么初始化工作,所以没有必要写入口函数和初始代码,完全是两回事!<br>至于Application.Handle := AHandle;<br>这是非常正确的!!!它的目的是使DLL中的窗体在建立时,指定主程序的Application对象为父,<br>这样做的好处很多,否则,比如:DLL窗体最小化,或DLL窗体还没被释放时,主程序被强行关闭等等很多<br>时候会带来不可预料的错误!<br>试想一下,平时的应用程序,在主窗口中动态创建一个子窗口,使其父为Application,这有错吗???<br>将它关闭时还要恢复什么东西吗??<br>所以Application是绝对没有错的!!!!<br><br>现在,这个问题的80%我都做好了,只是在消息处理的问题上可能什么地方没处理正确,希望大家多多帮助!
 
&gt;&gt;SENDMESSAGE是要等主程序处理完释放那段过程才返回,而那时DLL已经被释放掉了,所以程序出错了<br>&gt;&gt;不能用这种发送消息的办法!<br>这话似乎说到点子上了,容我再看看
 
procedure TfrmMain.WndProc(var Msg: TMessage);<br>begin<br>&nbsp; if Msg.Msg = UniqueMsgID then<br>&nbsp; begin<br>&nbsp; &nbsp; if DLLHandle &lt;&gt; 0 then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; PostMessage(FrmMain.Handle,Wm_User+1,0,0);<br>&nbsp; &nbsp; end<br>&nbsp; end<br>&nbsp; else if Msg.Msg=Wm_User+1 then<br>&nbsp; &nbsp;if DllHandle&lt;&gt;0 then<br>&nbsp; &nbsp;begin<br>&nbsp; &nbsp; &nbsp; CloseForm(FormHandle);<br>&nbsp; &nbsp; &nbsp; FreeLibrary(DLLHandle);<br>&nbsp; &nbsp; &nbsp; DLLHandle := 0;<br>&nbsp; &nbsp;end;<br>&nbsp; inherited WndProc(Msg);<br>end;<br><br><br>好象这样没把内存全释放出来,在任务管理器中看到的每次都会增加内存10几K呢
 
把内存增加的问题解决好了就可以了!是4K到8K不等?
 
问题得以圆满解决!!<br>DarwinZhang首先提出用传递消息的方法,给10;<br>遂我马上写了上面的代码,但还有小问题,就是主程序也被关闭了,正在冥思苦想的时候,<br>jackyzhang提出是SendMessage的问题,非常正确!!!一语点醒梦中人啊!!!否则,我根本<br>就不王那里想,非常好!非常好!给30分!(当然,不仅仅是换成PostMessage就完了)。<br>wqthai虽然对我没有任何实质性的帮助,但鉴于积极参与,忙前忙后的,也给10分。<br>分数就这么少,如果分配得不合理,大家谅解!<br>再次感谢各位的大力帮忙!!!
 
jackyzhang:<br>&gt;&gt;把内存增加的问题解决好了就可以了!是4K到8K不等?<br>这是Windows的内存管理机制的问题,不是程序的问题,比如:数M的程序,一旦被最小化,通过<br>任务管理器一看,占用内存马上降到几百K。所以说,它显示的是不准确的。[:D]
 
但是不通过DLL调用的话,它释放,打开就不会增加,这是为什么呢?
 
to 小笨苯,<br>我也遇到这种问题,问后来你是怎么解决的
 
后退
顶部