⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch19.htm

📁 delphi自学的好教材!特别适合刚刚起步学习delphi的人员!同样对使用者具有参考价值!
💻 HTM
📖 第 1 页 / 共 5 页
字号:
end;exports  SayHello,  DoSomething index 99,  DoSomethingReallyCool;beginend.</PRE><H4>LISTING 19.4. DynLoad.dpr.</H4><PRE>library TestDLL;uses  SysUtils,  Classes,  Forms,  Windows;procedure MyDLLProc(Reason: Integer);begin  if Reason = DLL_PROCESS_DETACH then    { DLL is unloading. Cleanup code here. }  MessageBox(0, `DLL is unloading!',    `DLL Message', MB_OK or MB_ICONEXCLAMATION);end;procedure SayHelloDyn(AForm : TForm);begin  MessageBox(AForm.Handle, `Hello From a DLL!' + #13 +    `This DLL was loaded dynamically',    `DLL Message', MB_OK or MB_ICONEXCLAMATION); end;exports  SayHelloDyn;begin  DLLProc := @MyDLLProc;end.</PRE><H4>LISTING 19.5. CallDllU.pas.</H4><PRE>unit CallDLLU;</PRE><PRE>interfaceuses  Windows, Messages, SysUtils, Classes, Graphics,   Controls, Forms, Dialogs, StdCtrls;type  TForm1 = class(TForm)    HelloBtn: TButton;    OrdBtn: TButton;    DynamicLoadBtn: TButton;    NamedBtn: TButton;    procedure HelloBtnClick(Sender: TObject);    procedure OrdBtnClick(Sender: TObject);    procedure DynamicLoadBtnClick(Sender: TObject);    procedure NamedBtnClick(Sender: TObject);  private    { Private declarations }  public    { Public declarations }  end;var  Form1: TForm1;{ A procedure imported by name. }procedure SayHello(AForm : TForm);  external `testdll.dll';{ A procedure imported by ordinal. }procedure OrdinalProcedure;  external `testdll.dll' index 99;{ A procedure imported and renamed. }procedure CoolProcedure;  external `testdll.dll' name `DoSomethingReallyCool';implementation{$R *.DFM}procedure TForm1.HelloBtnClick(Sender: TObject);begin  SayHello(Self);end;procedure TForm1.OrdBtnClick(Sender: TObject); begin  OrdinalProcedure;end;procedure TForm1.NamedBtnClick(Sender: TObject);begin  CoolProcedure;end;procedure TForm1.DynamicLoadBtnClick(Sender: TObject);type  TSayHello = procedure(AForm : TForm);var  DLLInstance : THandle;  SayHello    : TSayHello;begin  { Load the DLL. }  DLLInstance := LoadLibrary(`DynLoad.dll');  { If loading fails then bail out. }  if DLLInstance = 0 then begin    MessageDlg(`Unable to load DLL.', mtError, [mbOK], 0);    Exit;  end;  { Assign the procedure pointer. }  @SayHello := GetProcAddress(DLLInstance, `SayHelloDyn');  { If the procedure was found then call it. }  if @SayHello &lt;&gt; nil then    SayHello(Self)  else    MessageDlg(`Unable to locate procedure.', mtError, [mbOK], 0);  { Unload the DLL. }  FreeLibrary(DLLInstance);end;end. </PRE><H2><A NAME="Heading17"></A>Using Forms in DLLs</H2><P>Your DLLs can contain forms as well as code. There isn't much difference in theway the form is created compared to the way a form in an application is created.First, I'll explain how to write a DLL containing a form. After that, I'll talk aboutthe special case of using an MDI form in a DLL.</P><P><H3><A NAME="Heading18"></A>Writing a DLL Containing a Form</H3><PRE>Writing a DLL that contains forms is not much more difficult than writing a DLL that contains code only. I believe in learning by example, so in this section, you build a DLL containing a form. Perform these steps:</PRE><DL>	<DT></DT>	<DD><B>1. </B>Create a new DLL project (remove the comments at the top of the DLL,	if desired). Save the DLL as MyForms.dpr.	<P>	<DT></DT>	<DD><B>2. </B>Choose File|New Form to create a new form for the DLL project. Add	any components you want to the form.	<P>	<DT></DT>	<DD><B>3. </B>Change the Name property of the new form to DLLForm. Save the form	as DLLFormU.pas.	<P>	<DT></DT>	<DD><B>4. </B>Switch back to the DLL source unit. Add a function called ShowForm	that creates and shows the form. Use this code:	<P></DL><BLOCKQUOTE>	<PRE>function ShowForm : Integer; stdcall;var  Form : TDLLForm;begin  Form := TDLLForm.Create(Application);  Result := Form.ShowModal;  Form.Free;end;</PRE></BLOCKQUOTE><PRE></PRE><DL>	<DT></DT>	<DD><B>5. </B>Add an exports section to the DLL and export the ShowForm function.	Here's how the exports section should look:	<P></DL><BLOCKQUOTE>	<PRE>exports  ShowForm;</PRE></BLOCKQUOTE><PRE></PRE><DL>	<DT></DT>	<DD><B>6. </B>Choose Project|Build MyForms to build the DLL. Save the DLL.	<P></DL><P>That's all there is to creating the DLL. Notice that the ShowForm function isdeclared with the stdcall keyword. This keyword tells the compiler to export thefunction using the standard call calling convention. Exporting the function as stdcallenables this DLL to be used by development environments other than Delphi.</P><P><strong>New Term:</strong> <I>Calling conventions</I> specify how the compiler shouldpass arguments when calling functions and procedures. The five primary calling conventionsare stdcall, cdecl, pascal, register, and safecall. See the &quot;Calling Conventions&quot;topic in the Delphi help file for more information on calling conventions.</P><P>Notice also that the return value of the DLL's ShowForm function is the valuereturned from the ShowModal function. This enables you to return some status informationto the calling application. Listing 19.6 shows the code for the DLL.</P><P><H4>LISTING 19.6. THE FINISHED DLL.</H4><PRE>library MyForms;uses  SysUtils,  Classes,  Forms,  DLLFormU in `DLLFormU.pas' {DLLForm};function ShowForm : Integer; stdcall;var  Form : TDLLForm;begin  Form := TDLLForm.Create(Application);  Result := Form.ShowModal;  Form.Free;end;exports  ShowForm;  beginend.</PRE><P>Now the calling application can declare the ShowForm function and call the function.Listing 19.7 shows a Delphi application that calls the MyForms DLL.</P><P><H4>LISTING 19.7. AN APPLICATION TO CALL THE MyForms DLL.</H4><PRE>unit TestAppU;interfaceuses  Windows, Messages, SysUtils, Classes, Graphics,   Controls, Forms, Dialogs, StdCtrls;type  TForm1 = class(TForm)    Button1: TButton;    procedure Button1Click(Sender: TObject);  private    { Private declarations }  public    { Public declarations }  end;var  Form1: TForm1;function ShowForm : Integer; stdcall;  external `myforms.dll';implementation{$R *.DFM}procedure TForm1.Button1Click(Sender: TObject);begin  ShowForm;end;end.</PRE><P>Notice that I used the stdcall keyword again when I declared the function in thecalling application. Because the function was exported from the DLL with stdcall,it must also be imported with stdcall. You must always import a function or procedurewith the same calling convention that you used to export it.</P><BLOCKQUOTE>	<P><HR><strong>NOTE:</strong> If your Delphi DLLs are going to be used only by Delphi applications,	you don't need to worry about using stdcall when exporting your functions and procedures.	If, however, there is a chance that your DLL will be called from a wide range of	applications, you should export your functions and procedures with stdcall. <HR></BLOCKQUOTE><H3><A NAME="Heading19"></A>Calling an MDI Form in a DLL</H3><P>Having an MDI child form in a DLL is a special case. (MDI forms are discussedon Day 4, &quot;The Delphi IDE Explored.&quot;) Let's say you have a Delphi applicationand the main form is an MDI form. If you try to use an MDI child form contained ina DLL, you will get an exception from VCL that says No MDI forms are currently active.&quot;What? But I have an MDI form in my application!&quot; Not according to VCL,you don't. Here's what happens.</P><P>When you attempt to show your MDI child form, VCL checks whether the Applicationobject's MainForm property is valid. If the MainForm property is not valid, an exceptionis thrown. So what's the problem? The MainForm is valid, right? The problem is thatthe DLL also contains an Application object, and it is the DLL Application object'sMainForm that is checked, not the application's MainForm. Because a DLL doesn't havea main form, this check will always fail.</P><P>The fix for this problem is to assign the DLL's Application object to the Applicationobject of the calling application. Naturally, this will work only if the callingapplication is a VCL application. That's not the whole story, though. Before theDLL unloads, you must also set the DLL's Application object back to its originalstate. This enables the VCL memory manager to clean up any memory allocated for theDLL. It means that you have to store the DLL's Application object pointer in a globalvariable in the DLL so that it can be restored before the DLL unloads.</P><P>Let's back up for a moment and review the steps required to show an MDI childform in a DLL:</P><DL>	<DT></DT>	<DD><B>1. </B>Create a global TApplication pointer in the DLL.	<P>	<DT></DT>	<DD><B>2. </B>Save the DLL's Application object in the global TApplication pointer.	<P>	<DT></DT>	<DD><B>3. </B>Assign the calling application's Application object to the DLL's Application	object.	<P>	<DT></DT>	<DD><B>4. </B>Create and show the MDI child form.	<P>	<DT></DT>	<DD><B>5. </B>Reset the DLL's Application object before the DLL unloads.	<P></DL><P>The first step is easy. Just place the following code near the top of your DLL'ssource unit:</P><P><PRE>var</PRE><P>DllApp : TApplication;</P><P>Be sure that you place the var keyword below the uses list in the DLL source unit.</P><P>Next, create a procedure that will do the TApplication switch and create the childform. The procedure will look like this:</P><P><PRE>procedure ShowMDIChild(MainApp : TApplication);var  Child : TMDIChild;begin  if not Assigned(DllApp) then begin    DllApp := Application;    Application := MainApp;  end;  Child := TMDIChild.Create(Application.MainForm);  Child.Show;end;</PRE><P>Examine this code for a moment. When you call this procedure, you will pass theApplication object of the calling application. If the DllApp pointer has not yetbeen assigned, you assign the DLL's Application object to the temporary pointer.Then you assign the Application object of the calling application to the DLL's Applicationobject. This check ensures that the Application object is set only once. After that,the MDI child form is created, passing the calling application's MainForm as the

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -