DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: a12315
今日帖子: 52
在线用户: 19
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2022/1/13 16:24:46
标题:
请教:Dll 中返回数组 浏览:1749
加入我的收藏
楼主: Delphi 11 写了个 Dll,函数如下:

  procedure Test(var arrInt: TArray<Integer>); stdcall;
  const
    Count = 23;
  var
    I: Integer;
  begin
    SetLength(arrInt, Count);
    for I := 0 to Count - 1 do
    begin
      arrInt[I] := I + 1;
    end;
  end;

count 不超过 23 时, Dll、EXE 都正常。
超过 23,Dll 就异常了。分配内存出错。

为什么呀?有高手能指点一下吗。谢谢。
----------------------------------------------
武汉天气不好
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/1/13 16:29:44
1楼: DLL 的接口函数?

接口函数里面的参数能使用  TArray 这样的数据类型吗?
----------------------------------------------
-
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2022/1/13 17:01:36
2楼: 即使用指针,超过 23,DLL 依然会报错:

  procedure Test(var p: Pointer; var size: Integer); stdcall;
  const
    Count = 23;
  var
    I  : Integer;
    ttt: array of Integer;
  begin
    SetLength(ttt, Count);
    for I := 0 to Count - 1 do
    begin
      ttt[I] := I;
    end;

    size := Count * 4;
    GetMem(p, size);
    Move(ttt[0], p^, size);
  end;
----------------------------------------------
武汉天气不好
作者:
男 keymark (嬲) ▲▲▲△△ -
普通会员
2022/1/13 19:09:07
3楼: 不过是一个指针而已。按此在新窗口浏览图片
绕来绕取说那么复杂,不知道你咋用的。
----------------------------------------------
[alias]  co = clone --recurse-submodules  up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/>http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/1/13 20:33:54
4楼: RAD 11 ALEXANDRIA -> EXE x32bits, MSWin 10 x64 for tests

library ArrayInDLL;

IMPORTANT! IMPORTANT! IMPORTANT! ---> SHAREMEM or similar...

{ 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. }

uses
  ShareMem,
  System.SysUtils,
  System.Classes,
  System.Generics.Collections;

{$R *.res}

type
  TMyArrayToResult = TArray<integer>;

function ExportMyArray(AHowManyElements: integer): TMyArrayToResult; stdcall;
begin
  result := [];
  //
  if AHowManyElements > 1000 then
    { just for test };
  //
  for var i: integer := 1 to AHowManyElements do
    result          := result + [i];
end;

exports
  ExportMyArray;

begin

end.

----------
unit uView.FormMain;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TMyArrayToResult = TArray<integer>;

  //
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

// function ExportMyArray(AHowManyElements: integer): TMyArrayToResult; stdcall; external 'ArrayInDLL.dll';

var
  Form1: TForm1;

implementation

{$R *.dfm}

//function ExportMyArray(AHowManyElements: integer): TMyArrayToResult; stdcall; external 'ArrayInDLL.dll';

procedure TForm1.Button1Click(Sender: TObject);
var
  MyResult: TMyArrayToResult;
begin
  MyResult := ExportMyArray(395);
  //
  //  for var MyItem in ExportMyArray(395) do
  //
  for var MyItem in MyResult do
    Memo1.Lines.Add(MyItem.ToString);

end;

end.
此帖子包含附件:
PNG 图像
大小:6.5K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/1/13 20:35:45
5楼: screenshot
此帖子包含附件:
PNG 图像
大小:6.3K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/1/13 20:46:34
6楼: your code

NOTE: change "VAR" to "OUT" params...

....
此帖子包含附件:
PNG 图像
大小:128.6K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/1/13 20:54:42
7楼: Im not specialist in "Pointers" but...

NOTE by Embarcadero:

GetMem allocates a memory block. 

GetMem allocates a block of the given Size on the heap, and returns the address of this memory in the P parameter. The bytes of the allocated buffer are not set to zero. To dispose of the buffer, use FreeMem. If there is not enough memory available to allocate the block, an EOutOfMemory exception is raised. 

my note:
try
...
except
...
end;


Note: If the memory block must be initialized with zero, you can use AllocMem

This function is not available in C++. In C++ you can use GetMemory. 

In case of a typed pointer, you should consider the New and Dispose procedures, which respectively initialize and finalize the memory block accordingly.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2022/1/14 7:09:48
8楼: Found the cause of the problem, thank emailx45.
----------------------------------------------
武汉天气不好
作者:
男 roadrunner (roadrunner) ★☆☆☆☆ -
盒子活跃会员
2022/1/14 10:28:36
9楼: 如果要在DLL中传递动态数组, 需要符合以下两个条件

1. 主程序和DLL都必须是DELPHI编写, 不支持在任何非DELPHI程序之间传递动态数组

2. 主程序和DLL都必须在第一个单元就引用sharemem单元,并且将borlandmm.dll单元随程序和DLL一起发布

不遵循上述任一规则,后果不可预料,无法保证任何稳定西
----------------------------------------------
-
作者:
男 keymark (嬲) ▲▲▲△△ -
普通会员
2022/1/14 10:46:24
10楼: 拿到(数据)正确的位置 正确的长度
就能操作这个数组
数组一般是连续性的
泛型数组不清楚了~
----------------------------------------------
[alias]  co = clone --recurse-submodules  up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/>http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
作者:
男 kentty (kentty) ★☆☆☆☆ -
普通会员
2022/1/14 11:19:25
11楼: 老派的做法, 按照谁拉便便谁擦屁股的原则, 内存空间的申请和释放最好在同一侧做, 比如dll调用方先获得需要的内存长度,自己申请内存后传递给dll, 用完后自己负责释放, 这种在dll内部隐性申请内存的操作, 如果没有详细的文档说明很容易造成内存泄漏

Explicit is always better than implicit.
----------------------------------------------
-
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2022/1/14 11:21:51
11楼: @roadrunner:
  我印象中,Delphi11,使用了 FastMM。 
  所以我认为可以脱离 borland.dll 了。实际上不是。

@keymark:
  如果不按照 roadrunner 的说的那样,在 Dll 中是没有办法动态分配内存的。
  “拿到正确的位置、正确的长度”,无从谈起。

所以我现在使用指针了,不使用动态数组了,在 Dll 中。这样更具有通用性。
----------------------------------------------
武汉天气不好
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/1/14 12:08:24
12楼: As said some article Embarcadero, FastMM (lite version no-sources) is used for now.

But, "borlandmm" still as compatibility with old IDE(s) of course and help in any moment necessary :)
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 ksrsoft (cb168) ★☆☆☆☆ -
普通会员
2022/1/16 14:33:09
13楼: 学习了
----------------------------------------------
-
作者:
男 lsuper (lsuper) ★☆☆☆☆ -
盒子活跃会员
2022/1/16 21:09:21
14楼: 统一 runtime 即可:exe 和 dll 都带 rtl/vcl 包编译
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行140.625毫秒 RSS