delphi: dll без менеджера памяти для переноса строки - PullRequest
0 голосов
/ 05 января 2012

Delphi Xe.

Дано:

1.dll, в ней единица

unit DllUnit; interface

uses windows, sysutils;

Procedure GuPrcA(var p:PAnsiChar;const l:integer); StdCall;
Procedure GuPrcW(var p:PWideChar;const l:integer); StdCall;

Exports GuPrcA,GuPrcW;

implementation

procedure GuMes(s:string);
begin
MessageBox(0,pchar(s),'From dll',mb_iconinformation);
end;

Procedure GuPrcW(var p:PWideChar;const l:integer); // wide
var s:widestring;
begin
if (p=nil)or(l<1) then begin p:=nil;exit;end;
SetLength(s,trunc(l/sizeof(widechar)));Move(p^,Pointer(s)^,l);
gumes('l: '+inttostr(l)+', nl: '+inttostr(length(s))+#10+'-'+s+'-');
s:=widestring(Uppercase(s));Move(Pointer(s)^,p^,l);
end;

Procedure GuPrcA(var p:Pansichar;const l:integer); // ansi
var s:ansistring;
begin
if (p=nil)or(l<1) then begin p:=nil;exit;end;
SetLength(s,l);Move(p^,Pointer(s)^,l);
gumes('l: '+inttostr(l)+', nl: '+inttostr(length(s))+#10+'-'+s+'-');
s:=ansistring(AnsiUppercase(s));Move(Pointer(s)^,p^,l);
end;

Initialization

ReportMemoryLeaksOnShutdown:=true;

end.

2.Программа, у окна памятка и 2кнопки

...
implementation

{$R *.dfm}

Procedure GuPrcA(var p:PansiChar;const l:cardinal); StdCall; external 'mydll.dll' name 'GuPrcA';
Procedure GuPrcW(var p:PwideChar;const l:cardinal); StdCall; external 'mydll.dll' name 'GuPrcW';

procedure TForm1.Button6Click(Sender: TObject);
var p:pwidechar;c:cardinal;s:widestring;
begin
s:=widestring(memo1.Text);
c:=length(s)*sizeof(widechar);
p:=allocmem(c);
Move(Pointer(s)^,p^,c);
GuPrcW(p,c);
s:='';setlength(s,trunc(c/sizeof(widechar)));
Move(p^,Pointer(s)^,c);
Freemem(p,c);
memo1.Text:='='+s+'= l:'+inttostr(c);
end;

procedure TForm1.Button7Click(Sender: TObject);
var p:pansichar;c:cardinal;s:ansistring;
begin
s:=ansistring(memo1.text);
c:=length(s);
p:=allocmem(c);
Move(Pointer(s)^,p^,c);
GuPrcA(p,c);
s:='';setlength(s,c);
Move(p^,Pointer(s)^,c);
Freemem(p,c);
memo1.Text:='='+s+'= l:'+inttostr(c);
end;

Initialization

ReportMemoryLeaksOnShutdown:=true;

end.

Скачать исходный код можно и здесь: http://www.multiupload.com/WSZKF8IGP1

При нажатии кнопок происходит перевод в dll-строки (ansi или широкая строка), его отображение вmsgbox dll, его обработка там (простой прописной) и возврат в программу.Менеджер памяти не используется (быстро - просто - sharemem).И в программу, и в dll включены ReportMemoryLeaksOnShutdown (отображение событий о потерях памяти), которые оба молчат, т.е. вроде бы все работало бы и длины строк тоже везде совпадают.

что нужно :

  1. Посмотреть, нет ли там ошибок (проверить на ошибки)

  2. Можно ли оптимизировать или предложитьлучше или проще

  3. Можно ли обращаться к этой DLL с такими процедурами из VB или C ++ / C #?

Спасибо

Ответы [ 3 ]

4 голосов
/ 05 января 2012

Если вы не хотите использовать менеджер кучи для передачи данных, просто используйте WideString тип строки.

Это будет (немного) медленнее, но это позволит вам изменять длину строки на каждой стороне.

И это будет настоящий Unicode, так что у вас не возникнет проблем с набором символов и т.п. при использовании нативного Delphi UnicodeString под XE. Вы можете использовать WideString в своем коде, и преобразование в string будет выполняться без вывода сообщений.

Все это будет управляться Windows, поэтому даже не-библиотеки Delphi или приложения (такие как .Net или C ++) смогут обрабатывать его напрямую.

3 голосов
/ 05 января 2012

Вы слишком усложняете.Язык / библиотеки Delphi будут обрабатывать преобразование между строками и указателями в символьные массивы с нулевым символом в конце.

unit DllUnit; 

interface

uses 
  windows, sysutils;

Procedure GuPrcA(var p:PAnsiChar); StdCall;
Procedure GuPrcW(var p:PWideChar); StdCall;

Exports 
  GuPrcA,GuPrcW;

implementation

procedure GuMes(s:string);
begin
  MessageBox(0,pchar(s),'From dll',mb_iconinformation);
end;

Procedure GuPrcW(var p:PWideChar); // wide
var
  s: string;
begin
  s := p;
  gumes(s);
end;

Procedure GuPrcA(var p:Pansichar); // ansi
var
  s: string;
begin
  s := p;
  gumes(s);
end;

Initialization
  ReportMemoryLeaksOnShutdown:=true;

end.

И аналогично для вызывающих подпрограмм

Procedure GuPrcA(var p:PansiChar); StdCall; external 'mydll.dll' name 'GuPrcA';
Procedure GuPrcW(var p:PwideChar); StdCall; external 'mydll.dll' name 'GuPrcW';

procedure TForm1.Button6Click(Sender: TObject);
var
  s: UnicodeString;
begin
  s := memo1.Text;
  GuPrcW(PWideChar(s));
end;

procedure TForm1.Button7Click(Sender: TObject);
var
  s: AnsiString;
begin
  s := memo1.Text;
  GuPrcA(PAnsiChar(s));
end;

Я опустил весь код диагностикичто ты включил.Если вы хотите внести изменения в текст перед его отображением или перед передачей в DLL, это легко.Внесите изменения, используя стандартные строковые операции в локальных строковых переменных (всегда с именем s выше).

Например:

Procedure GuPrcA(var p:Pansichar); // ansi
var
  s: string;
begin
  s := p;
  s := s + '-' + Length(s);
  gumes(s);
end;

или

procedure TForm1.Button7Click(Sender: TObject);
var
  s: AnsiString;
begin
  s := memo1.Text;
  s := s + '-' + Length(s);
  GuPrcA(PAnsiChar(s));
end;

Суть в том, что вам совершенно не нужно писать код, который преобразует строки и указатели в массивы символов с нулевым символом в конце, поскольку Delphi сделает это за вас.

1 голос
/ 05 января 2012

С кодом

SetLength(s, trunc(l/sizeof(widechar)));
Move(p^, Pointer(s)^, l);

вы, наконец, получите поврежденную кучу программ;Я предполагаю, что вы имели в виду

SetLength(s, l);
Move(p^, Pointer(s)^, l * sizeof(widechar));

Поскольку ваш Dll не использует управляемые типы строк в разделе интерфейса, он не нуждается в диспетчере общей памяти и может использоваться с другими языками (такими как VB или C ++ / C #).

...