Проблема с DLL, формой и потоком (все в одном) в delphi - PullRequest
3 голосов
/ 26 апреля 2011

есть очень сложное приложение, которое я пытаюсь создать.

Есть библиотека DLL, которую я создаю. Я вставил в него форму и добавил в нее тему.

в DLL у меня есть функция:

procedure ShowForm; stdcall;
var
Form1 : TFormSNVFL7;
begin
  Form1 := TFormSNVFL7.Create(nil);
  Form1.Show;
end;

Я создаю форму и показываю ее. здесь нет проблем Я добавляю нить в эту DLL. я поставил таймер в форме. через пару секунд я создаю поток и запускаю его. все идет нормально, но когда я пытаюсь что-то изменить в форме, ничего не происходит.

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

Вот файлы:

DLL pas:

library uploader;

uses
  SysUtils,
  Classes,
  Forms,
  UploaderForm in 'UploaderForm.pas' {FormUploader},
  ThreadUpload in 'ThreadUpload.pas';

{$R *.res}

procedure ShowForm; stdcall;
var
  upForm: TFormUploader;
begin
  upForm := TFormUploader.Create(nil);
  upForm.Show;
end;

exports
ShowForm;

begin
end.

Форма па:

unit UploaderForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, acPNG, ExtCtrls, JvExExtCtrls, JvImage, JvExControls, JvLabel,
  JvAnimatedImage, JvGIFCtrl, ComCtrls, JvExComCtrls, JvProgressBar, StdCtrls,
  FileCtrl, JvDriveCtrls;

type
  TFormUploader = class(TForm)
    imgRunning: TJvImage;
    imgReady: TJvImage;
    imgUpdate: TJvImage;
    JvLabel1: TJvLabel;
    JvLabel2: TJvLabel;
    imgConnect: TJvImage;
    imgUpload: TJvImage;
    imgCheck: TJvImage;
    JvLabel3: TJvLabel;
    JvLabel4: TJvLabel;
    JvLabel5: TJvLabel;
    JvLabel6: TJvLabel;
    imgRun: TJvImage;
    imgOK: TJvImage;
    imgDone: TJvImage;
    JvProgressBar1: TJvProgressBar;
    JvLabel7: TJvLabel;
    fileList: TJvFileListBox;
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  FormUploader: TFormUploader;

implementation

{$R *.dfm}

Uses ThreadUpload;

procedure TFormUploader.FormCreate(Sender: TObject);
begin
imgUpdate.Picture := imgReady.Picture;
imgConnect.Picture := imgReady.Picture;
imgUpload.Picture := imgReady.Picture;
imgCheck.Picture := imgReady.Picture;
imgRun.Picture := imgReady.Picture;
imgOK.Picture := imgReady.Picture;
fileList.Directory := ExtractFilePath(Application.ExeName) + 'csvexport/';
end;

procedure TFormUploader.Timer1Timer(Sender: TObject);
var
UpThread: TThread;
begin
Timer1.Enabled := False;

UpThread := UploadThread.Create(true);
UpThread.Create;
UpThread.Resume;

end;

end.

Тема потока:

unit ThreadUpload;

interface

uses
  Classes, UploaderForm;

type
  UploadThread = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

implementation

{ UploadThread }

procedure UploadThread.Execute;
begin
  With FormUploader do
  begin
    imgUpdate.Picture := imgRunning.Picture;
  end;
end;

end.

Я не могу решить эту проблему.

Ответы [ 4 ]

6 голосов
/ 26 апреля 2011

TThread.Synchronize() не работает в DLL по умолчанию, поскольку очередь синхронизации, в которую отправляется Synchronize(), является локальной для исполняющего файла, который ее вызывает. Другими словами, когда приложение вызывает Synchronize(), оно отправляет сообщение в очередь, локальную для исполняемого файла. Когда DLL вызывается Synchronize(), она отправляет сообщение в очередь, локальную для файла dll. Когда приложение перекачивает свою очередь синхронизации во время простоя, оно не будет перекачивать очередь DLL автоматически. Вы должны экспортировать функцию из вашей DLL, которую ваше приложение может затем вызывать при необходимости, например, в событии TApplication.OnIdle или в таймере. Эта экспортируемая функция может затем вызывать функцию RTL CheckSynchronize() для накачки очереди синхронизации DLL.

0 голосов
/ 18 мая 2016

У меня была похожая проблема при попытке обновить значок TToolButton в главном EXE из функции обратного вызова, вызванной DDL.DLL вызывает функцию обратного вызова в ответ на сообщение широковещания на канал, отправленное через реализацию DataSnap , я думаю, в дочернем потоке.Доступ к TToolButton напрямую из функции обратного вызова EXE приводит к мерцанию TToolBar и исчезновению значков.
Я создал объект TThread, а взаимодействие с TToolButton осуществляется с помощью функции TThread.Synchonize () в основном потоке: это решено дляme.

interface    
type
  TCallBackThread=class(TThread)

  private
    procedure DoInSync;
  public
    procedure Execute; override;
  end;
var
  CallBackThread: TCallBackThread;

implementation

procedure TCallBackThread.DoInSync;
begin
  // Jobs to be done in main thread
end;

procedure TCallBackThread.Execute;
begin
  inherited;
  Synchronize(DoInSync);
end;

Функция обратного вызова в EXE:

procedure ConnectWf_Callback(s: PAnsiChar); stdcall;
begin
  if not Assigned(CallBackThread) then begin
    CallBackThread := TCallBackThread.Create(true);
    CallBackThread.Resume;
  end else begin
    CallBackThread.Execute;
  end;
end;
0 голосов
/ 24 февраля 2013

Ваша проблема возникает из-за использования VCL и многопоточности. Вы не должны никогда вызывать связанный с VCL код из потока без использования механизмов синхронизации.

Обычно вы создаете приложение VCL, используя TApplication и TApplication.Run () для создания основного цикла вашей программы. Основной цикл обрабатывает сообщения Windows и другие вещи, но также вызывает CheckSynchronize (), тогда как CheckSynchronize () ищет, есть ли очередь вызовов, которая должна быть синхронизирована (то есть вызов, который добавляется в очередь с помощью TThread.Synchronize ()) , Поэтому, когда вы создаете поток, я запускаю его одновременно с основным циклом, и именно здесь начинается ваша проблема.

Вы должны либо переместить код назначения изображения в отдельный метод в TFormUploader и вызвать этот метод с помощью TThread.Synchronize (), либо использовать другие механизмы синхронизации, например объекты событий (TEvent / CreateEvent ()).

0 голосов
/ 26 апреля 2011

Простой

Вы изменяете свойство из Var FormUploader из модуля UploaderForm в UpThread

Но в модуле DLL.pas вы создаете другой объект из TFormUploader

Попробуйте сделать это в процедуре, которая показывает форму:

procedure ShowForm; stdcall;
begin
  FormUploader := TFormUploader.Create(nil);
  FormUploader.Show;
end;

Сделайте это, и проблема будет решена

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...