基础功不扎实,现在被卡住了,dll的数组参数传递,郁闷啊!请大虾们都来指教 ( 积分: 100 )

  • 主题发起人 主题发起人 maoke
  • 开始时间 开始时间
M

maoke

Unregistered / Unconfirmed
GUEST, unregistred user!
我在编写一个dll时,碰到了一个问题:
有一个静态记录型数组和一个静态byte数组作为参数传给我在dll中写的导出函数,
在我的函数中需要对这两个数组中的元素进行赋值或读取,比如说初始化所有数组元素什么的,然后这两个数组的更新后的内容还要被调用程序(可能是delphi程序也可能是.net程序)使用,请问我该如何做,才能做到上面提到的要求呢?
请大家指教一下。
 
我在编写一个dll时,碰到了一个问题:
有一个静态记录型数组和一个静态byte数组作为参数传给我在dll中写的导出函数,
在我的函数中需要对这两个数组中的元素进行赋值或读取,比如说初始化所有数组元素什么的,然后这两个数组的更新后的内容还要被调用程序(可能是delphi程序也可能是.net程序)使用,请问我该如何做,才能做到上面提到的要求呢?
请大家指教一下。
 
对与数组我都没有用过,这样用有什么好处
 
数组由应用程序声明并分配内存,然后把数组的头地址传给dll的函数(同时需要告诉dll该数组的元素个数,当然如果静态数组的大小永远不变的话也可偷懒),dll中函数对该地址的数组进行初始化等操作后返回即可
 
传指针(即数组第一个元素的地址)即可。
例如(对于不改变元素个数的情况):
type
PTest1 = ^TTest1;
TTest1 = packed record
V1: ***;
...
end;

PTest2 = ^TTest2;
TTest2 = record
V1: Byte;
end;

function Test(P1: PTest1
C1: Integer
P2: PTest2
C2: Integer): Boolean
stdcall;//C1、C2指定数组的元素个数。
 
但是这样做以后,我对记录数组中的元素赋值时出现了地址报错的情况,会是什么原因引起的呢?
 
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2796913
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2665183
 
数组没有初始化长度或者数组中的元素没有创建?
用不着指针,直接用就可以。
 
呵呵,我也刚刚遇到类似的问题
用传指针的方式看上去好像可以,但是数据到后面往往会出错
后面我改使用定义记录的方式
FMyType = record
floararr : Array [0..743] of Single;
end;
procedure TfrmMain.Button4Click(Sender: TObject);
var
MyPD:FMemoType;
i:integer;
begin
MyPD:= ReFunction();
//ReFunction是dll中的函数,它传出的就是MyPD:FMemoType类型的记录
for i:=0 to 734 do
begin
Memo1.Lines.Add(IntToStr(i)+'----'+FloatToStr(MyPD.floararr)+#13)

end;
end;

这样就ok'了
 
来自:maoke, 时间:2005-6-2 8:38:23, ID:3091633
但是这样做以后,我对记录数组中的元素赋值时出现了地址报错的情况,会是什么原因引起的呢?

Test1: array[0..X-1] of TTest1;
Test2: array[0..Y-1] of TTest2;
调用:
Test(@Test1, X, @Test2, Y);
如果DLL是DELPHI实现的,则可以这样:
function Test(P1: PTest1
C1: Integer
P2: PTest2
C2: Integer): Boolean
stdcall;//C1、C2指定数组的元素个数。
begin
P1^.V1 := ...
//数组的第一个元素
P1 := Pointer(Integer(P1) + SizeOf(TTest1));
P1^.V1 := ...
//数组的第二个元素,注意C1
...
end;
 
P1^.V1 := ...
//数组的第一个元素
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
这样写好象不行,编译时系统提示
Record, object or class type required
 
楼主就别害羞了,还是把你的代码贴出来吧,别让大家再这里猜谜浪费时间了[8D]

如果你的结构中有string类型肯定出错,因为你肯定没有看每个DLL前面的这段话:

library Project1;

{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }

如果字符类型调用前没有事先分配内存也会出错,给你的链接为什么就不看呢???[:(][:(!]
 
呵呵。。盲人摸象,程序不是靠猜的。
把代码贴出来,好让高手对症下药啊!
 
不好意思,代码如下,请高手们都来指教

类型说明,dll和主函数中都有:
rTotalReceived=record
PackVaild : Byte;
RevBuf : array [1..2048] of byte;
PackType : byte;
PackLen:Byte;
end;
TTotalReceived=Array [0..99] of rTotalReceived;
pTotalReceived=^TTotalReceived;

TReceivedBuffer=Array [1..2048] of byte;
pReceivedBuffer=^TReceivedBuffer;


dll中:
//初始化
procedure InitTotalBuffer(TotalReceive:pTotalReceived);
var i : byte;
begin
for i:=1 to 100 do
begin
TotalReceive^.PackVaild:=0;
^^^^^^^^^^^^^^^^编译通不过,如果改为TotalReceive.PackVaild:=0;地址报错
TotalReceive^.PackType:=0;
TotalReceive^.PackLen:=0;
fillChar(TotalReceive^.RevBuf ,length(TotalReceive^.RevBuf),0);
//TotalReceive:=Pointer(Integer(TotalReceive)+SizeOf(rtotalreceived));
end;
end;

//从SOCKET中读出的数据进行拆包处理
function ClientSocketReadDetail(var AnswerPacketCount:Integer;
var ValidPacketCount:Integer;var InVaildPacketCount:integer;
var TcpConnectSuccess:Boolean;ReceivedBuffer:pReceivedBuffer;var Info:PChar;
TotalReceive:pTotalReceived;Debug:Boolean=False):ShortInt;stdcall;exports;
var i,len,Pl,j:Short;
s:string;
begin
len := ReceivedLen;
i:=1;
s:='';
AnswerPacketCount:=0;
ValidPacketCount:=0;
InVaildPacketCount:=0;
while (i<=len) and (i<2048) do
begin
CopyMemory(@Pl,@ReceivedBuffer[i+1],2)

if i+pl+4>2048 then Exit

case ReceivedBuffer of
0:.......
1:begin
TotalReceive^[ValidPacketCount].PackLen:=Pl;
TotalReceive^[ValidPacketCount].PackVaild:=1;
CopyMemory(@TotalReceive^[ValidPacketCount].RevBuf[1],@ReceivedBuffer,pl+5);
TotalReceive^[ValidPacketCount].PackType:=ReceivedBuffer[i+5];
if Debug or AllDebug then
begin
s:=s+'单包'+IntToStr(TotalReceive^[ValidPacketCount].PackType)+'开始'+#13#10
+MakeInfo(TotalReceive^[ValidPacketCount].RevBuf,Pl+5)+#13#10
+'单包'+IntToStr(TotalReceive^[ValidPacketCount].PackType)+'结束';
end;
ValidPacketCount:=ValidPacketCount+1;
end;
2:......
end;
i:=pl+i+5;
end;
Info:=PChar(s);


end;

//从SOCKET中读出数据
function ClientSocketRead(var AnswerPacketCount:Integer;
var ValidPacketCount:Integer;var InVaildPacketCount:integer;var xReceiveLen:Integer;
var TcpConnectSuccess:Boolean;ReceivedBuffer:pReceivedBuffer;Info:PChar;
TotalReceive:pTotalReceived;Debug:Boolean=False):ShortInt;stdcall;exports;
var s : string;
begin
try
if MySocket.Active then
begin
if ReadStream.WaitForData(Socktimeout) then
begin
xReceiveLen := ReadStream.Read(ReceivedBuffer,2048);
ReceivedLen:=xReceiveLen;
if ReceivedLen>0 then
begin
InitTotalBuffer(TotalReceive)
ClientSocketReadDetail(AnswerPacketCount,ValidPacketCount, InVaildPacketCount,tcpconnectSuccess,ReceivedBuffer,info,TotalReceive,Debug);
end;
result:=1;
end;
end
else
begin
result:=-1;
end;
except
on E : Exception do begin
..............
end;
end;
end;

主函数中:

procedure TForm1.Timer1Timer(Sender: TObject);
var
vTotalBuffer:pTotalReceived;
vRevicedBuffer:pReceivedBuffer;
vTcpConnectSuccess:boolean;
AnswerPacketCount:Integer;
ValidPacketCount:Integer;
InVaildPacketCount:integer;
vReceiveLength:integer;
vInfo:PChar;
s:string;
begin
New(vTotalBuffer);
New(vRevicedBuffer);
vinfo:=StrAlloc(2048*SizeOf(Char));
m1.Lines.Add(IntToStr(Integer(vTotalBuffer)));
ClientSocketRead(AnswerPacketCount,ValidPacketCount,InVaildPacketCount,vReceiveLength,vTcpConnectSuccess,
vRevicedBuffer,vInfo,vTotalBuffer);
s:=IntToStr(AnswerPacketCount)+' and '+IntToStr(ValidPacketCount)+' and '+IntToStr(InVaildPacketCount);
m1.Lines.Add(s);
Dispose(vTotalBuffer);
Dispose(vRevicedBuffer);
StrDispose(vInfo);
end;
 
是呀,传递指针。
 
根本没有必要搞个什么InitTotalBuffer函数嘛,直接用ZeroMemory初始化就是了:

var
RecvBuf: TTotalReceived;
begin
ZeroMemory(@RecvBuf, SizeOf(TTotalReceived));
ClientSocketRead(@RecvBuf);
//....

end;
 
没法用ZeroMemory,这个InitTotalBuffer函数只是个范例,我有可能把其他值赋给其中的元素
 
注意一下数组下标范围就可以了:
procedure InitTotalBuffer(TotalReceive:pTotalReceived);
var i : byte;
begin
for i:=0 to 99 do //数组下标范围是0~99
begin
TotalReceive.PackVaild:=0;
TotalReceive.PackType:=0;
TotalReceive.PackLen:=0;
fillChar(TotalReceive.RevBuf ,length(TotalReceive.RevBuf),0);
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
RecvBuf: TTotalReceived;
begin
InitTotalBuffer(@RecvBuf);
ClientSocketRead(@RecvBuf);
end;
 
for i:=0 to 99 do //数组下标范围是0~99
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
我原来写的是for i:=low(TotalReceive^) to high(TotalReceive^) do
进入for后,第一次循环就地址报错。
而且你这样写 TotalReceive.PackVaild:=0;应该不行吧,
我觉得是TotalReceive^.PackVaild:=0;
 
//初始化
procedure InitTotalBuffer(TotalReceive:pTotalReceived);
var
i: Integer;
begin
//其实只要: ZeroMemory(TotalReceive, SizeOf(TTotalReceived));
for i:=0 to 99 do
begin
TotalReceive^.PackVaild:=0;
TotalReceive^.PackType:=0;
TotalReceive^.PackLen:=0;
fillChar(TotalReceive^.RevBuf ,length(TotalReceive^.RevBuf),0);
end;
end;
 

Similar threads

回复
0
查看
978
不得闲
S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
900
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部