W jaki sposob moge sterowac watkiem tworzonym w dll chodzi o pause resume terminate z poziomu aplikacji?
Nie używałem nigdy wątków w dllach, ale jak rozumiem zadeklarowanie
zmiennej globalnej typu TThread i obslugiwanie jej przez eksportowane
procedury nie działa wcale / nie działa prawidłowo, o ile to sprawdziłeś?
Cos takiego probowalem ale nie dziala
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
Type
TTestThread = class(TThread)
private
protected
procedure Execute; override;
public
I :Integer;
end;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button5: TButton;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
Test : TTestThread;
Licznik : Integer;
public
{ Public declarations }
end;
procedure CreateTheard(Watek:TTestThread); stdcall external 'test.dll' name 'CreateTheard';
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TTestThread.Execute;
begin
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Test.Suspend;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Test.Resume;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
Test.Terminate;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Caption:=IntToStr(Test.I);
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
Caption:=IntToStr(Test.I);
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
CreateTheard(Test);
end;
end.
library test;
uses
SysUtils,
Classes,Dialogs;
Type
TTestThread = class(TThread)
private
protected
procedure Execute; override;
public
I :Integer;
end;
{$R *.res}
procedure TTestThread.Execute;
begin
ShowMessage('watek Start');
I:=1;
FreeOnTerminate := True;
while not (Terminated) do
begin
Sleep(1000);
Inc(I);
end;
ShowMessage('watek end');
end;
procedure CreateTheard(Watek:TTestThread); stdcall;
begin
Watek:=TTestThread.Create(True);
Watek.Resume;
end;
exports // eksportuj procedurę
CreateTheard name 'CreateTheard';
begin
end.
A czy Ty myślisz co robisz w ogóle? Przecież chciałeś wątek obslużyć w dllce.
To na logikę w dllce powinien być ten wątek jako zmienna globalna i to typu
TThread, a eksportowane na zewnątrz procedury mają nim "sterować", masz
jakieś problemy z rozumieniem polskiego języka w piśmie? Przecież Ty w tej
swojej dllce tylko tworzysz wątek i jest to jedyna eksportowana procedura, a
czy zadziała po tym jak spróbujesz to zrobić tak jak się powinno próbowac to
nie gwarantuję. Ale teraz w kodzie programu i dll, robisz zupełnie coś innego.
EDIT: aż sprawdziłem i nie mam pojęcia dlaczego sobie generujesz sam jakieś
problemy zamiast sprawdzić, według mnie wszystko działa jak należy. A Label
dałem po to żeby nie było problemów, bo nieraz wątki nie moga wpływać i to
nawet w tym samym programie na etykiete samej formatki. Potrzebne jest w
takim wypadku Synachronize. No ale tutaj wszystko działa, tylko że dll nieco
"spuchł", ale to nic dziwnego przy użyciu dodatkowych modułów. Oto kod dll:
library test;
uses
Classes, StdCtrls, SysUtils;
type
TMainThr = class(TThread)
private
FWhatLabel : TLabel;
public
constructor Create(WhatLabel : TLabel);
protected
procedure Execute; override;
end;
var
AThr : TThread;
constructor TMainThr.Create(WhatLabel : TLabel);
begin
inherited Create(False);
FWhatLabel := WhatLabel;
end;
procedure TMainThr.Execute;
begin
Randomize;
while Terminated = False do
begin
FWhatLabel.Caption := IntToStr(Random(99999));
Sleep(100);
end;
end;
procedure StartThread(ALabel : TLabel) stdcall;
begin
if AThr = nil then
begin
AThr := TMainThr.Create(ALabel);
end
else
begin
AThr.Resume;
end;
end;
procedure StopThread; stdcall;
begin
if AThr <> nil then
begin
AThr.Terminate;
AThr.Free;
AThr := nil;
end;
end;
procedure PauseThread; stdcall;
begin
if AThr <> nil then
begin
AThr.Suspend;
end;
end;
exports
StartThread,
StopThread,
PauseThread;
begin
end.
Kod programu. Trzy zwykłe Buttony i Label, o standadowych nazwach.
buttony muszą mieć ustawione OnClick. Nadal nie rozumiem - z czym
masz u siebie problem. Chociaż Ty zignorowałeś moje rady i coś tam
po swojemu tworzysz. Jak wątek dalej nie działa to wklej jego kod z
użyciem w dllce. Chociaż prawidlowo napisany każdy będzie działał:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1 : TButton;
Label1 : TLabel;
Button2 : TButton;
Button3 : TButton;
procedure FormCreate(Sender : TObject);
procedure Button1Click(Sender : TObject);
procedure Button2Click(Sender : TObject);
procedure Button3Click(Sender : TObject);
private
public
end;
var
Form1 : TForm1;
StartThread : procedure(ALabel : TLabel); stdcall;
StopThread : procedure stdcall;
PauseThread : procedure stdcall;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender : TObject);
var
DllH : THandle;
begin
Button1.Enabled := False;
Button2.Enabled := False;
Button3.Enabled := False;
DllH := LoadLibrary('test.dll');
if DllH <> 0 then
begin
StartThread := GetProcAddress(DllH, 'StartThread');
StopThread := GetProcAddress(DllH, 'StopThread');
PauseThread := GetProcAddress(DllH, 'PauseThread');
if (@StartThread = nil) or (@StopThread = nil) or (@PauseThread = nil) then
begin
Exit;
end;
end
else
begin
Exit;
end;
Button1.Enabled := True;
Button2.Enabled := True;
Button3.Enabled := True;
end;
procedure TForm1.Button1Click(Sender : TObject);
begin
StartThread(Label1);
end;
procedure TForm1.Button2Click(Sender : TObject);
begin
PauseThread;
end;
procedure TForm1.Button3Click(Sender : TObject);
begin
StopThread;
end;
end.
Nawet nie wiedziałem ze tak to można napisać z wątków nie jestem zbyt dobry.
Podany przez ciebie przyklad działa jak należy.Teraz moje nastepne pytanie co by trzeba dodac lub zmienic aby dll działała dla dynamicznej tablicy TLabel.Podejrzewam że bedzie potrzebyny uchwyt watku
Przekazujesz tablicę jako parametr do procedury, najlepiej poprzedzoną słowem var i
na niej operujesz, jeżeli konieczna jest pętla z operacjami na całej tej tablcy to robisz
ją od najnizszego do najwyższego elementu czyli na przykład tak jak poniżej. Myślę,
że nie powinno być z tym problemów. Jeżeli tablica ma zawierać dane typu string, to
zamiast string używasz typ PChar w dllce. Natomiast jeżeli to ma być TLabel lub inny
obiekt to możesz go przechowywać na liście wskaźników TList lub też jako obiekty na
choćby TStringList gdzie robisz AddObject('', JakisLabel); zaś do konkretnego obiektu
odwołujesz się przez TLabel*TwojaStringLista.OBjects[IndeksOdZera] i chyba tyle ;/
Ja od kąd dowiedziałem się, a bylo to nie tak dawno, bo może z rok temu, że da się
przechowywac wskaźniki na obiekty na TList i w ogołe obiekty na komponentach - z
danymi przechowywnymi jako TStrings oraz na ListView i TreeView czy StringGrid z
łatwością można przchowywac obiekty, to nie srosuje już wcale tablic dynamicznych
tylko właśnie te obiekty. Oczywiście w VCL gdzie wiadomo exe i tak Ci "spuchnie".
for I := Low(Tablica) to Hidgh(Tablica) do // ...