加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 将数据从DLL传递到Application的问题

发布时间:2020-12-15 09:44:01 所属栏目:大数据 来源:网络整理
导读:关于如何在我的场景中正确使用Pointers,我有点疑惑.我有一个DLL,里面有一些嵌入式资源.我在这个DLL中公开了一个函数,它将其中一个资源的二进制数据传递回其调用应用程序.在这种情况下,我嵌入了一个JPG图像文件.我的DLL确实将文件正确加载到资源流中.然而,从
关于如何在我的场景中正确使用Pointers,我有点疑惑.我有一个DLL,里面有一些嵌入式资源.我在这个DLL中公开了一个函数,它将其中一个资源的二进制数据传递回其调用应用程序.在这种情况下,我嵌入了一个JPG图像文件.我的DLL确实将文件正确加载到资源流中.然而,从那里,将它传回应用程序变得混乱.

这是我的DLL代码(加载JPG并命名为SOMERESOURCE):

library ResDLL;

{$R *.dres}

uses
  System.SysUtils,System.Classes,Winapi.Windows;

{$R *.res}

function GetResource(const ResName: PChar; Buffer: Pointer;
  var Length: Integer): Bool; stdcall;
var
  S: TResourceStream;
  L: Integer;
  Data: array of Byte;
begin
  Result:= False;
  try
    S:= TResourceStream.Create(HInstance,UpperCase(ResName),RT_RCDATA);
    try
      S.Position:= 0;
      L:= S.Size;
      Length:= L;
      SetLength(Data,L);
      S.Read(Data[0],L);
      Buffer:= @Data[0];
      Result:= True;
    finally
      S.Free;
    end;
  except
    Result:= False;
  end;
end;

exports
  GetResource;

begin
end.

这是我的应用程序代码(只有TBitBtn和TImage):

function GetResource(const ResName: PChar; Buffer: Pointer;
  var Length: Integer): Bool; stdcall; external 'ResDLL.dll';

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  Buffer: array of Byte;
  Size: Integer;
  S: TMemoryStream;
  P: TPicture;
begin
  if GetResource('SOMERESOURCE',@Buffer[0],Size) then begin
    S:= TMemoryStream.Create;
    try
      SetLength(Buffer,Size);
      S.Write(Buffer,Size);
      S.Position:= 0;
      P:= TPicture.Create;
      try
        P.Graphic.LoadFromStream(S);
        Image1.Picture.Assign(P);
      finally
        P.Free;
      end;
    finally
      S.Free;
    end;
  end else begin
    raise Exception.Create('Problem calling DLL');
  end;
end;

看起来好像整个DLL调用都成功,但是收到的数据是空的(满0).我对如何像Data [0]需要调用Data这样的东西以及我应该在什么场景中以及在什么场景中需要使用@Data充满了好奇心.我完全在DLL中编写了这段代码,我对这些工作并不熟悉,所以我确定我把它搞砸了.我哪里错了?

解决方法

在DLL方面,GetResource()将资源数据读入本地数组,而不是将其复制到传递给函数的缓冲区中.将本地数组分配给Buffer指针不会复制指向的数据.

在应用程序方面,BitBtn1Click()没有为GetResource()分配任何内存来写入资源数据.即使它是,您也没有正确地将缓冲区写入TMemoryStream.即使你是,你也没有正确地将TMemoryStream加载到TPicture中.

您可以采取几种方法来解决缓冲区问题:

1)让GetResource()分配一个缓冲区并将其返回给应用程序,然后让应用程序在完成后将缓冲区传递回DLL以释放它:

library ResDLL;

{$R *.dres}

uses
  System.SysUtils,Winapi.Windows;

{$R *.res}

function GetResourceData(const ResName: PChar; var Buffer: Pointer;
  var Length: Integer): Bool; stdcall;
var
  S: TResourceStream;
  L: Integer;
  Data: Pointer;
begin
  Result := False;
  try
    S := TResourceStream.Create(HInstance,RT_RCDATA);
    try
      L := S.Size;
      GetMem(Data,L);
      try
        S.ReadBuffer(Data^,L);
        Buffer := Data;
        Length := L;
      except
        FreeMem(Data);
        raise;
      end;
      Result := True;
    finally
      S.Free;
    end;
  except
  end;
end;

procedure FreeResourceData(Buffer: Pointer); stdcall;
begin
  try
    FreeMem(Buffer);
  except
  end;
end;

exports
  GetResourceData,FreeBufferData;

begin
end.

.

unit uMain;

interface

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

type
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    Image1: TImage;
    procedure BitBtn1Click(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

uses
  Vcl.Imaging.jpeg;

{$R *.dfm}

function GetResourceData(const ResName: PChar; var Buffer: Pointer;
  var Length: Integer): Bool; stdcall; external 'ResDLL.dll';

procedure FreeResourceData(Buffer: Pointer); stdcall; external 'ResDLL.dll';

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  Buffer: Pointer;
  Size: Integer;
  S: TMemoryStream;
  JPG: TJPEGImage;
begin
  if GetResourceData('SOMERESOURCE',Buffer,Size) then
  begin
    try
      S := TMemoryStream.Create;
      try
        S.WriteBuffer(Buffer^,Size);
        S.Position := 0;
        JPG := TJPEGImage.Create;
        try
          JPG.LoadFromStream(S);
          Image1.Picture.Assign(JPG);
        finally
          JPG.Free;
        end;
      finally
        S.Free;
      end;
    finally
      FreeResourceData(Buffer);
    end;
  end else begin
    raise Exception.Create('Problem calling DLL');
  end;
end;

end.

2)让app查询DLL的资源大小,然后分配一个缓冲区并将其传递给DLL来填写:

library ResDLL;

{$R *.dres}

uses
  System.SysUtils,Winapi.Windows;

{$R *.res}

function GetResourceData(const ResName: PChar; Buffer: Pointer;
  var Length: Integer): Bool; stdcall;
var
  S: TResourceStream;
  L: Integer;
  Data: Pointer;
begin
  Result := False;
  try
    S := TResourceStream.Create(HInstance,RT_RCDATA);
    try
      L := S.Size;
      if Buffer <> nil then
      begin
        if Length < L then Exit;
        S.ReadBuffer(Buffer^,L);
      end;
      Length := L;
      Result := True;
    finally
      S.Free;
    end;
  except
  end;
end;

exports
  GetResourceData;

begin
end.

.

unit uMain;

interface

uses
  Winapi.Windows,Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    Image1: TImage;
    procedure BitBtn1Click(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

uses
  Vcl.Imaging.jpeg;

{$R *.dfm}

function GetResourceData(const ResName: PChar; Buffer: Pointer;
  var Length: Integer): Bool; stdcall; external 'ResDLL.dll';

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  Buffer: array of Byte;
  Size: Integer;
  S: TMemoryStream;
  JPG: TJPEGImage;
begin
  if GetResourceData('SOMERESOURCE',nil,Size) then
  begin
    SetLength(Buffer,Size);
    if GetResourceData('SOMERESOURCE',Size) then
    begin
      S := TMemoryStream.Create;
      try
        S.WriteBuffer(Buffer[0],Size);
        S.Position := 0;
        // alternatively,use TBytesStream,or a custom
        // TCustomMemoryStream derived class,to read
        // from the original Buffer directly so it does
        // not have to be copied in memory...

        JPG := TJPEGImage.Create;
        try
          JPG.LoadFromStream(S);
          Image1.Picture.Assign(JPG);
        finally
          JPG.Free;
        end;
      finally
        S.Free;
      end;
      Exit;
    end;
  end;
  raise Exception.Create('Problem calling DLL');
end;

end.

要么:

library ResDLL;

{$R *.dres}

uses
  System.SysUtils,Winapi.Windows;

{$R *.res}

function GetResourceData(const ResName: PChar; Buffer: Pointer;
  var Length: Integer): Bool; stdcall;
var
  S: TResourceStream;
  L: Integer;
  Data: Pointer;
begin
  Result := False;
  if (Buffer = nil) or (Length <= 0) then Exit;
  try
    S := TResourceStream.Create(HInstance,RT_RCDATA);
    try
      L := S.Size;
      if Length < L then Exit;
      S.ReadBuffer(Buffer^,L);
      Length := L;
      Result := True;
    finally
      S.Free;
    end;
  except
  end;
end;

function GetResourceSize(const ResName: PChar): Integer; stdcall;
var
  S: TResourceStream;
begin
  Result := 0;
  try
    S := TResourceStream.Create(HInstance,RT_RCDATA);
    try
      Result := S.Size;
    finally
      S.Free;
    end;
  except
  end;
end;

exports
  GetResourceData,GetResourceSize;

begin
end.

.

unit uMain;

interface

uses
  Winapi.Windows,Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    Image1: TImage;
    procedure BitBtn1Click(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

uses
  Vcl.Imaging.jpeg;

{$R *.dfm}

function GetResourceData(const ResName: PChar; Buffer: Pointer;
  var Length: Integer): Bool; stdcall; external 'ResDLL.dll';

function GetResourceSize(const ResName: PChar): Integer; stdcall; external 'ResDLL.dll';

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  Buffer: array of Byte;
  Size: Integer;
  S: TMemoryStream;
  JPG: TJPEGImage;
begin
  Size := GetResourceSize('SOMERESOURCE');
  id Size > 0 then
  begin
    SetLength(Buffer,Size);
        S.Position := 0;
        JPG := TJPEGImage.Create;
        try
          JPG.LoadFromStream(S);
          Image1.Picture.Assign(JPG);
        finally
          JPG.Free;
        end;
      finally
        S.Free;
      end;
      Exit;
    end;
  end;
  raise Exception.Create('Problem calling DLL');
end;

end.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读