AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi non-vcl Thread innerhalb einer Klasse deklarieren

non-vcl Thread innerhalb einer Klasse deklarieren

Ein Thema von Nogge · begonnen am 3. Aug 2007 · letzter Beitrag vom 6. Aug 2007
Antwort Antwort
Seite 2 von 2     12
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.529 Beiträge
 
#11

Re: non-vcl Thread innerhalb einer Klasse deklarieren

  Alt 3. Aug 2007, 10:38
Ach Du schande. Da bin ich dann wohl wieder gefragt

So wild ist das eigentlich nicht. Ich hab irgendwo eine voll dokumentierte Version von dem ASM-Teil auf der Platte zuhause. Muss ich heut Abend mal nachgucken, wenn ich nicht in Transformers gehe.
Sebastian P.R. Gingter
不死鳥 Visit my Blog.
Do not argue with an idiot. They lower you to their level and then try to beat you with experience.
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#12

Re: non-vcl Thread innerhalb einer Klasse deklarieren

  Alt 3. Aug 2007, 11:05
@Luckie
Funktioniert auch bei mir. Früher ging das doch nicht Ich musst immer extra mit virtualalloc und virtualfree statt getmem und freemem arbeiten (z.B. bei meinem Matheparser der die Funktion auch adhoc implementiert). Naja, vielleicht war ich auch nur zu vorsichtig.

virtualprotect geht so, dass du erst mit virtualquery dir die BaseAdress und die Regionsize holst und dann mit virtualprotect dieses Segment auf Page_Execute_ReadWrite legst.


@Nogge
Das Prinzip von Luckie ist etwas verzwickt. Man könnte auch sagen unsauber,... aber schön

(ab hier für 32bit-System)
1. Unterschied zwischen Funktionszeiger und Methodenzeiger: Der Funktionszeiger besteht aus einer 32bit-Adresse die wird einfach aufgerufen , fertig. Beim Methodenzeiger liegt neben der Adresse noch ein zweiter Zeiger (self), der auf die Instanz zeigt und an die Mthode als erster (versteckter) Parameter übergeben wird. Deswegen hast du immer die Variable self zur Verfügung, damit du überhaupt auf dein Objekt zugreifen kannst. Self ist quasi der erste Übergabeparameter und steht einfach im Methodenzeiger mit drin.
Deswegen gibts TMethod.Code (der stinknormale Funktionszeiger, der einfach dahin zeigt, wo die Methode anfängt, genauso wie bei einer Funktion) und TMethod.Data der "self" beinhaltet.

2. Jetzt wirds schmutzig
Was macht diese Methode MakeProcInstance.
diese Methode schreibt einfach eine neue Funktion. Die Funktion gibts vorher noch nicht im Code und nicht in der Exe. Dazu werden 15 Byte Speicher angefordert (solang soll dei Funktion werden. Und jetzt kommt ASM, was die Methode adhoc implementiert, in dem einfach der OpCode, so wie ihn der Prozessoer will, in die 15 Bytes geschrieben wird. Darin ist halt die Variable self und der Funktionszeiger hard-gecoded enthalten. sieht dann etwa so aus:
Delphi-Quellcode:
{auf dem Stack liegt jetzt folgendes
Rücksprungadresse
Parameter 1
Parameter 2
Parameter ...
}


//zwei Konstanten deren Wert die MakeProcinstance festlegt
const self:pointer=...
      funktionszeiger:pointer=...
asm
  mov ecx,self
  pop edx //bisherige Rücksprungadresse nach edx
  push ecx //self als Parameter 0 anfügen
  push edx //Rücksprungadresse zurück auf den Stack
  mov ecx,funktionszeiger //adresse nach ecx laden
  jmp ecx //und zur Methode SPRINGEN
  //hier kein Call, ansonsten würde noch eine Rücksprungadresse auf den Stack gelegt
end;

{auf dem Stack liegt jetzt folgendes
Rücksprungadresse
Parameter 0 = self
Parameter 1
Parameter 2
Parameter ...
}
Und nur dieses self ist der Unterschied zwischen Methoden und Funktionsaufruf.
(btw: da alle Parameter auf dem Stack liegen geht eben nur stdcall)

MakeProcInstance liefert jetzt die Adresse dieser neu implementierten Funktion zurück. Und diese Funktion macht eben nix weiteres, als self (welches ja in den 15 Bytes mit enthalten ist) als Parameter vorne dran zu hängen und die eigentliche Funktion (siehe Funktionszeiger) aufzurufen.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie
(Moderator)

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#13

Re: non-vcl Thread innerhalb einer Klasse deklarieren

  Alt 3. Aug 2007, 11:17
Und warum wurde das im original Code alles mit MOV gemacht?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#14

Re: non-vcl Thread innerhalb einer Klasse deklarieren

  Alt 3. Aug 2007, 11:18
Warum so kompliziert? Bei BeginThread kann man doch einen Parameter übergeben. Man legt einfach eine Funktion (wie laut dokumentation beschrieben) an und nutzt den Parameter um die Instanz mitzugeben.

Delphi-Quellcode:
TMyClass = class
  private
    procedure ThreadProc();
  public
    procedure callThread();
  end;

[...]

{global functions}
function GlobalThreadProc(Ptr: Pointer): DWORD;
begin
  TMyClass(Ptr).ThreadProc();
end;

{class methods}
procedure TMyClass.ThreadProc();
begin
  //Place Thread-code here
end;

procedure TMyClass.callThread();
begin
  tHandle := BeginThread([...], @GlobalThreadProc, Self, [...]);
end;
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Nogge

Registriert seit: 15. Jul 2004
336 Beiträge
 
Delphi 7 Professional
 
#15

Re: non-vcl Thread innerhalb einer Klasse deklarieren

  Alt 3. Aug 2007, 11:23
So ist es dann also in Pseudocode:
Delphi-Quellcode:
//zwei Konstanten, deren Wert die MakeProcinstance-Parameter festlegen
const self: pointer = M.Data;
      funktionszeiger: pointer = M.Code;
=> Wahnsinn, vielen Dank für die ausführliche Erklärung, sirius! Ich habe keine Fragen mehr.

@SirThornberry: Diese Lösung hat sirius ja bereits weiter oben vorgeschlagen, allerdings ist dies so etwas umständlich.

@Lucky: Mit den mov-Instruktionen werden Op-Codes in den Speicher vor dem Funktionszeiger geschrieben, die den oben angegebenen Code ausführen (also pop, push usw.) und somit in der Klassenmethode die self-Referenz zur Verfügung stellen. Ohne diese Referenz wäre es ja keine Klassenmethode, sondern eine ganz "normale" Funktion ohne Klassenzugehörigkeit. Aber genau das Gegenteil wollte ich ja implementieren.
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie
(Moderator)

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#16

Re: non-vcl Thread innerhalb einer Klasse deklarieren

  Alt 3. Aug 2007, 11:35
Zitat von sirius:
2. Jetzt wirds schmutzig
Was macht diese Methode MakeProcInstance.
diese Methode schreibt einfach eine neue Funktion. Die Funktion gibts vorher noch nicht im Code und nicht in der Exe. Dazu werden 15 Byte Speicher angefordert (solang soll dei Funktion werden. Und jetzt kommt ASM, was die Methode adhoc implementiert, in dem einfach der OpCode, so wie ihn der Prozessoer will, in die 15 Bytes geschrieben wird.
Verstehe ich das richtig? Wenn ich es so formuliere: "Aufgabe dieser Funktion ist es den Self-Parameter mit auf den Stack zu legen, so dass er nicht als zusätzlicher "unsichtbarer" Parameter an die Methode über geben wird."
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Muetze1
(Gast)

n/a Beiträge
 
#17

Re: non-vcl Thread innerhalb einer Klasse deklarieren

  Alt 3. Aug 2007, 11:37
Zitat von Luckie:
Wenn ich es so formuliere: "Aufgabe dieser Funktion ist es den Self-Parameter mit auf den Stack zu legen, so dass er nicht als zusätzlicher "unsichtbarer" Parameter an die Methode über geben wird."
Ja, wenn du das fette "nicht" streichst ist es richtig...
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie
(Moderator)

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#18

Re: non-vcl Thread innerhalb einer Klasse deklarieren

  Alt 3. Aug 2007, 11:44
Oh, ja natürlich, sonst macht es ja keinen Sinn.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Nogge

Registriert seit: 15. Jul 2004
336 Beiträge
 
Delphi 7 Professional
 
#19

Re: non-vcl Thread innerhalb einer Klasse deklarieren

  Alt 3. Aug 2007, 13:33
Mh, ich habe das mal getestet, allerdings wird der Zeiger auf den/die Parameter nicht korrekt übergeben, sodass jedesmal eine Zugriffsverletzung in TMyDialog.SaveThread erscheint.
Delphi-Quellcode:
procedure TMyDialog.createSpecificThread(methodAddr: Pointer;
  var Parameter: TFileTransferList);
var
  AThreadHandle : Integer;
  //Param : PParam;
begin
  {New(Param);
    Param^.AObject := Parameter;}


  AThreadHandle := beginThread(methodAddr, Parameter);

  if (AThreadHandle > 0) then
  begin
    // warten, bis sich der Thread geschlossen hat
    if (WaitForSingleObject(AThreadHandle, INFINITE) <> WAIT_OBJECT_0) then
    begin
      ShowMsg('ERROR(WaitForSingleObject): Cannot close thread!', '', MB_ICONERROR);
    end;
    CloseHandle(AThreadHandle);
  end;
end;

[...]

function TNonVCLThread.beginThread(methodAddr: Pointer; Parameter: Pointer): Integer;
var
  method : TMethod;
  ThreadID : Cardinal;
begin
  method.Code := methodAddr;
  method.Data := self;
  // converts method to function pointer
  FProcInst := MakeProcInstance(method);
  // creates the thread
  result := System.BeginThread(nil, 0, FProcInst, Parameter, 0, ThreadID);
end;

[...]

// Aufruf
procedure TMyDialog.SaveFiles;
var
  files: TFileTransferList;
begin
  files := TFileTransferList.Create();
  [...] // files.add usw.
  createSpecificThread(@TMyDialog.SaveThread, files);
end;

[...]

function TMyDialog.SaveThread(Ptr: Pointer): DWORD; stdcall;
var
  Param : PParam;
  files : TFileTransferList;
  len : Integer;
begin
  result := 0;

  {Param := PParam(Ptr);
  try
    files := TFileTransferList(Param^.AObject);
  finally
    Dispose(Param);
  end;}


  files := TFileTransferList(Ptr);
  try
    BytesCount := 0;
    len := files.Count; // <- AV bzw. ein ungültiger int-Wert
    for i := 0 to len-1 do
  [...]
end;
  Mit Zitat antworten Zitat
Nogge

Registriert seit: 15. Jul 2004
336 Beiträge
 
Delphi 7 Professional
 
#20

Re: non-vcl Thread innerhalb einer Klasse deklarieren

  Alt 6. Aug 2007, 00:03
So, ich habe das Problem gelöst. Es lag an BeginThread. Diese Funktion verwendet CreateThread intern anders, als es von MSDN beschrieben/empfohlen wird. Ich habe daher...
result := System.BeginThread(nil, 0, FProcInst, Parameter, 0, ThreadID); ...durch...
Delphi-Quellcode:
System.IsMultiThread := true;
  result := Windows.CreateThread(nil, 0, FProcInst, Parameter, 0, ThreadID);
...ersetzt und siehe da, es funktioniert nun alles wunderbar mit der Parameterübergabe.
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +2. Es ist jetzt 16:03 Uhr.
Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf