Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 2 [3] 4   вперед  Ctrl      все
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11196
Kazantsev Alexey
Вангую, это такая соломка от:
Зато будет сюрприз
var
  Some: TSomethingImplementor;
begin
  Some := TSomethingImplementor.Create;
  try
    DoSomething(Some);
  finally
    Some.Free;  // Surprise!
  end;
end;

У себя всегда пишу так
TSomethingImplementor = class(..., ISomething)
................
public
  class function CreateIntf: ISomething; inline;
end;

class function TSomethingImplementor.CreateIntf: ISomething; 
begin
  Result := Self.Create;
end;
10 июн 19, 18:58    [21906153]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3832
_Vasilisk_
Зато будет сюрприз

А так не будет:
DoSomething(TSomethingImplementor.Create As ISomething);

Тут уж, либо с интерфейсами работаем, либо вручную объектами управляем.
10 июн 19, 19:23    [21906161]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
alekcvp
Member

Откуда:
Сообщений: 1553
shonli95
alekcvp,

function GetDynData(const AFlags: DWORD; out AData: Pointer; out ADataSize: DWORD): BOOL; stdcall;
var
  P: array of Something;
begin
  P := { ... готовим данные ... };
 
  ADataSize := Length(P) * SizeOf(Something);
  AData := CoTaskMemAlloc(ADataSize);
  Move(Pointer(P)^, AData^, ADataSize);
 
  Result := True;
end;




Я же специально указал раздел "выделенные функции", там в dll другой код - найдите тут CoTaskMemAlloc:

unction GetDynData(const AFlags: DWORD; out AData: Pointer; out ADataSize: DWORD): BOOL; stdcall;
var
  P: array of Something;
begin
  P := { ... готовим данные ... };
 
  ADataSize := Length(P) * SizeOf(Something);
  Pointer(AData) := Pointer(P); // копируем указатель, не копируем данные
  Pointer(P) := nil; // блокируем автоматическую очистку 
 
  Result := True;
end;
 


И текст из статьи, цитирую:
Другой вариант - обернуть ваш предпочитаемый менеджер памяти в экспортируемую функцию. Соответственно, в документации к функции должно быть указано, что для освобождения памяти нужно вызывать не CoTaskMemFree (или что вы там использовали), а вашу функцию-обёртку.
10 июн 19, 19:32    [21906169]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
shonli95
Member

Откуда:
Сообщений: 85
alekcvp,

Всё - всё, понял - понял)
10 июн 19, 20:13    [21906185]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
GunSmoker
Member

Откуда:
Сообщений: 3110
alekcvp, спасибо, исправил.
11 июн 19, 03:03    [21906290]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
GunSmoker
Member

Откуда:
Сообщений: 3110
_Vasilisk_
с какого перепугу?


У меня под конец уже время закончилось, я уж не стал расписывать, тем более, что в блоге и так было. Так да, это "защита от дурака".
11 июн 19, 03:12    [21906291]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
SQL-Talker
Member

Откуда: Если есть на свете рай, это - ...
Сообщений: 419
В статье про DLL предлагается использовать BSTR получения/передачи строковых данных.
Пытаюсь в DLL, написанной в Delphi, возвращать строковое значение из функции в WideString (он же BSTR), но получается ерунда.
Если DLL вызывать из программы написанной в Delphi то все хорошо, если вызывать из C++, то получаем ошибку "Out of memory".

Код DLL:
+
library test_ws;

uses
  System.SysUtils,
  Vcl.Dialogs;

function TestWideString: WideString; stdcall;
begin
  try
    Result := 'This is the result of TestWideString';
  except
    on E:Exception do
      ShowMessage('Delphi exception::TestWideString : ' + E.Message); // In C++ : Out of memory
  end;
end;

exports
  TestWideString;

begin
end.

Вызов DLL из Delphi (все работает):
+
program test_ws_call;

{$APPTYPE CONSOLE}

uses
  Windows, System.SysUtils;

type
  TTestWideString = function : WideString; stdcall;

var
  LibHandle: THandle;
  TestWideString: TTestWideString;
  str: WideString;
begin
  LibHandle := LoadLibrary('test_ws.dll');
  @TestWideString := GetProcAddress(LibHandle, 'TestWideString');
  str := TestWideString();
  Writeln(str);

  ReadLn;
end.

Вызов из C++ (ошибка "Out of memory"):
+
#include <iostream>
#include <windows.h>

using namespace std;

int main()
{
    HMODULE lib = LoadLibrary("test_ws.dll");

    typedef BSTR (__stdcall *Func)();
    Func TestWideString = (Func) GetProcAddress(lib, "TestWideString");

    BSTR str = TestWideString();
    wprintf(L"%s\n", str);
    SysFreeString(str);

    return 0;
}


Что тут не так? Почему не работает?
Или идея с BSTR не совсем рабочая?
10 июл 19, 11:04    [21924033]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5215
SQL-Talker,

а так пробовал?
typedef BSTR* (__stdcall *Func)();
10 июл 19, 12:01    [21924081]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
SQL-Talker
Member

Откуда: Если есть на свете рай, это - ...
Сообщений: 419
kealon(Ruslan),

При таком варианте, компилятор выдает ошибку на строке вызова функции:
error: cannot convert 'OLECHAR** {aka wchar_t**}' to 'BSTR {aka wchar_t*}' in initialization
10 июл 19, 13:51    [21924175]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11196
Импорт должен быть таким
 typedef void (__stdcall *Func)(BSTR * res);

Ссылку на документацию найти не могу, но для сложных возвращаемых типов (строки, записи, массивы) в Delphi функция превращается в процедуру с последним var параметром.

Т.е. это
SQL-Talker
function TestWideString: WideString; stdcall;
компилятор превращает в это
procedure TestWideString(var Result: WideString); stdcall;
10 июл 19, 16:18    [21924280]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
asutp2
Member

Откуда: Тюмень
Сообщений: 545
GunSmoker
alekcvp, спасибо, исправил.


GunSmoker, подкорректируйте плиз тогда и глобальный пример, который у вас приложен к статье :-)
10 июл 19, 16:58    [21924310]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
SQL-Talker
Member

Откуда: Если есть на свете рай, это - ...
Сообщений: 419
_Vasilisk_,

Заработало! Спасибо))
10 июл 19, 17:06    [21924316]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5215
SQL-Talker,

лучше уж тогда safecall заюзать, однотипно будет хоть
10 июл 19, 17:10    [21924318]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
SQL-Talker
Member

Откуда: Если есть на свете рай, это - ...
Сообщений: 419
kealon(Ruslan),

stdcall - требование заказчика
10 июл 19, 17:31    [21924334]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5215
SQL-Talker,

да это и есть тот же stdcall, только результат функции всегда один и тот же тип
10 июл 19, 18:13    [21924364]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
ziv-2014
Member

Откуда:
Сообщений: 462
kealon(Ruslan),
stdcall и safecall - это не одно и тоже. При safecall результат возвращается в параметрах.
10 июл 19, 19:32    [21924403]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5215
ziv-2014,

а при stdcall это невозможно? :-)

абсолютно тот же stdcall, только результат функции всегда HResult
10 июл 19, 20:08    [21924414]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
SQL-Talker
Member

Откуда: Если есть на свете рай, это - ...
Сообщений: 419
Правильно ли я понимаю, что для функции типа
function SomeFunction(Check: BOOL): BSTR; stdcall;

В C++ импорт должен быть таким:
typedef void (__stdcall *Func)(BOOL, BSTR * res);


Пробую так делать - вылетает ошибка при выполнении.
11 июл 19, 09:22    [21924529]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5215
SQL-Talker,

я бы предложил взять idl-ку какую ни будь из SDK как шаблон - компиляция там простая, и извращаться там (т.е. описывать всё на одном языке). Для Delphi и fpc тоже консолька импорта в pas есть.
Так вы сможете понять как это будет выглядеть на других языках. Ну и конечно safecall, он удобнее.
11 июл 19, 09:39    [21924550]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
ziv-2014
Member

Откуда:
Сообщений: 462
SQL-Talker
Правильно ли я понимаю, что для функции типа
function SomeFunction(Check: BOOL): BSTR; stdcall;

В C++ импорт должен быть таким:
typedef void (__stdcall *Func)(BOOL, BSTR * res);


Пробую так делать - вылетает ошибка при выполнении.

Так должно быть
function SomeFunction(Check: BOOL): BSTR; safecall;


HRESULT __stdcall SomeFunction(BOOL, BSTR &res);
описание типа:
typedef HRESULT (__stdcall *Func)(BOOL, BSTR &res);
11 июл 19, 14:46    [21924954]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
ziv-2014
Member

Откуда:
Сообщений: 462
SQL-Talker,
Лучше переходи на интерфейсы (interface), так больше возможностей получаешь.
Получаешь типа такого на си++:
+

  DECLARE_INTERFACE_IID_(ICMWebRTCNative, IUnknown, "{D7C7A33F-CCE8-403A-B95E-44F2DE7493D4}")
  {
    IUNKNOWN_METHODS_PURE()
    virtual HRESULT __stdcall InitializeSSL();
    virtual HRESULT __stdcall CleanupSSL();
    virtual HRESULT __stdcall AddIceServer(_In_ BSTR uri, _In_ BSTR username, _In_ BSTR password);
    virtual HRESULT __stdcall ClearIceServers();
    virtual HRESULT __stdcall InitializePeerConnection(_Out_ BOOL &init);
    virtual HRESULT __stdcall ClosePeerConnection();
    virtual HRESULT __stdcall ProcessMessages(_In_ int delay, _Out_ BOOL &result);
    virtual HRESULT __stdcall PushFrame(_In_ ICMVideoCapturer * capturer, _In_ BITMAPINFO bmi, _In_ uint8_t * image, _Out_ BOOL &result);
    virtual HRESULT __stdcall CreateOffer(_Out_ BOOL &result);
    virtual HRESULT __stdcall CreateAnswer(_In_ BSTR sdp, _Out_ BOOL &result);
    virtual HRESULT __stdcall AddIceCandidate(_In_ BSTR  sdp_mid, _In_ int sdp_mlineindex, _In_ BSTR sdp, _Out_ BOOL &result);
    virtual HRESULT __stdcall SetRemoteDescription(_In_ BSTR type, _In_ BSTR sdp, _Out_ BOOL &result);
    virtual HRESULT __stdcall CreateDataCanal(_In_ BSTR label, _Out_  BOOL &result);
    virtual HRESULT __stdcall CreateAudioStream(_In_ BSTR label, _In_ STREAMLIST ids, _In_ AUDIOPARAMS params, _Out_ BOOL &result);
    virtual HRESULT __stdcall CreateCameraStream(_In_ BSTR label, _In_ STREAMLIST ids, _In_ BSTR device_id, _In_ VIDEOINFO info, _In_ VIDEOPARAMS params, _Out_ BOOL &result);
    virtual HRESULT __stdcall CreateVideoStream(_In_ BSTR label, _In_ STREAMLIST ids, _In_ VIDEOINFO info, _In_ VIDEOPARAMS params, _Out_ ICMVideoCapturer * capturer, _Out_ BOOL &result);
  };



Делфи:
+

  ICMWebRTCNative = interface
    ['{D7C7A33F-CCE8-403A-B95E-44F2DE7493D4}']
    procedure InitializeSSL; safecall;
    procedure CleanupSSL; safecall;
    procedure AddIceServer(uri, username, password : CMString); safecall;
    procedure ClearIceServers(); safecall;
    function InitializePeerConnection : LongBool; safecall;
    procedure ClosePeerConnection; safecall;
    function ProcessMessages(delay : Integer) : LongBool; safecall;
    function PushFrame(const Capturer : ICMVideoCapturer; bmi : TBitmapInfo; image : PByte) : LongBool; safecall;
    function CreateOffer() : LongBool; safecall;
    function CreateAnswer(sdp : CMString) : LongBool; safecall;
    function AddIceCandidate(sdp_mid : CMString; sdp_mlineindex : Integer; sdp : CMString) : LongBool; safecall;
    function SetRemoteDescription(_type, sdp : CMString) : LongBool; safecall;
    function CreateDataCanal(_label : CMString) : LongBool; safecall;
    function CreateAudioStream(_label : CMString; ids : TStreamList; params : TAudioParams) : LongBool; safecall;
    function CreateCameraStream(_label : CMString; ids : TStreamList; device_id : CMString; Info : TVideoInfo; Params : TVideoParams) : LongBool; safecall;
    function CreateVideoStream(_label : CMString; ids : TStreamList; info : TVideoInfo; Params : TVideoParams; var capturer : ICMVideoCapturer) : LongBool; safecall;
  end;



Красота :)
11 июл 19, 14:51    [21924958]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11196
SQL-Talker
Пробую так делать - вылетает ошибка при выполнении.
Проверь sizeof(BOOL) в Си и Делфи. А лучше использовать типы с явным размером. Например, WordBool

SQL-Talker
- вылетает ошибка при выполнении.
Где? Какая ошибка?

ziv-2014
Так должно быть
Не должно
11 июл 19, 15:01    [21924976]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5215
ziv-2014,

кстати, вполне вариант, условия на статик линковку у него вроде нет, судя по тому что он динамически грузит функцию

загрузил одну функцию возвращающую интерфейс и всё

интерфейс в idl описал для надёжности, лепота...
11 июл 19, 15:32    [21925016]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
SQL-Talker
Member

Откуда: Если есть на свете рай, это - ...
Сообщений: 419
_Vasilisk_,

И в Delphi и в C++ sizeof(BOOL) = 4

Вот исходники:
Delphi DLL:
+
library test_ws_b;

uses
  System.SysUtils,
  Vcl.Dialogs;

function GetLastErrText_CH(Check: WordBool): WideString; stdcall;
begin
  Pointer(Result) := nil;
  if Check then
    Result := 'This is the result of GetLastErrText - TRUE'
  else
    Result := 'This is the result of GetLastErrText - FALSE'
   ;
end;

exports
  GetLastErrText_CH;

begin
end.

C++:
+
#include <iostream>
#include <windows.h>

using namespace std;

int main()
{
    std::cout << "\nsizeof(BOOL) = " << sizeof(BOOL); // 4
    HMODULE lib = LoadLibrary("test_ws_b.dll");
    if (lib == NULL) {
        std::cout << "\nLibrary not loaded";
        return -1;
    };

    typedef void (__stdcall *Func)(BOOL, BSTR * res);
    Func GetLastErrText_CH = (Func) GetProcAddress(lib, "GetLastErrText_CH");
    if (GetLastErrText_CH == 0) {
        std::cout << "\nFunction GetLastErrText_CH not found in Library";
        return -2;
    };

    BSTR bstr;
    std::cout << "\nbefore call";
    GetLastErrText_CH(true, &bstr);
    std::cout << "\nafter call";

    setlocale(LC_ALL, "Russian_Russia.866");
    std::wcout << bstr;

    SysFreeString(bstr);

    return 0;
}

При выполнении си-шного кода, спотыкается об строку вызова функции из DLL и выдает в консоль "Process returned -1073741819 (0xC0000005)"
Это если из IDE запускать (Code::Blocks), а так молча завершается
11 июл 19, 15:50    [21925038]     Ответить | Цитировать Сообщить модератору
 Re: DLL - Написать DLL, в ней функцию, которая возвращает массив записей.  [new]
SQL-Talker
Member

Откуда: Если есть на свете рай, это - ...
Сообщений: 419
Пардон, заголовок функции в Delphi такой :
function GetLastErrText_CH(Check: BOOL): WideString; stdcall;
11 июл 19, 15:56    [21925044]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 2 [3] 4   вперед  Ctrl      все
Все форумы / Delphi Ответить