2015-01-20 3 views
0

큰 문자열을 반환하는 Delphi 7 DLL 함수가 있는데 제대로 작동하지만 Delphi XE5에서는 특정 크기가 지나면 액세스 위반이 발생합니다.Delphi XE5 DLL과 EXE 사이의 문자열 크기 교환 제한

내 실제 코드를 반영하는 샘플 데모를 작성했으며, 또한 큰 문자열을 반환하지만 다시 특정 크기를 반환하는 Delphi XE5에서 AV를 생성하므로 액세스 위반이 발생합니까?

13000 줄의 20 개 문자로 작동하지만 정상적으로 작동하지만 14000 줄은 충돌합니다. Delphi 7에서 몇 가지 테스트를 수행했으며 제대로 작동합니다.

내가 뭘 잘못하고 있니? 누구든지 나를 도울 수 있습니까?

감사합니다.

function RetLargeStr(Buffer : pAnsiChar; var BufferSize: Integer) : boolean ; stdcall; 
    var l_ansiStr : string; 
     loop : integer; 
    begin 
     Result := False; 
     //13000 ok  14000+ fail ??? 
     for loop := 1 to 15000 do 
      begin 
      l_AnsiStr := l_AnsiStr + 'String of 20 chars' + Char($0D) + Char($0A) ; 
      end; 

     if Assigned(Buffer) and (BufferSize >= Length(l_ansiStr) + 1) then 
      begin 
       //Buffer := pAnsiChar(AnsiString(l_AnsiStr)); 

       move(l_AnsiStr, Buffer^, length(l_AnsiStr) + 1); 
       Result := True; 
      end; 
     //Return actual size of output string. 
     BufferSize := Length(l_AnsiStr) + 1; 
    end ; 

가 여기 내 EXE에서 통화의 : 그것은 전혀 작동 아마 행운이야 당신이 여기가

procedure TForm1.Button7Click(Sender: TObject); 
var l_StrOut : pAnsiChar; 
    l_Str : ansistring; 
    p_Size : integer; 
begin 
    p_Size := 600000; 
    SetLength(l_Str, p_Size); 
    l_strout := pAnsiChar(l_str); 

    Memo2.Lines.Clear; 
    if RetLargeStr(l_StrOut, p_Size) 
     then Memo2.Lines.Add(l_StrOut); 
end; 
+0

이 코드는 여러 수준에서 잘못되었습니다. 어디서부터 시작해야할지 알기가 어렵습니다. –

+0

나는 여기에서 길을 잃고 필사적이다. 나는 더 이상 분명하게 보이지 않는다고 생각한다. Delphi DLL 함수를 구현하는 방법에 대한 작은 예제를 작성해 주시겠습니까? – Errol

+0

AnsiString을 반환 할 수 없습니다. 그건 불가능하다. AnsiString은 interop에 적합하지 않습니다. Delphi 용어에서 COM 문자열 유형,'BSTR' 또는'WideString'을 사용해보십시오. –

답변

1

방법 여기

내 DLL의 코드입니다. 는 DLL에서

, 당신이 할 때 :

Buffer := pAnsiChar(AnsiString(l_AnsiStr)); 

당신은 실제로 당신이 명시 적으로는 호출하기 전에 수신 버퍼를 할당 한 경우에도 호출 EXE로 DLL에서 할당 된 문자열 버퍼를 반환한다. 그 수신 버퍼 포인터는 덮어 씌워진다.

충돌은 DLL의 다른 어딘가에 할당 된 메모리 블록을 해제 할 준비가되지 않았기 때문에 발생합니다.

대신 버퍼 할당, 당신은 다음과 같이 그것에 문자열의 내용을 복사 시도 할 수 있습니다 :

if Assigned(Buffer) and (BufferSize >= Length(l_ansiStr) + 1) then 
     begin 
      move(AnsiStr[1], Buffer^, length(AnsiStr) + 1)); 
      Result := True; 
     end; 

테스트 코드 (DLL) :

library Project2; 
uses 
    SysUtils, 
    Classes; 

    function RetLargeStr(Buffer : pAnsiChar; var BufferSize: Integer) : boolean ; stdcall; 
    var l_ansiStr : string; 
     loop : integer; 
    begin 
     Result := False; 
     //13000 ok  14000+ fail ??? 
     for loop := 1 to 15000 do 
      begin 
      l_AnsiStr := l_AnsiStr + 'String of 20 chars' + Char($0D) + Char($0A) ; 
      end; 

     if Assigned(Buffer) and (BufferSize >= Length(l_ansiStr) + 1) then 
      begin 
       //Buffer := pAnsiChar(AnsiString(l_AnsiStr)); 

       move(l_AnsiStr[1], Buffer^, length(l_AnsiStr) + 1); 
       Result := True; 
      end; 
     //Return actual size of output string. 
     BufferSize := Length(l_AnsiStr) + 1; 
    end ; 

exports 
    RetLargeStr; 

begin 
end. 

테스트 코드 (EXE)을 :

unit Unit3; 

interface 

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

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

var 
    Form3: TForm3; 

implementation 

{$R *.dfm} 

function RetLargeStr(Buffer : pAnsiChar; var BufferSize: Integer) : boolean ; stdcall; external 'project2.dll'; 

procedure TForm3.Button1Click(Sender: TObject); 
var l_StrOut : pAnsiChar; 
    l_Str : ansistring; 
    p_Size : integer; 
begin 
    p_Size := 600000; 
    SetLength(l_Str, p_Size); 
    l_strout := pAnsiChar(l_str); 

    Memo1.Lines.Clear; 
    if RetLargeStr(l_StrOut, p_Size) 
     then Memo1.Lines.Add(l_StrOut); 
end; 

end. 
+1

필자는 주된 문제는 할당 해제 된 메모리에 대한 포인터를 반환하는 호출 수신자라고 생각합니다. 전체 기능을 다시 설계해야합니다. 버퍼를 var 매개 변수로 전달하지 않음으로 시작하십시오. –

+0

나는 (AnsiStr [1], Buffer ^, length (AnsiStr) + 1) 제안을 제안하고 var param을 사용하지 않기를 시도했지만 큰 문자열에는 여전히 작동하지 않습니다. 작은 줄에는 효과가 있습니다. – Errol

+0

질문을 실제 테스트 코드로 업데이트하면 지금 사용해 볼 수 있으며 문제가 무엇인지 확인할 수 있습니다. D7과 XE7을 모두 설치해야합니다. –