DLL - Thread и безудержный секс

HOME_X
Дата: 05.10.2019 16:10:10
Доброго дня господа !

Имею первичную постановку
1.Динамический вызов из библиотека DLL
2.Создаю пользовательский объект AddSpan
3.Основная функция объекта AddSpan это Execute
4.Поле объекта Thread, который может запуска Execute в потоке (по потребности)
5.Возврат значения RecordSet, по результатам выполнения (в примере возвращаю String)

Проблема при вызове в потоке, невозможно вернуть результат


Возможное решение
1. При создание AddSpan - фиксирую адрес ячейки

constructor TAddSpan.Create(aFile: String; aBars: TProgressBar; Terminate: TTerminate; var aSql: OleVariant);
...............
pSql:=@aSql;
................

2.При создании поля-потока, фикcирую родитель-объект
constructor TAddExec.Create(aHandleParent: TAddSpan; aExecute: TExecute; aTerminate: TTerminate);
................
HandleParent :=aHandleParent;
................

3.При окончании работы потока - уничтожаю родитель-объект, предварительно по адресу
передав результат выполнения функции Execute

procedure TAddExec.TerminateThread(Sender: TObject);
begin
HandleParent.pSql^:=OleVariant(HandleParent.SQL); - возврат результата
HandleParent.Free;
HandleParent:=Nil;
AddTerminate(Sender); - доп. процедура которая в основной форме
end;

Не нравится
- " окончания работы потока - уничтожаю родитель-объект"
уничтожить из дочери - родителя - не есть архитектурно !

- слишком сексуально !!!! и много извращений связанных с адресами переменных

Но другого решения увы не нашел.
О великие ГУРУ прошу подсказать более технологичное решение (можно с примером)

Заранее благодарен !

Имею код вызова
Create_AddSpan: function(aFile: String; aList: String; aThread: Boolean; aBar: TProgressBar; Terminate: TTerminate; var aSql: OleVariant): Integer; stdcall;

@Create_AddSpan:=nil;
LibHandle := LoadLibrary('MyLibrary.dll');
if LibHandle >= 32 then begin
  @Create_AddSpan:=GetProcAddress(LibHandle,'Create_AddSpan');
  if @Create_AddSpan<>nil then Create_AddSpan(aFile,aList,True,pbMain,TerminateThread,ovSql);
end;
FreeLibrary(LibHandle); //если поток уничтожать нельзя


Пользовательский класс

unit AddSpan;

type
  POleVariant = ^OleVariant;
  TAddSpan    = class;
  TExecute    = procedure of object;
  TTerminate  = procedure(Sender: TObject) of object;


  TAddExec = class(TThread)
  private
    ParentExecute: TExecute;
    AddTerminate:  TTerminate;
   protected
    //
  public
    HandleParent: TAddSpan;
    constructor   Create(aHandleParent: TAddSpan; aExecute: TExecute; aTerminate: TTerminate);
    procedure     Execute; override;
    procedure     TerminateThread(Sender: TObject);
  published
    //
  end;

  TAddSpan = class(TObject)
  private
    thExec:   TAddExec;
    mtExit:   TTerminate;
    pSql:     POleVariant;
 protected
    //
 public
    SQL:        String;
    constructor Create(aFile: String; aBars: TProgressBar; Terminate: TTerminate; var aSql: OleVariant); virtual;
    procedure   Execute;
    procedure   ExecuteThread;
  published
    //
  end;

implementation

  function Create_AddSpan(aFile: String; aList: String; aThread: Boolean; aBar: TProgressBar; Terminate: TTerminate; var aSql: OleVariant): Integer;
  var A: TAddSpan;

      I: Integer;
      L: Boolean;
      S,List: String;

  begin
    A:=TAddSpan.Create(aFile,aBar,Terminate,aSql);
    .........................
    if aThread then A.ExecuteThread else A.Execute;

    //если поток уничтожать нельзя - 3-и строки это ошибка
    aSql:=OleVariant(A.sSql);
    A.Free;
    A:=Nil;
  end;

  constructor TAddExec.Create(aHandleParent: TAddSpan; aExecute: TExecute; aTerminate: TTerminate);
  begin
    Inherited Create(True);
    HandleParent   :=aHandleParent;
    ParentExecute  :=aExecute;
    AddTerminate   :=aTerminate;
    FreeOnTerminate:=True;
    OnTerminate    :=TerminateThread;
  end;

  procedure TAddExec.TerminateThread(Sender: TObject);
  begin
    HandleParent.pSql^:=OleVariant(HandleParent.SQL);
    HandleParent.Free;
    HandleParent:=Nil;
    AddTerminate(Sender);
  end;

  procedure TAddExec.Execute;
  begin
    ParentExecute;
  end;

  constructor TAddSpan.Create(aFile: String; aBars: TProgressBar; Terminate: TTerminate; var aSql: OleVariant);
  var I: Integer;
      S: TArrayStr;
      Sect,Note: String;
  begin
    Inherited Create;
    .........................
    mtExit:=Terminate;
    pSql:=@aSql;
  end;

  destructor TAddSpan.Destroy;
  begin
    .................
    inherited;
  end;

  procedure TAddSpan.Execute;
  var I: Integer;
      L: Boolean;

  begin
    CoInitialize(nil);
    try
      SQL:='значение этой переменной нужно вернуть';
    ................................
    end;
    CoUninitialize;
  end;

  procedure TAddSpan.ExecuteThread;
  begin
    thExec:=TAddExec.Create(Self,Self.Execute,Self.mtExit);
    thExec.Resume;
  end;

end.
ёёёёё
Дата: 05.10.2019 16:18:46
HOME_X,

используй сообщения. Рабочая нить выделяет память под результат и, выполнив работу, посылает сообщение потребителю. Потребитель последовательно выгребает сообщения из очереди, обрабатывает и освобождает память.
Сто раз описано, в том числе и здесь.
HOME_X
Дата: 05.10.2019 16:51:34
ёёёёё
HOME_X,
Сто раз описано, в том числе и здесь.


Если желаете помочь - пишите четко, и на конкретном примере
Если НЕ желаете помочь НЕ пишите в 101 раз...

Спасибо
ёёёёё
Дата: 05.10.2019 16:58:46
HOME_X,

а что тебе непонятно, конкретно? Не знаешь, что такое сообщения, сообщения Windows, очередь сообщений нити, ... - что?
HOME_X
Дата: 05.10.2019 17:32:29
ёёёёё
HOME_X,

а что тебе непонятно, конкретно? Не знаешь, что такое сообщения, сообщения Windows, очередь сообщений нити, ... - что?



Изложите Ваши мысли в конкретный программный код

Спасибо
Dimitry Sibiryakov
Дата: 05.10.2019 17:59:06

HOME_X
Имею первичную постановку
1.Динамический вызов из библиотека DLL

Твой код где: в основном приложении или в библиотеке? Потоки где: в основном приложении
или библиотеке?

Во втором случае обломись, потоки и DLL это тема на которой обламывают зубы даже зубры,
новичкам туда лучше не лезть вообще.

Posted via ActualForum NNTP Server 1.5

HOME_X
Дата: 05.10.2019 18:54:22
Dimitry Sibiryakov
HOME_X
Имею первичную постановку
1.Динамический вызов из библиотека DLL

Твой код где: в основном приложении или в библиотеке? Потоки где: в основном приложении
или библиотеке?

Во втором случае обломись, потоки и DLL это тема на которой обламывают зубы даже зубры,
новичкам туда лучше не лезть вообще.


1.
- пользовательский объект находиться в DLL
- в этом объекте находиться метод Execute, вызываться как линейно так и в потоке
- в этом объекте находиться метод ExecuteThread, который "заворачивает" Execute
и выполняет его в потоке
- этот объект возвращает тип RecordSet (OleVariant - так как эта DLL будет использоваться
НЕ только исходниками Delphi)
- вызывающий код, находиться в основном приложении , вызов объекта осуществляется динамически
(LoadLibrary->FreeLibrary)

Если есть еще вводные вопросы - прошу Вас.....

P.S. "зубы даже зубры"
Зубрами не рождаются, "горшки не только программисты обжигают"
Во времени особо не ограничен, если конкретизируете тему "потоки и DLL" (примеры , статьи , ссылки)
узнать новое и практически применить знания буду рад.


Спасибо за уделенное время.
ziv-2014
Дата: 05.10.2019 18:55:59
Dimitry Sibiryakov
HOME_X
Имею первичную постановку
1.Динамический вызов из библиотека DLL

Твой код где: в основном приложении или в библиотеке? Потоки где: в основном приложении
или библиотеке?

Во втором случае обломись, потоки и DLL это тема на которой обламывают зубы даже зубры,
новичкам туда лучше не лезть вообще.

Какая разница, где поток в основном приложении или в DLL? Потоку в общем-то насрать, где крутиться.
Проблема в менеджере памяти и общих данных.
Есть особенности работы при инициализации DLL, но в целом потоку без разницы.

А вообще тема норм, хорошо названа, побольше бы таких тем
ziv-2014
Дата: 05.10.2019 19:02:19
HOME_X,
+
 function Create_AddSpan(aFile: String; aList: String; aThread: Boolean; aBar: TProgressBar; Terminate: TTerminate; var aSql: OleVariant): Integer;
  var A: TAddSpan;

      I: Integer;
      L: Boolean;
      S,List: String;

  begin
    A:=TAddSpan.Create(aFile,aBar,Terminate,aSql);
    .........................
    if aThread then A.ExecuteThread else A.Execute;

    //если поток уничтожать нельзя - 3-и строки это ошибка
    aSql:=OleVariant(A.sSql);
    A.Free;
    A:=Nil;
  end;


А кто поток ждать будет? А вообще это лучше реализовывать на интерфейсах.
HOME_X
Дата: 05.10.2019 19:37:12
ziv-2014
Какая разница, где поток в основном приложении или в DLL?
А вообще тема норм, хорошо названа, побольше бы таких тем


....OleVariant - так как эта DLL будет использоваться НЕ только исходниками Delphi

Основное приложение (оно же Delphi, оно же VBS, оно же VBA, оно же ............)
ссылается на логически законченный объект, который в DDL

Побольше технологически грамотных решений и понимания тоже не помешает..

А кто поток ждать будет?
А вообще это лучше реализовывать на интерфейсах.

В Delphi - основная форма - AddTerminate

 procedure TAddExec.TerminateThread(Sender: TObject);
  begin
    HandleParent.pSql^:=OleVariant(HandleParent.SQL);
    HandleParent.Free;
    HandleParent:=Nil;
    AddTerminate(Sender); - это процедура основной формы, которая обновить 'дерево" штатки
  end;


Буду рад осмотреть Ваш вариант решения
если начальных вводных недостаточно - прошу вопрошать..