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. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |