如何开发自己的DLL?(100分)

  • 主题发起人 主题发起人 xjhuo
  • 开始时间 开始时间
X

xjhuo

Unregistered / Unconfirmed
GUEST, unregistred user!

我为DLL编程的问题已经苦恼好几天了,
看了几份材料,编了几个例程,仍旧不能取得预期效果,
总是编译不过去,我的具体做法如下:
先在一个FORM中写好代码;
为其建立一工程,
将工程中的PROGRAM改为LIBRARY,并将其中的
要EXPORT的过程写在PROJECT文件中的EXPORT部分,
进行编译,发现出错,出错信息不是为不能找到我的FORM,
就是需要一个宿主程序。
我真是被它搞得不耐烦了,恳请各位大侠
能够仗义直言,帮帮小弟的忙,最好能将其制作步骤
以及这当中的注意事项告之本人,
小弟在这先谢了!
 
把你的工程文件贴出来让大家分析一下
 
1.创建DLl可是使用File菜单下的New then
在Object repository上
选择DLl即可
(不用手工将 program 改成library )
2.提示需要host program,
是因为你按了运行键,DLl不能单独运行
但它可以调试(这是Delphi 3的new feature)
调试时,输入调用这个Dll的程序名即可

找不到Form就不知道为何了?
贴出你的文件吧?
btw:建议看《Delphi 3从入门到精通》关于DLL一章 P637 20章
 
哈哈,关于dll?我研究了不知多久了。
没有问题,这样搞定它:
1. 关于Form的问题,在view/Project Manager菜单中将相就的单元和Form删
除即可。建议在new app后,立即删除之。.dll中不会用到form.
2. 现在你可以改program为Library了。
3. 调试.dll时需要一个宿主程序,如果你编译后直接运行,也会得到这个
提示。你需要写一个调用这个.dll的.exe程序,编译后将它的路径填到Run/
Parameters菜单的Host app...输入条中。
4. 现在,你可以开以运行/调试这个.dll了。
 
光编译,不运行就不会又要宿主程序了!
还有,最好用他给你生成dll,而不是光把
program改为library.
我觉得,您应该把具体的程序贴上来,让大家
帮你分析!
 
光编译,不运行就不会又要宿主程序了!
还有,最好用他给你生成dll,而不是光把
program改为library.
我觉得,您应该把具体的程序贴上来,让大家
帮你分析!
 
Hi xjhou,
This is the way to create a dll with a form or forms:
1. Create a new DLL project. Save the Dll project(here ia MyDll.dpr).
2. Add a new form to MyDll project(in your case, use project manager
to add your existing form). Add any components you want to the
form.
3. Name your form and save it(here is 'TDllForm').
4. Switch back to the MyDLL source unit. Add a function called
ShowForm that creates and shows the form. Use the code bellow:
function ShowForm : Integer;
stdcall;
var
Form : TDLLForm;
begin
Form := TDLLForm.Create(Application);
Result := Form.ShowModal;//alt Form.Show;
Form.Free;
end;
5. Add an exports section to the MyDLL and export the ShowForm
function. Here's how the exports section should look:
exports
ShowForm;
6. Choose Project| Build MyDll to build the DLL. Save the DLL.
I think you can handel the rest include the debuging.
Good luck!
 
我这里有个关于DLL的比较详细的文章,由于太多
为了不影响网络的熟读邮寄给你了!
 
发不出去,只好贴上来了!
Delphi中DLL的创建和使用

1.DLL简介; 2.调用DLL; 3.创建DLL; 4.两个技巧; 5.初始化; 6.例外处理。

1、DLL简介
  DLL是Dynamic-Link Libraries(动态链接库)的缩写,库里面是一些可执行的模块以及资源(如位图、图标等)。可以认为DLL和EXE基本上是一回事,只是DLL不能直接执行,而必须由应用程序或者其他DLL调用。DLL为应用程序间的资源共享提供了方便,同时也是多语言混合编程的重要手段。由此可见学习使用DLL是Windows程序员必须掌握的一项重要技术。
<Back to Top>

2、如何调用DLL
  在Delphi中有两种方法调用DLL中的函数和过程,即外部声明或者动态加载。
<1>外部声明
  在Delphi中外部声明是访问外部例程最容易和最常用的方式,有两种声明方式:通过名字、通过索引号。举例如下:在MYDLL.DLL中有两个函数和一个过程,则其外部声明可以写成:
function test1:integer;external 'mydll';
//直接通过名称调用test1(注意名称大小写敏感)。
function test11:integer;external 'mydll' name 'test1';
//通过名称调用test1,在程序中使用新名称(原名称仍然大小写敏感)。
procedure test2;external 'mydll' index 1;
//通过索引号调用TEST2。程序中可以用与DLL中不一样的名称.
  使用外部声明的缺点是程序启动时如果找不到mydll.dll将无法运行,即使没有调用其中的模块。 动态加载的方法可以避免这种情况。
<2>动态加载
  通过调用Windows API中的相关函数,将DLL调入内存并获得指向函数或过程的指针,执行完模块后释放内存。除了节约内存外,这种方法的一个很大的优点是能处理找不到dll或者在装入过程中出错的情况。这样即使某个dll有问题,应用程序的其他部分仍然能够正常运行。动态加载的例子如下:
var hDll:THandle;
  Test1:function:integer;
begin
  hDll:=LoadLibrary('mydll.dll');
  if hDll<32 then
exit;//如果Dll无法加载则跳出
  @Test1:=GetProcAddress(hDll,MakeIntResource(1));
    //取得mydll中的第一个函数的地址。
  ...
  FreeLibrary(hDll);
end;

<Back to Top>

3、用Delphi创建DLL
  用Delphi创建一个DLL是十分简单的,首先需要新建一个DLL的Porject(如果使用Delphi3.0则可以在File->New对话框中选择DLL),当然也可以自己写,现在这个Project是这样的:
library Project1;
uses SysUtils,Classes;
begin
end.

  当然这是一个空DLL,现在让我们来加入一个函数,让他成为我们的第一个可以使用的DLL。完成后的文件是这样的:
library dll1;
uses SysUtils,Classes;
function Test1(a,b:integer):integer;
begin
Result:=a+b;
end;

exports
Test1 index 1;
begin
end.

  在这个DLL里我们声明了一个加法函数,然后用exports语句输出它,只有被输出的函数或过程能被其他程序调用。exports语句后的语法是:函数名 [index <n>],index <n>是为函数手工指定索引号,以便其他程序确定函数地址;也可以不指定,如果没有使用Index关键字,Delphi将按照exports后的顺序从1开始自动分配索引号。现在我们可以调用这个DLL了,下面给出一个实例,运行后form1的标题将变成“1+2=3”:
声明部分:function Test1(a,b:integer):integer;external 'dll1';
       注意此处是大小写敏感的。
运行部分:form1.caption:='1+2='+inttostr(test1(1,2));

<Back to Top>

4、使用DLL的两个技巧
<1>把现有的项目改成DLL
  学会制作DLL以前,大多数程序员手中都积攒下来不少已经完成了的项目,如果现在需要把这些项目做成DLL而不是可执行文件,重新写一遍显然是没有必要的,只要按照下面的步骤对已有的项目文件进行修改就可以了:
  ① 打开项目文件(.DPR),删除单元底部begin
和end.
之间的所有语句(一般情况下这些语句是由Delphi自动生成的)。如果项目中没有用到Form,则从uses子句中删除表单单元(Form),然后转到第③步。
  ② 对项目进行修改,令除Main Form之外的所有Form都是动态生成的,这样我们只要在DLL输出的一个函数或者过程中生成Main Form,即可调用执行整个项目。我们假设Main Form的名字是MyMainForm,项目的名字是MyDll,现在在单元底部的begin
语句之前加入一个过程,过程的名字为RunMyDll,这个过程将动态生成Main Form,从而运行整个项目。RunMyDll的写法如下:
    procedure InitDll2;
    begin
    Application.CreateForm(TMyMainForm, MyMainForm);
    MyMainForm.Show;
//如果MyMainForm不可视则需要这一句.
    end;
  ③ 如果想要输出其他函数或者过程,而原来的项目中没有,则可以在单元底部的begin
语句之前加入这些代码。
  ④ 在单元底部的begin
语句之前加入一个exports小节,然后写出所有想要输出的函数或过程的名字(最好指定索引号)。注意如果执行了第②步,一定要输出RunMyDll过程。
  ⑤ 将项目文件顶部的保留字program改为library。
  ⑥ 编译。
  现在就可以在其他程序中调用本项目中的函数和过程了,只要执行RunMyDll就可以执行这个项目,和执行原来的可执行文件一模一样。
<2>创建一个引入文件
  如果DLL比较复杂,则为它的声明专门创建一个引入程序单元将是十分有意义的,并且会使这个DLL变得更加容易维护。引入单元的格式如下:
  unit MyImport;
{Import unit for MyDll.Dll}
  interface
  procedure RunMyDll;
  implementation
  procedure RunMyDll;external 'MyDll' index 1;
  end.
这样以后想要使用MyDll中的例程时,只要简单的在程序模块中的uses子句中加上MyImport即可。
<Back to Top>

5、DLL的初始化和善后工作
  一般的DLL不需要做初始化和善后工作,因此大部分读者可以跳过这一节。但如果你想让你的DLL在被载入时先作一些初始设定,或者退出时释放资源,则可以有三种方法达到目的:
<1>利用Unit的Initalization与Finalization这两个小节
  可以在Unit的这两个小节中安排Unit的进入和退出,但是Program与Library并没有这两个部分,所以只能写在Unit中。
<2>利用ExitProc变量
  在Library的begin
..end.
中间是可以写代码的,这里可以放置DLL初始化代码。如果想要做善后工作,则可以利用ExitProc变量。我们首先在初始化代码中把ExitProc中包含的默认的善后过程地址保存下来,然后把自定义的过程的地址赋给它,这样DLL退出时就会执行我们制定的程序;在自定义的过程的最后,把ExitProc恢复原来的默认值,以便DLL能够继续完成原来默认的善后工作。下面是示例:
  library MyDLL;
  ...
  OldExitProc: pointer;
  ...
  procedure MyExitProc;
  begin
  ... //善后程序
  ExitProc := OldExitProc;
  end;
  ...
  begin
  ... //初始化程序
  OldExitProc := ExitProc;
  ExitProc := @MyExitProc;
  end.

<3>利用DllProc变量
  和ExitProc一样,DllProc也是一个在Systemd单元中预定义的变量。在使用DLLProc时, 必须先写好一个具有以下原型的程序:
  procedure DLLHandler(Reason: integer);
并在library的begin
..end.
之间, 将这个DLLHandler程序的执行地址赋给DLLProc中, 这时就可以根据参数Reason的值分别作出相应的处理。另外注意要将Windows单元加入uses子句。示例如下:
  library TestDLL;
  ...
  procedure MyDLLHandler(Reason: integer);
  begin
   case Reason of
    DLL_Process_Attach: //整个DLL的初始化代码
    DLL_Process_Detach: //整个DLL的善後程序
    DLL_Thread_Attach: //当主叫端开始一个Thread时
    DLL_Thread_Detach: //当主叫端终止一个Thread时
   end;
  end;
  ...
  begin
  ... //初始化代码
  DLLProc := @MyDLLHandler;
  MyDLLHandle(DLL_Process_Attach);
  end.
由上例可以知道,当DLL支援多进程(Thread)的处理时, DllProc非常适合使用。
<Back to Top>

6、DLL中的例外处理
  在用Delphi制作DLL时, 在例外处理方面请留意以下三点:
如果uses子句中没有SysUtils话,无法使用例外处理。
如果DLL中没有对例外进行处理的话,这个例外会想完传导到主叫端的应用程序。如果该应用程序也是Delphi写的话, 这个例外可以由主叫端进行处理。
承上, 如果主叫端的程式不是Delphi或Borland C++ Builder,则例外以作业系统错误的形式来处理,例外编号是$0EEDFACE,ExceptionInformation中第一个进入点是例外发生的地址,第二个进入点是指向的Delphi例外物件的引用。
<Back to Top>

本文参考了钱达智先生(Wolfgang Chien)的技术文章,以及《Delphi for Windows Power Toolkie》([美]Harold Davis著)

出处 http://www.nease.net/~ganglion
 
huizhang的回答是正确的,在DLL中是可以有Form的,将重用的Form做进DLL
是一个不错的想法。
 
DLL编写入门级,我最近也因使用HOOK的原因刚学起来。
动态链接库(DLL)是Windows中最重要的部分之一,Windows中的运
行程序可以共享DLL中的子例程,从而使应用程序可以共享代码,减少
内存占用。本文简要介绍用Delphi创建及使用DLL。
一、创建动态链接库
1.建立一个新的工程文件
由于此工程只是个库文件,因此并不需要Form。首先选择主菜单V
iew|Project Manage, 将自动生成的Unit1及Form1移去,然后选择Fil
e|Save Project As,将此工程取名为 Mydl.d pr存盘(命名可任意 ),
当系统提问是否保存Unit1时回答‘NO’,再选择View|Projectourc
e,将其代码修改如下:
library Mydll;
uses WinTypes;
begin
end.
此文件与一般工程文件主要不同之处在于将标识符"program"改
为"library"。
2.向动态链接库中加入被多个应用程序公用的子例程(过程及函
数 )
建立一个新的Unit,将被多个应用程序公用的子例程在这里声明
及实现。注意在这个Ui t的Interface部分声明的例程尾部要加关键
字"export",表示此例程能够被"引出",也就是能被其它应用程序调用
。例如:有一个公用函数Plus,其作用是将两个整数求和,此Unit的代
码如下:
Unit Content;
{公用例程单元,命名可任意}
interface
function plus (a,b:integer):integer;export;
implementation
function plus (a,b:integer):integer;
begin
Result:=a+b;
end;
end.

3.引出公用例程
选择View|Project Source,在Mydll.dpr的uses部分之后加入:
exports
plus;
{将公用例程引出}
完整的工程文件如下:
library Mydll;
uses WinTypes,
Content in ‘CONTENT.PAS’;
exports
plus;
begin
end.
以上就完成了DLL库的创建,选择Compile将其编译。
二、使用动态链接库
DLL中的资源可以被多个EXE文件公用,现在可以用Delphi建立多
个应用程序,共同使用y dll.dll中的函数Plus:
1.建立一个新的工程文件 Usedll.dpr, 移去所有的Unit及Form

2.为引用 Mydll.dll 中的函数Plus,建立一个新的Unit,其目的
是为了说明要引用的例程存在于哪个DLL库中(用关键字"external"),
此Unit的代码如下:
Unit useunit;
{这是使用DLL的单元}
interface
function plus (a,b:integer):integer;
implementation
function plus;
external ‘Mydll’;
{说明这个函数是在外部Mydll.dll库中实现的}
end.
可以看出,对于外部例程,在interface部分的声明与普通例程一
样,但是在implementai on部分要使用关键字"external",表示此例程
是在程序外部实现的。
3.在需要使用函数Plus的Unit中,只要在其Implementation部分
用Uses将useunit包含进来即可。
例如:新建一Form,加入Edit及Button控件,为Button增加OnClick
事件,此Form对应Uni的implementation代码如下:
implementation
{$R *.DFM}
uses useunit;
{包含useunit单元}
procedure TForm1.Button1Click(Sender: TObject);
{Button1的OnClick事件}
begin
Edit1.Text:=IntToStr (Plus (10,20));
{使用DLL库中的函数}
end;
end.
将此工程编译,生成Usedll.exe,运行时按下Button即可看到Edit
控件的Text变成了30。
依上例可以建立多个EXE文件,共同使用Mydll中的函数Plus,由此
可以看出动态链接库的优越性,特别是在开发大型软件时,动态链接库
经常使用。
以上程序在Delphi 1.0/Win3.2、Delphi2.0/Win95上运行通
 
分账分账,这位老兄根本不来了,
我又没时间详细看,见者有份!
 
后退
顶部