Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Это пример кода для статьи http://www.gunsmoker.ru/2013/04/plugins-9.html
- // Мы рассмотрим пять (современных) способов передачи данных произвольного
- // размера между двумя исполняемыми модулями (например, DLL и exe), которые
- // могут быть написаны на разных языках программирования.
- // В качестве учебной функции мы будем использовать IntToStr:
- // передаём число, функция возвращает строку.
- // Примеры ниже будут использовать экспортируемые функции для наглядности.
- // Но не забывайте, что на практике вместо глобально экспортируемых функций
- // предпочтительнее использовать методы интерфейсов - ровно как мы постоянно
- // это делаем в вышеукпомянутой серии статей.
- // Примеры приводятся с полной обработкой ошибок и пригодны для использования в
- // D3-DXE6 (с учётом UnicodeString = WideString в Delphi 2007 и ниже).
- //______________________________________________________________________________
- // Общие модули: для обработки ошибок через HRESULT.
- // Как мы уже обсуждали в серии статей, вы можете не использовать эти модули,
- // а взять из них нужные определения и функции.
- uses
- ActiveX,
- ComObj;
- //______________________________________________________________________________
- // Способ №1: BSTR/WideString (возможно только для строк)
- function EMyFunc1(const I: Integer; out Rslt: WideString): HRESULT; stdcall;
- // эквивалентно:
- // function EMyFunc1(const I: Integer): WideString; safecall;
- begin
- try
- // начало работы метода
- Rslt := IntToStr(I);
- // конец работы метода
- // обработка ошибок (этот код будет отсутствовать, если вы делаете не функцию,
- // а safecall-метод у интерфейса)
- Result := S_OK;
- except
- Result := HandleSafeCallException(ExceptObject, ExceptAddr, GUID_NULL, '', '');
- end;
- end;
- // Использование функции:
- procedure TForm1.Button1Click(Sender: TObject);
- var
- MyFunc1: function(const I: Integer): WideString; safecall;
- S: String;
- begin
- // начало вызова
- S := MyFunc1(1);
- // конец вызова
- end;
- //______________________________________________________________________________
- // Способ №2: интерфейс (обобщённый)
- type
- // Интерфейс
- IRAWData = interface
- ['{093B31B8-1A1D-46B4-9940-86DE0624A09A}']
- function Data: Pointer; safecall; // указатель на данные
- function Size: NativeUInt; safecall; // размер данных
- end;
- // Примечание: этот интерфейс имеет самый общий вид
- // (нетипизированный указатель и размер в байтах).
- // Это позволяет использовать его для передачи чего угодно, но ценой не самого
- // удобного вызова.
- // К примеру, если вы хотим передать строку, то вместо Pointer мы бы
- // использовали PWideChar, вместо Size указывали бы Length, а конструктор
- // принимал бы строку. Кроме того, данные были бы нуль-терминированы.
- // См. также альтернативный пример этого способа ниже.
- // Реализация
- TRAWData = class(TInterfacedObject, IRAWData)
- // В нашей серии статей вместо TInterfacedObject мы используем более
- // продвинутый TCheckedInterfacedObject - с дополнительными проверками и
- // обработкой ошибок. Всегда используйте TCheckedInterfacedObject вместо
- // TInterfacedObject по мере возможности. TInterfacedObject используется
- // здесь только для примера.
- private
- FData: Pointer;
- FSize: NativeUInt;
- protected
- function Data: Pointer; safecall;
- function Size: NativeUInt; safecall;
- public
- constructor Create(const ASize: NativeUInt);
- destructor Destroy; override;
- end;
- { TRAWData }
- constructor TRAWData.Create(const ASize: NativeUInt);
- begin
- inherited Create;
- FData := AllocMem(ASize);
- FSize := ASize;
- end;
- destructor TRAWData.Destroy;
- begin
- FreeMem(FData);
- FData := nil;
- FSize := 0;
- inherited;
- end;
- function TRAWData.Data: Pointer;
- begin
- Result := FData;
- end;
- function TRAWData.Size: NativeUInt;
- begin
- Result := FSize;
- end;
- function EMyFunc2(const I: Integer; out Rslt: IRAWData): HRESULT; stdcall;
- var
- S: String;
- Data: UnicodeString;
- DataSz: Integer;
- begin
- try
- // начало метода
- S := IntToStr(I);
- Data := S;
- DataSz := Length(Data) * SizeOf(WideChar);
- Rslt := TRAWData.Create(DataSz);
- Move(Pointer(Data)^, Rslt.Data^, DataSz);
- // конец метода
- Result := S_OK;
- except
- Result := HandleSafeCallException(ExceptObject, ExceptAddr, GUID_NULL, '', '');
- end;
- end;
- // Использование функции:
- procedure TForm1.Button2Click(Sender: TObject);
- var
- MyFunc2: function(const I: Integer): IRAWData; safecall;
- RAWData: IRAWData;
- Data: UnicodeString;
- S: String;
- begin
- // начало метода
- RAWData := MyFunc2(1);
- SetLength(Data, RAWData.Size div SizeOf(WideChar));
- Move(RAWData.Data^, Pointer(Data)^, RAWData.Size);
- S := Data;
- // конец метода
- end;
- //______________________________________________________________________________
- // Способ №3: интерфейс (специализированный)
- type
- // Интерфейс
- IStringData = interface
- ['{093B31B8-1A1D-46B4-9940-86DE0624A09A}']
- function Str: PWideChar; safecall; // указатель на данные строки
- function Length: Integer; safecall; // длина строки
- end;
- // Реализация
- TStringData = class(TInterfacedObject, IRAWData)
- private
- FStr: UnicodeString;
- protected
- function Str: PWideChar; safecall;
- function Length: Integer; safecall;
- public
- constructor Create(const AStr: String);
- end;
- { TStringData }
- constructor TStringData.Create(const AStr: String);
- begin
- inherited Create;
- FStr := AStr;
- end;
- function TStringData.Str: PWideChar;
- begin
- Result := PWideChar(FStr);
- end;
- function TStringData.Length: Integer;
- begin
- Result := Length(FStr);
- end;
- function EMyFunc3(const I: Integer; out Rslt: IStringData): HRESULT; stdcall;
- begin
- try
- // начало метода
- Rslt := TStringData.Create(IntToStr(I));
- // конец метода
- Result := S_OK;
- except
- Result := HandleSafeCallException(ExceptObject, ExceptAddr, GUID_NULL, '', '');
- end;
- end;
- // Использование функции:
- procedure TForm1.Button3Click(Sender: TObject);
- var
- MyFunc3: function(const I: Integer): IStringData; safecall;
- S: String;
- begin
- // начало метода
- S := MyFunc3(1).Str;
- // конец метода
- end;
- //______________________________________________________________________________
- // Способ №4: выделенная функция управления памятью
- // Примечание: аналогично способу №2, в способах №4 и 5 мы используем
- // максимально общие определения (указатель и размер в байтах). Мы можем
- // упростить вызовы таких функций, используя специализированные определения
- // (как мы сделали это в способе №3). Я не буду приводить специализированные
- // примеры для способов №4 и №5. Это остаётся вам домашним заданием.
- function EMyFunc4(const I: Integer; out AData: Pointer; out ASize: Integer): HRESULT; stdcall;
- var
- S: String;
- Data: UnicodeString;
- begin
- try
- // начало метода
- S := IntToStr(I);
- Data := S;
- ASize := Length(Data) * SizeOf(WideChar);
- GetMem(AData, ASize);
- Move(Pointer(Data)^, AData^, ASize);
- // конец метода
- Result := S_OK;
- except
- Result := HandleSafeCallException(ExceptObject, ExceptAddr, GUID_NULL, '', '');
- end;
- end;
- // Этот способ требует одной дополнительной функции на каждую DLL
- function EFreeFunc(const AData: Pointer): HRESULT; stdcall;
- begin
- FreeMem(AData);
- end;
- procedure TForm1.Button4Click(Sender: TObject);
- var
- MyFunc4: function(const I: Integer; out AData: Pointer): Integer; safecall;
- FreeFunc: procedure(const AData: Pointer); safecall;
- Data: UnicodeString;
- P: Pointer;
- Size: Integer;
- S: String;
- begin
- // начало метода
- Size := MyFunc4(1, P);
- try
- SetLength(Data, Size div SizeOf(WideChar));
- Move(P^, Pointer(Data)^, Size);
- finally
- FreeFunc(P);
- end;
- S := Data;
- // конец метода
- end;
- //______________________________________________________________________________
- // Способ №5: использование общего менеджера памяти
- // Примечание: это разновидность способа №4, где функции выделения/освобождения
- // памяти фиксированы и доступны глобально. В качестве таковых я выбрал
- // HeapAlloc/HeapFree, но вы, при желании, можете использовать любые другие
- // функции.
- function EMyFunc5(const I: Integer; out AData: Pointer; out ASize: Integer): HRESULT; stdcall;
- var
- S: String;
- Data: UnicodeString;
- begin
- try
- // начало метода
- S := IntToStr(I);
- Data := S;
- ASize := Length(Data) * SizeOf(WideChar);
- AData := HeapAlloc(GetProcessHeap, 0, ASize);
- Move(Pointer(Data)^, AData^, ASize);
- // конец метода
- Result := S_OK;
- except
- Result := HandleSafeCallException(ExceptObject, ExceptAddr, GUID_NULL, '', '');
- end;
- end;
- procedure TForm1.Button5Click(Sender: TObject);
- var
- MyFunc5: function(const I: Integer; out AData: Pointer): Integer; safecall;
- Data: UnicodeString;
- P: Pointer;
- Size: Integer;
- S: String;
- begin
- // начало метода
- Size := MyFunc5(1, P);
- try
- SetLength(Data, Size div SizeOf(WideChar));
- Move(P^, Pointer(Data)^, Size);
- finally
- HeapFree(GetProcessHeap, 0, P);
- end;
- S := Data;
- // конец метода
- end;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement