![]() |
Wie stelle ich sicher dass ich nichts von VCL verwende
Hallo.
Ich bin mir da bei einer Sache schon seit langem unsicher. Ich weiß, dass ich in einem Thread die VCL nicht verwenden darf. Ich weiß aber nicht genau was jetzt zur VCL gehört. Wie es mir scheint ist in diesem Fall die Unit Forms := pfui. Ist Forms die einzige Unit die zur VCL gehört? Wenn ich diese also nicht benutze bin ich auf der sichern Seite bzw.andere Units darf ich verwenden wie ExtCtrls, SysUtils? |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Also wenn "Ctrls" drin vorkommt, sieht es auch böse aus.
VCL steht für VISUAL Component Library. Du musst dir nicht merken, welche Units verboten sind, sondern einfach nur, dass du im Thread keine Bildschirmausgaben generierst. |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Hmmm... Verstehe dass noch nicht so ganz... dass das V für Visuall steht weiss ich ja :-D
aber wie ist es zB. mit Application.ProcessMessages? Hat ja nicht direkt was mit der Bildschirmausgabe zu tun. Aber in einem Thread sollte man das auch nicht verwenden, oder? Und wie ist das zB. mit TTimer? Der kommt ja aus ExtCtrls, macht aber auch keine Bildschirmausgabe. Darf ich den nun verwenden oder nicht? usw. Irgendwie blicke ich dass nicht was ich warum verwenden darf und was nicht :( Deswegen dachte ich, wenn ich einfach die und die Units nicht verwende, dann ist alles okay. Ist aber natürlich auch blöd wenn ich Units nicht verwenden würde, die nur teilweise 'bösen' Inhalt haben. Dann könnte ich den 'guten' Inhalt dieser Unit ja auch nicht verwenden... Wie Du siehtst: Ich bin verwirrt :? |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Do sollst einfach nichts auf den Bildschirm malen, also Label, Buttons, Listboxen etc. in Threads verwenden.
Meiner Ansicht nach ist es ein Designfehler, wenn ich in einem Thread mit 'Application.ProcessMessages' arbeiten muss. |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Application.ProcessMessages sollte auf den Thread sowieso keine Auswirkung haben.
IMHO sollte der Thread eine eigene MessageLoop haben, ProcessMessages arbeitet nur die Loop des Mainthreads ab.
Delphi-Quellcode:
Dieser Code erstellt im Thread eine Message-Loop. PeekMessage(MsgRec, 0, 0, 0, PM_NOREMOVE); bWorking := false; if Terminated then bWorking := true; while not Terminated do begin if not bWorking then begin GetMessage(MsgRec, 0, 0, 0); while PeekMessage(MsgRec, 0, 0, 0, PM_REMOVE) do begin TranslateMessage(MsgRec); DispatchMessage(MsgRec); end; end else bWorking := false; end; GetMessage wartet auf die nächste Nachricht. Mit Translate und Dispatch den Inhalt der Loop lesen. QED => Application.ProcessMessages bewirkt im Thread nix, ausser das du vielleicht eine fürchterliche Race-Condition heraufbeschwörst wenn im MainThread Application.ProcessMessages verwendet wird |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
GetMEssage und Peekmessage kurz hintereinander? Da gehen dir abher ein paar MEssages verloren.
|
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Der Grund warum ich Application.ProcessMessages ist folgender: Ich habe eine DLL geschrieben, welche von anderen Programmieren benutzt werden soll. Die Funktionen sollen auch in einem Thread aufrufbar sein. Dazu habe ich
![]() Nun wird eine Funktion dazu verwendet einen DSP per USB zu pollen. Ist unschön, aber lässt sich durch den Anwendungsfall nicht ändern. Nun kann es sein, dass der DSP (aus welchen Gründen auch immer) rebootet. Das heißt er ist nach einigen Sekunden wieder da. Wenn dies passiert, muss ich in der Funktion solange warten (ich darf nicht vorher aus der Funktion zurückkehren) bis er wieder da ist. Dazu habe ich mir ein 'Notifyer Objekt' gemacht. Ich reagiere auf die entsprechenden WM, prüfe dann auf VendorID usw. Nun möchte den Notifyer alle 100 ms abfragen ob sich was getan hat. Ich habe also erst sleep(100) gemacht und dann nachgeschaut. Das funktioniert allerdins nicht. Sleep scheint wohl die ganze Anwendung komplett lahm legt und somit hat mein Notifyer die WM wohl nicht mitbekommen. Dann habe ich mir als Alternative zu sleep diese Lösung überlegt:
Delphi-Quellcode:
So funktioniert es zwar, aber wenn die Funktion in einem Thread aufgerufen wird, wird somit ja auch Application.ProcessMessages in einem Thread aufgerufen. Kann ich denn irgendwie dafür sorgen dass die mein Notifyer mit einer anderen Lösung als der oben Genannten weiterarbeiten kann?
Sleeper := 0;
while Sleeper < 100 do begin Sleep(1); inc(Sleeper); Application.ProcessMessages; end; |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Wieso brauchts du Application.ProcessMessages in einem Thread? Hast du mal in der Hilfe nachgeguckt, was diese Methode überhaupt macht? Sie sorgt dafür, dass dein Fenster die Nachrichtenschlange abarbeitet und so noch auf eingaben reagiert. Da ein Thread aber sowieso von deinem Hauptthread mit dem Fenster entkoppelt ist, ist der Aufruf von Application.ProcessMessages unsinnig.
|
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Ja, ich habe da schon mal nachgelesen:
Da der Notifyer nicht mehr funktioniert hat, bin ich davon ausgegangen dass die WM noch in der Nachrichtenschlange hängt und nicht abgearbeitet wird. Deswegen dache ich, ich kann das so umgehen: Zitat:
Dass sich das jetzt nur auf Eingaben bezieht, wird für mich aus der Hilfe nicht ersichtlich :? Bezieht sich dass nicht auch auf WM? |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Alle Windowsnachrichten, die mit WM_... anfangen sind Fensternachrichten, das heißt, sie werden an Fenster gesendet. Hat dein Thread ein Fenster und eine Nachrichtenschleife?
|
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Zitat:
Die Objekt Variable meines Notifyer ist in der DLL global definiert. Das Notifyer Objekt wird in einer "init" Funktion (welche immer als erstes aufgerufen werden muss wenn man andere Funktionen der DLL verwenden möchte) erstellt. Das Notifyer Objekt reagiert auf die WM:
Delphi-Quellcode:
Ich mache nur die DLL. Es kann sein dass eine Funktion der DLL in einem Thread aufgerufen wird, muss aber nicht. Das weiß ich leider nicht.
constructor TNotifyUSB.Create(AOwner: TComponent);
begin inherited Create(AOwner); FWindowHandle := AllocateHWnd(WndProc); USBNotifyRegister; ... end; function TNotifyUSB.USBNotifyRegister: Integer; var dbi : DEV_BROADCAST_DEVICEINTERFACE; Size : Integer; r : Pointer; ret : Integer; begin ret := DLL_CO_USB_NOTIFY_REGISTER_FAILED; Size := SizeOf(DEV_BROADCAST_DEVICEINTERFACE); ZeroMemory(@dbi, Size); dbi.dbcc_size := Size; dbi.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE; dbi.dbcc_reserved := 0; dbi.dbcc_classguid := GUID_DEVINTERFACE_USB_DEVICE; dbi.dbcc_name := nil; r := RegisterDeviceNotification(FWindowHandle, @dbi, DEVICE_NOTIFY_WINDOW_HANDLE); if Assigned(r) then ret := 0; // ??? Retwert anpassen Result := ret; end; procedure TNotifyUSB.WndProc(var Msg: TMessage); begin if (Msg.Msg = WM_DEVICECHANGE) then begin try WMDeviceChange(Msg); except Application.HandleException(Self); end; end else Msg.Result := DefWindowProc(FWindowHandle, Msg.Msg, Msg.wParam, Msg.lParam); end; |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
1. So ein Windowhandle klappt. Aber wie gesagt, wenn es in einem eigenen Thread läuft brauchst du eine Messageschleife. Die kannst du allerdings nicht selber implementieren, sondern du musst dies dem Anwender deiner DLL mitteilen.
2. Schau dir mal die Methoden Dispatch und DefaultHandler an. Damit kannst du deine WindowProc-Funktion "schicker" aufbauen. |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Muss da jetzt doch nochmal nachhaken:
Ist das Application.ProcessMessages hier wirklich sinnlos?
Delphi-Quellcode:
Also folgende Situation: Meine DLL Init Funktion wird im Main Thread aufgerufen. In dieser wird meine Notifyer Objekt erstellt, welcher ein Fenster(-handle) ist welches auf (USB-)WM wartet und bei den entsprechenden WM irgendwelche Aktionen ausführt. Damit gehört diese Fenster doch zum MainThread!?
Sleeper := 0;
while Sleeper < 100 do begin Sleep(1); inc(Sleeper); Application.ProcessMessages; end; Nehmen wir mal an, jetzt wird eine andere DLL-Funktion in einem anderen Thread aufgerufen, mein USB Gerät rebootet und ich muss warten, bis mein Notifyer erkennt dass es wieder da ist. Ich kehre also aus der Funktion vorerst nicht zurück. Damit müsste der MainThread solange lahmgelegt sein, oder? Also kann mein Notifyer nicht auf die WM reagieren, oder? Um dies zu verhindern, also um dafür zu sorgen, dass die WM im Mainthread weiter abgearbeitet werden und mein Notifyer wieterhin funktioniert, müsste Application.ProcessMessages hier doch sogar notwendig sein, oder? Oder habe ich das Prinzip falsch verstanden? Nochmals vielen Dank für eure Hilfe und Geduld mit mir. |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Wenn du die DLL programmierst, umnd die Funktion nicht zurückkehren darf, bis das Ding am USB anschlus rebootet ist, ,dann kehrst duu nicht zurück und PUNKT ;)
Wenn der entwickeler der anwendung, der deine dll benutzt dann aber möchte, dass seine anwendung nicht einfreirt, weil die dll-fkt nicht zurückkehrt, dann soll er das eben in einen thread packen ;) :arrow: Wenn deine DLL-Funktionen blockieren, dann tun sie es eben. Es istt nicht die aufgabe der DLL dafür zu sorgen, dass die Anwendung flüssig läuft. Just my 2 cents ;) |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Oh mann, da habe ich gerade aber nen gewaltigen gedanken fehler :wall:
Der abgespaltet Thread wird natürlich lahmgelegt und der MainTread sollte weiter laufen -> Notifyer funktioniert -> Application.ProcessMessages nicht notwending. Wenn meine Funktion aber nicht in einem separten Thread aufgerufen wird, (was nicht muss aber sein kann, weiss es ja leider nicht), dann ist Application.ProcessMessages notwendig oder? |
Re: Wie stelle ich sicher dass ich nichts von VCL verwende
Nein. Application.Processmessages ist im Grunde nie notwendig.
Es ist manchmal praktisch, wenn auch etwas unsauber, wenn man verhindern möchte dass die GUI einfriert. Wenn du nett sein möchtest, kannst du dem Entwickler natürlich auch 2 Versionen anbieten: Eine blockierende, und eine die schaut, obs geht und dann entweder zurückliefert "dauert noch" oder eben den Wert. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:38 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz