gpt4 book ai didi

delphi - 将数据从 DLL 传递到应用程序时出现问题

转载 作者:行者123 更新时间:2023-12-03 15:15:25 25 4
gpt4 key购买 nike

我对如何在我的场景中正确使用指针感到有点困惑。我有一个 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.

这是我的应用程序的代码(只有 TBitBtnTImage):

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这样的东西需要如何被称为Data[0],以及在什么场景下我应该调用,以及在什么场景下我需要使用@Data。我完全在 DLL 中编写了该代码,而且我对此类工作并不熟悉,所以我确信我在某个地方搞砸了。我哪里出错了?

最佳答案

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

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

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

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

library ResDLL;

{$R *.dres}

uses
System.SysUtils,
System.Classes,
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, UpperCase(ResName), 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, System.Classes, 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) 让应用程序向 DLL 查询资源的大小,然后分配一个缓冲区并将其传递给 DLL 进行填充:

library ResDLL;

{$R *.dres}

uses
System.SysUtils,
System.Classes,
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, UpperCase(ResName), 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, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, 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; 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', @Buffer[0], 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,
System.Classes,
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, UpperCase(ResName), 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, UpperCase(ResName), RT_RCDATA);
try
Result := S.Size;
finally
S.Free;
end;
except
end;
end;

exports
GetResourceData,
GetResourceSize;

begin
end.

.

unit uMain;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, 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; 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);
if GetResourceData('SOMERESOURCE', @Buffer[0], Size) then
begin
S := TMemoryStream.Create;
try
S.WriteBuffer(Buffer[0], 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.

关于delphi - 将数据从 DLL 传递到应用程序时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14681364/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com