dll编写问题 ( 积分: 50 )

  • 主题发起人 主题发起人 smart_jun
  • 开始时间 开始时间
S

smart_jun

Unregistered / Unconfirmed
GUEST, unregistred user!
如题
为了使dll能被其他语言调用,我将函数的参数及返回值都表示为pchar(可能为string的参数和返回值都用pchar表示而不用string),请问函数内部变量可以为string的吗?
 
如题
为了使dll能被其他语言调用,我将函数的参数及返回值都表示为pchar(可能为string的参数和返回值都用pchar表示而不用string),请问函数内部变量可以为string的吗?
 
内部使用的变量可以用 string
外部的建议使用 PChar、Single、Integer等类型
 
标题?: Delphi制作Dll全集
关键字:
分类?: 面向对象
密级?: 私有
(评分: , 回复: 0, 阅读: 2) »&raquo

标题:Delphi制作Dll全集 (0分)
阿朱 (2001-5-18 8:49) 534762
用Delphi制作DLL
一 Dll的制作一般步骤
二 参数传递
三 DLL的初始化和退出清理[如果需要初始化和退出清理]
四 全局变量的使用
五 调用静态载入
六 调用动态载入
七 在DLL建立一个TForM
八 在DLL中建立一个TMDIChildForM
九 示例:
十 Delphi制作的Dll与其他语言的混合编程中常遇问题:
十一 相关资料

一 Dll的制作一般分为以下几步:
1 在一个DLL工程里写一个过程或函数
2 写一个Exports关键字,在其下写过程的名称。不用写参数和调用后缀。
二 参数传递
1 参数类型最好与window C++的参数类型一致。不要用DELPHI的数据类型。
2 最好有返回值[即使是一个过程],来报出调用成功或失败,或状态。成功或失败的返回值最好为1[成功]或0[失败].一句话,与windows c++兼容。
3 用stdcall声明后缀。
4 最好大小写敏感。
5 无须用far调用后缀,那只是为了与windows 16位程序兼容。

三 DLL的初始化和退出清理[如果需要初始化和退出清理]
1 DLLProc[SysUtils单元的一个Pointer]是DLL的入口。在此你可用你的函数替换了它的入口。但你的函数必须符合以下要求[其实就是一个回调函数]。如下:
procedure DllEnterPoint(dwReason: DWORD);far;stdcall;
dwReason参数有四种类型:
DLL_PROCESS_ATTACH:进程进入时
DLL_PROCESS_DETACH进程退出时
DLL_THREAD_ATTACH 线程进入时
DLL_THREAD_DETACH 线程退出时
在初始化部分写:
DLLProc := @DLLEnterPoint;
DllEnterPoint(DLL_PROCESS_ATTACH);
2 如Form上有TdcomConnection组件,就Uses Activex,在初始化时写一句CoInitialize (nil);
3 在退出时一定保证DcomConnection.Connected := False,并且数据集已关闭。否则报地址错。

四 全局变量的使用
在widnows 32位程序中,两个应用程序的地址空间是相互没有联系的。虽然DLL在内存中是一份,但变量是在各进程的地址空间中,因此你不能借助dll的全局变量来达到两个应用程序间的数据传递,除非你用内存映像文件。

五 调用静态载入
1 客户端函数声名:
1)大小写敏感。
2)与DLL中的声明一样。
如: showform(form:Tform);Far;external'yproject_dll.dll';
3)调用时传过去的参数类型最好也与windows c++一样。
4)调用时DLL必须在windows搜索路径中,顺序是:当前目录;Path路径;windows;widows/system;windows/ssystem32;

六 调用动态载入
1 建立一种过程类型[如果你对过程类型的变量只是一个指针的本质清楚的话,你就知道是怎么回事了]。如:
type
mypointer=procedure(form:Tform);Far;external;
var
Hinst:Thandle;
showform:mypointer;
begin
Hinst:=loadlibrary('yproject_dll');//Load一个Dll,按文件名找。
showform:=getprocaddress(Hinst,'showform');//按函数名找,大小写敏感。如果你知道自动化对象的本质就清楚了。
showform(application.mainform);//找到函数入口指针就调用。
Freelibrary(Hinst);
end;

七 在DLL建立一个TForM
1 把你的Form Uses到Dll中,你的Form用到的关联的单元也要Uses进来[这是最麻烦的一点,因为你的Form或许Uses了许多特殊的单元或函数]
2 传递一个Application参数,用它建立Form.

八 在DLL中建立一个TMDIChildForM
1 Dll中的MDIForm.FormStyle不用为fmMDIChild.
2 在CreateForm后写以下两句:
function ShowForm(mainForm:TForm):integer;stdcall
var
Form1: TForm1;
ptr:PLongInt;
begin
ptr:=@(Application.MainForm);//先把dll的MainForm句柄保存起来,也无须释放,只不过是替换一下
ptr^:=LongInt(mainForm);//用主调程序的mainForm替换DLL的MainForm。MainForm是特殊的WINDOW,它专门管理Application中的Forms资源.
//为什么不直接Application.MainForm := mainForm,因为Application.MainForm是只读属性
Form1:=TForm1.Create(mainForm);//用参数建立
end;
备注:参数是主调程序的Application.MainForm

九 示例:
DLL源代码:
library Project2;

uses
SysUtils,
Classes,
Dialogs,
Forms,
Unit2 in 'Unit2.pas' {Form2};

{$R *.RES}
var
ccc: Pchar;

procedure OpenForm(mainForm:TForm);stdcall;
var
Form1: TForm1;
ptr:PLongInt;
begin
ptr:=@(Application.MainForm);
ptr^:=LongInt(mainForm);
Form1:=TForm1.Create(mainForm);
end;

procedure InputCCC(Text: Pchar);stdcall;
begin
ccc := Text;
end;

procedure ShowCCC;stdcall;
begin
ShowMessage(String(ccc));
end;

exports
OpenForm;
InputCCC,
ShowCCC;
begin
end.

调用方源代码:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}
procedure OpenForm(mainForm:TForm);stdcall;External'project2.dll';
procedure ShowCCC;stdcall;External'project2.dll';
procedure InputCCC(Text: Pchar);stdcall;External'project2.dll';

procedure TForm1.Button1Click(Sender: TObject);
var
Text: Pchar;
begin
Text := Pchar(Edit1.Text);
// OpenForm(Application.MainForm);//为了调MDICHILD
InputCCC(Text);//为了实验DLL中的全局变量是否在各个应用程序间共享
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
ShowCCC;//这里表明WINDOWS 32位应用程序DLL中的全局变量也是在应用程序地址空间中,16位应用程序或许不同,没有做实验。
end;

十 Delphi制作的Dll与其他语言的混合编程中常遇问题:
1 与PowerBuilder混合编程
在定义不定长动态数组方面在函数退出清理堆栈时老出现不可重现的地址错,原因未明,大概与PB的编译器原理有关,即使PB编译成二进制代码也如此。
sundart (2001-5-30 1:9)
呵呵。楼上兄台精神可敬。
leebons (2001-5-31 17:24)
怎么不给分啊
pcexplorer (2001-5-31 18:19)
To:leebons
你还想要分吗,知识是无价的!
楼上兄台精神可敬,改天我也来发表发表文章
:)
悲酥清风 (2001-5-31 18:29)
好啊好啊!
什么时候再来个COM制作全集、控件制作全集、专家制作全集。。。(是不是太贪心了?)
阿朱 (2001-5-31 21:31)
悲酥清风同志说的这几个全集我都在考虑。不过目前我正在写一篇关于数据库存储引擎的
文章,改天写好给大家
mikedeakins (2001-5-31 21:59)
阿朱同志,可否把全部文章发给我?谢谢。
iamfly (2001-5-31 22:7)
期待着阿朱同志的下几个全集:)
P.S 我这也有个同事我们叫他阿朱的,不过他不用DELPHI的
程云 (2001-6-8 14:51)
真是受益非浅,我正用到这方面的东西呢。
多谢了。
程云 (2001-6-8 15:3)
只是哪个在DLL中建立一个TMDIChildForM,并动态加载这个DLL,并显示这个Form时,
在关闭时,要如何才能去释放这个DLL呢?

我试过,会出错的。
9861 (2001-6-8 15:19)
我想知道怎样开发一个最简单的VCL或OCX控件。
jiceyang (2001-6-8 15:26)
真实对大富翁的高手门无私的奉贤精神,对与我正样的菜鸟真实太好。。。。。。
千中元 (2001-6-8 15:34)
手藏收藏。。。
慕容乾坤 (2001-6-8 16:4)
thanks
程云 (2001-6-8 16:22)
有人知道"阿朱"的信箱吗?
我有问题请教。
程云 (2001-6-8 16:29)
我在DLL写如下程序
function ShowForm(FHandle: THandle
mainform: TForm):LongInt;StdCall;
begin
ptr:=@(Application.MainForm);
ptr^:=LongInt(mainForm);
DllLongInt:=ptr^;
DllForm:=TDllForm.Create(mainform);
Result:=LongInt(DllForm);
end;

使用动态加载DLL见如下

procedure TMainFrm.LoadLib(LibName: String);
var
LibHandle : Thandle;
ShowForm : TShowForm;
begin
LibHandle:=LoadLibrary(LibName);

try
if LibHandle=0 then raise EDLLLoadError.Create(extractfilepath(application.ExeName)+'FrmLib/'+LibName+'文件没有发现!');
@ShowForm:=GetProcAddress(LibHandle,'ShowForm');
if Assigned(ShowForm) then
ShowForm(Application.Handle, DllCortrol.Handle, MainFrm);
except { finally }
FreeLibrary(libHandle);
end;
end;


结果,我在想释放这个DLL时就出现了错误。

FreeLibrary(DllHandle);

不知如何作?

帮帮我吧
阿朱 (2001-6-8 17:4)
我的这段代码是把DLL的句柄在程序执行时换掉了,有一段再换回的代码忘写了。你在释放
DLL时,只要把DLL句柄换回即可。
DllLongInt:=ptr^;就是此意.
程云 (2001-6-8 17:11)
我也换回来了,可是还是一样有错误

procedure TDllForm.FormClose(Sender: TObject
var Action: TCloseAction);
begin
Action := caFree;
ptr^:=DllLongInt;
end;

最好能看看你原来的代码
程云 (2001-6-8 19:3)
前的写的次序不对,在DLL中如下写

function ShowForm(FHandle: THandle
mainform: TForm):LongInt;StdCall;
begin
ptr:=@(Application.MainForm);
DllLongInt:=ptr^
//保存原句柄,多次试,发现此时为"0";
ptr^:=LongInt(mainForm)
//修改
DllForm:=TDllForm.Create(mainform);
Result:=LongInt(DllForm);
end;

procedure TDllForm.FormClose(Sender: TObject
var Action: TCloseAction);
begin
Action := caFree;
ptr^:=DllLongInt
//改为原来句柄
end;

可错误依旧,真不知哪里错了
阿朱 (2001-6-8 21:29)
我不是在FormCreate和FormClose中写的,而是在DLL的函数中写的.那些变量也是dll的全局变量。
DllLongInt:=ptr^
这两个都是.
程云 (2001-6-8 22:8)
我也是这样写的,可还是有错,我真不知是为什么,
哪些变量也全是dll的全局变量。

你有没有例程给我寄个来看看呢?

真是头疼死人了
程云 (2001-6-8 23:4)
阿朱老兄,还是不成,就是报错,说是任地址不可用。

我给你寄去个程序,你帮我看看是哪里错了。

多谢了
程云 (2001-6-9 11:41)
各位不好意思,打扰了,我的问题已经解决,
出错的原因,是我不应试图再修改回一哪个值,
这完全是画蛇添足。

多谢各位了,由其是阿朱老兄。
ynjinti (2001-6-9 14:58)
TO 阿朱:
你是DLL高手吗?我正在学DLL,并用DLL实现了MDI子窗体,创建DLL子窗体有两种方法,
一是在DLL里创建,别一个是在主程序里创建,两种方法都可行,但是有一个问题父窗体不
认识子窗体,也就是说我创建了子窗体后父窗体的MDIChildCount仍然为这0,这样的话,
父窗体无法控制子窗体比如我在主程序里发送消息给子窗体进行打印就无法进行。此外是关于
数据传输的问题,书上讲得较多的是两个应用程序共享的DLL的数据,但我现在是多个DLL共享
应用程序的通用变量(可能随时改变),如何实现,一般共享数据是用内存映射文件实现当然也可以
用流文件实现,你觉得哪种更好,当然数据类型的数据共享相对容易,如果要传送控件,对象,
如何进行。
我做的程序的思想是只有主程序是EXE,此外每个模块都是一个DLL,由主程序调用,行吗?
你有没有相关的DLL源代码,有的话麻烦发一点给我,我是说是你自己写的,不要书上抄来的。OK!
如果满意的话,我把我的分全给你,如何?
程云 (2001-6-11 14:1)
to ynjinti:

你说的在主程序里创建中创建DLL中的窗体,这是如何作的?我只知在DLL中创建。
没听说过哪个对象能在DLL之外被创建。要这样作,也得在外部进行说明,
这样哪也没有必要放入DLL中了。

我就是这样作的,主程序中只有一个主窗体,其它的都放在各DLL中,
这种方法的好处显而易见,只是有很多问题还没很好地解决,
希望能同你多多交流。
电暖气 (2001-6-11 14:15)
阿朱是个好同志
踏雪无痕 (2001-6-11 16:5)
To 程云:
在主程序中创建窗体是这样做的,Dll有一个函数返回DLL中的窗体的类,主窗体加载这个然后通过返回
的类名进行创建。一般一书上都是在DLL中进行创建的,我原来也以为不行,因为我以为和应用在不同的
进程空间运行,你也在做这方面的吗?希望以后多交流,我的EMAIL:hoboes@163.net
程云 (2001-6-12 8:6)
OK。多交流了。
踏雪无痕 (2001-6-12 8:18)
To 程云:
你的EMAIL是多少,我现在也正在做如果我最新进展我会告诉你的。
maming (2001-6-12 9:1)
学学
程云 (2001-6-12 11:33)
to 踏雪无痕:

EMail是:zzmcy@21cn.com
我上午给发了封邮件。
almeidar (2001-9-25 17:24)
[:D]今天才看到 ,呵呵 ,不好意思!
oceanwave (2001-9-25 17:43)
[gold]不错,不错。大富翁这样深入的的谈论越来越少了,向阿朱同志致敬[:D][/gold]
Ayong (2001-9-25 18:10)
真是不好意思!今天才看到。
“阿朱”。。
这个名字好亲切!!我有个大学同学,也是同居四年的室友,我们就是这样称呼他的!
你后面的全集写好了吗?千万别忘了给我一份!先谢谢了!!
dinjian (2001-9-26 9:45)
阿朱兄太棒了![^]
ctx62 (2001-9-26 13:6)
to 阿朱
有一个问题不知能否解决,就是在编两层数据库管理程序,我每一个模块都用一个
独立的exe,然后用一个主程序去调用,现在的问题是我的每一个exe文件都与server
建立一个数据库连接,如果同时执行好几个模块,再加上几个工作站都在执行
这样可能造成连接数不够的问题,能否用dll文件来实现所有的exe用一个连接。
不能没有你 (2001-9-26 13:9)
不错
值得关注
蛐蛐 (2001-9-26 13:11)
go on .
anzuo@lungcheong.com.cn
叶不归 (2001-9-26 15:21)
[:D]gua z
lliuxxingw (2001-9-26 15:47)
gz:
能否用dll文件来实现所有的exe用一个连接?
lbmjy (2001-10-6 12:26)
我遇到的问题与ynjinti一样,想在主控程序控制Dll中的MDIChildForm,
非常想知道解决问题的方法。
lbmjy@163.net
蛐蛐 (2001-10-6 12:38)
贴出来嘛,好东东,要大家分享才好。
免费得到 (2001-10-8 18:1)
洗耳恭听!
冰 原 (2001-10-8 18:56)
听课
zhuhuan (2001-10-8 20:21)
嘿嘿,其实从DLL中创建Form(无论室MDI还是其他FORM)有另外一种方法,至今不太见到,其实
DLL和EXE在同一进程空间,那和BPL有什么不一样呢?为什么BPL可以直接使用其类,而DLL就不
可以?当然可以!答案在D2 Unleashed里(后续的Unleasned里反而不见了).
刘永学 (2001-10-27 13:50)
dll学习的书籍中,有几本讲的较好,
其一为:delphi5开发人员指南《机械工业出版社》2000年//非常好,建议购买
其二为:《精通delphi》姚庭宝 电子工业出版社 1997年
其三为: 《delphi2 程序设计大全》《机械工业出版社》//好,想买也买不到

COM:
1、delphi com 深入编程 机械工业出版社
2、徐新华的书,书名忘了//深入不浅出
3、李维delphi5.x高级程序设计篇//好,有高手风范

数据库及电子商务
李维的delphi5.x丛书

控件制作、使用
1、delphi第三方控件使用大全 中国水利水电出版社//建议不要买,看看就可以了
2、delphi部件开发编程深入剖析 机械工业出版社 //其中有一个数值计算控件蛮好的

opengl
open gl 三维图形设计与制作 人民邮电出版社 //c++的例子
可视化opengl程序设计 清华大学出版社//较好,有示例
delphi 多媒体特效制作百例//中国电力出版社 ,看看就行了,不要买,将随书的光盘栲下来就可以

操纵office
网上有很多例子,查找一下就可以了


以上是我这4年的学习心得,大家可以参考一下!!
zhang12321 (2001-11-9 10:48)
太好了.我已经看到阿朱的好几个好文了.多谢了:)!!!!!!!!!!!!!!!
yxq1220 (2001-11-9 10:52)
谢谢
lop (2001-11-9 11:6)
没什么好说的了,谢谢!
tkggai (2001-11-9 11:36)
阿朱:谢谢你了:tkggai@sian.com
dcsdcs (2001-11-9 13:9)
主程序:
function dcs_logon(input:tstringlist):Tstringlist;far
external 'logondll.DLL';

var
namelist:Tstringlist;
begin
namelist:=Tstringlist.Create;
namelist.Append('dcs');
try
namelist:=dcs_logon(namelist);
except
end;
if namelist.Strings[0]='0' then
begin
label1.Caption:='用户名:'+namelist.Strings[1];
label2.Caption:='密码:'+namelist.Strings[2];
end
else
begin
label1.Caption:='用户取消登录';
label2.Caption:='';
end;
end;

dll程序:
uses
SysUtils,
Classes,
loginunit in 'loginunit.pas' {loginform};

{$R *.RES}
exports
dcs_logon index 1;
begin
end.

function dcs_logon(input:tstringlist):Tstringlist;
var
loginform: Tloginform;
begin
try
loginform:=Tloginform.Create(application);
loginform.ComboBox1.Items.Clear;
loginform.ComboBox1.Items.AddStrings(input);
loginform.ShowModal;
res.Strings[1]:=loginform.ComboBox1.Text;
res.Strings[2]:=loginform.Edit2.Text;
result:=res;
finally
loginform.Free;
end;
end

EdwinYeah (2001-11-10 22:1)
关于制作DLL,<delphi 5开发人员指南第九章有详细介绍,以下是目录:
第9章 动态链接库 234
9.1 究竟什么是DLL 234
9.2 静态链接与动态链接 235
9.3 为什么要使用DLL 236
9.3.1 共享代码、资源和数据 236
9.3.2 隐藏实现的细节 237
9.3.3 自定义控件 237
9.4 创建和使用DLL 237
9.4.1 数美分:一个简单的DLL 237
9.4.2 显示DLL中的模式窗体 239
9.5 显示DLL中的无模式窗体 241
9.6 在Delphi应用程序中使用DLL 242
9.7 DLL的入口函数和出口函数 246
9.7.1 进程/线程初始化和终止例程 246
9.7.2 DLL入口/出口示例 246
9.8 DLL中的异常 250
9.8.1 在16位Delphi中捕捉异常 250
9.8.2 异常和Safecall指示符 250
9.9 回调函数 250
9.9.1 使用回调函数 253
9.9.2 拥有者绘制的列表框 253
9.10 从DLL中调用回调函数 253
9.11 在不同的进程间共享DLL数据 256
9.11.1 一个可以被共享数据的DLL 256
9.11.2 访问DLL中的共享数据 259
9.12 引出DLL中的对象 261
9.13 总结 265
阿朱 (2001-12-2 10:52)
接受答案了.
得分富翁:9861
 
可以用 String, 不过你要求的是 为了使dll能被其他语言调用
这样就不可以了 String 是 Delphi 一种特有的数据类型来的...
 
可以用哈!只是注意一点:用String时要在编写时第一个引用ShareMen, 同时在你要引用这个Dll的程序中的.DPR文件中也要第一个引用ShareMen,就OK了!
 
可以用,如牢上所说.
 
引用ShareMem 就必须在发布dll时 需要带着borland.dll一同发布。这是我不想要的 。
这样 是不是我 就不能再函数内部使用string了
再顶
 
只要对外的函数中用PChar,内部用string是不需要borland.dll的
 
多人接受答案了。
 
后退
顶部