powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
25 сообщений из 87, страница 3 из 4
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825089
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev AlexeyВангую, это такая соломка от:Зато будет сюрприз
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
var
  Some: TSomethingImplementor;
begin
  Some := TSomethingImplementor.Create;
  try
    DoSomething(Some);
  finally
    Some.Free;  // Surprise!
  end;
end;


У себя всегда пишу так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
TSomethingImplementor = class(..., ISomething)
................
public
  class function CreateIntf: ISomething; inline;
end;

class function TSomethingImplementor.CreateIntf: ISomething; 
begin
  Result := Self.Create;
end;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825095
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_Зато будет сюрприз
А так не будет:
Код: pascal
1.
DoSomething(TSomethingImplementor.Create As ISomething);


Тут уж, либо с интерфейсами работаем, либо вручную объектами управляем.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825099
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shonli95alekcvp,

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
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:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
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 (или что вы там использовали), а вашу функцию-обёртку .
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825110
shonli95
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
alekcvp,

Всё - всё, понял - понял)
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825156
GunSmoker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alekcvp, спасибо, исправил.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39825157
GunSmoker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_с какого перепугу?

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

Код DLL:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
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 (все работает):
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
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"):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
#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 не совсем рабочая?
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39835888
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

а так пробовал?
Код: plaintext
1.
typedef BSTR* (__stdcall *Func)();
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39835952
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan),

При таком варианте, компилятор выдает ошибку на строке вызова функции:
Код: sql
1.
error: cannot convert 'OLECHAR** {aka wchar_t**}' to 'BSTR {aka wchar_t*}' in initialization
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836017
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Импорт должен быть таким
Код: plaintext
1.
 typedef void (__stdcall *Func)(BSTR * res);


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

Т.е. это
SQL-Talker
Код: pascal
1.
function TestWideString: WideString; stdcall;

компилятор превращает в это
Код: pascal
1.
procedure TestWideString(var Result: WideString); stdcall;
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836032
asutp2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GunSmokeralekcvp, спасибо, исправил.

GunSmoker, подкорректируйте плиз тогда и глобальный пример, который у вас приложен к статье :-)
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836036
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

Заработало! Спасибо))
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836038
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

лучше уж тогда safecall заюзать, однотипно будет хоть
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836050
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan),

stdcall - требование заказчика
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836067
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

да это и есть тот же stdcall, только результат функции всегда один и тот же тип
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836090
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan),
stdcall и safecall - это не одно и тоже. При safecall результат возвращается в параметрах.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836096
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014,

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

абсолютно тот же stdcall, только результат функции всегда HResult
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836170
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Правильно ли я понимаю, что для функции типа
Код: pascal
1.
function SomeFunction(Check: BOOL): BSTR; stdcall;


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



Пробую так делать - вылетает ошибка при выполнении.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836180
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,

я бы предложил взять idl-ку какую ни будь из SDK как шаблон - компиляция там простая, и извращаться там (т.е. описывать всё на одном языке). Для Delphi и fpc тоже консолька импорта в pas есть.
Так вы сможете понять как это будет выглядеть на других языках. Ну и конечно safecall, он удобнее.
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836399
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-TalkerПравильно ли я понимаю, что для функции типа
Код: pascal
1.
function SomeFunction(Check: BOOL): BSTR; stdcall;


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



Пробую так делать - вылетает ошибка при выполнении.
Так должно быть
Код: pascal
1.
function SomeFunction(Check: BOOL): BSTR; safecall;



Код: plaintext
1.
2.
3.
HRESULT __stdcall SomeFunction(BOOL, BSTR &res);
описание типа:
typedef HRESULT (__stdcall *Func)(BOOL, BSTR &res);
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836401
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-Talker,
Лучше переходи на интерфейсы (interface), так больше возможностей получаешь.
Получаешь типа такого на си++:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
  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);
  };




Делфи:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
  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;




Красота :)
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836411
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SQL-TalkerПробую так делать - вылетает ошибка при выполнении.Проверь sizeof(BOOL) в Си и Делфи. А лучше использовать типы с явным размером. Например, WordBool

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

ziv-2014Так должно бытьНе должно
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836437
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014,

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

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

интерфейс в idl описал для надёжности, лепота...
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836451
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

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

Вот исходники:
Delphi DLL:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
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++:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
#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), а так молча завершается
...
Рейтинг: 0 / 0
DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
    #39836455
SQL-Talker
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пардон, заголовок функции в Delphi такой :
Код: pascal
1.
function GetLastErrText_CH(Check: BOOL): WideString; stdcall;
...
Рейтинг: 0 / 0
25 сообщений из 87, страница 3 из 4
Форумы / Delphi [игнор отключен] [закрыт для гостей] / DLL - Написать DLL, в ней функцию, которая возвращает массив записей.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]