Autor Beitrag
moddin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 75

WinXP Pro
Delphi 7 Enterprise ;-)
BeitragVerfasst: Mo 16.03.09 15:08 
Schönen guten Tag!

Ich kämpfe im Moment mit einem Problem, und zwar
versuche ich die Ausgabe der CallCmd-Function ( die vom Plugin ausgeführt wird und wiederholt WriteLine aufruft)
umzuleiten

CallAndCapture -> HookWriteLine -> CallCommand -> [ Wiederholt WriteLine abfangen ] -> Unhook -> Exit

Dabei tritt aber immer eine Exception auf, und zwar in der Hook-Funtion

Am Hook selbst liegt es nicht, die funktion springt immer wichtig zurück

Das ganze diehnt dazu, die Ausgabe meiner Console abzufangen und über das Netzwerk an einen Clienten zu senden

Ideen?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
function CallAndCapture(const Cmd:String;Args : TArguments):String;
var
 OldFunc : Pointer;
 OutText : TStringList;
// Callback
function HookedWriteLine(Const S:String):boolean;
begin
 OutText.Add(S); // <--- Exception
end;
// Main
begin
 try
  OutText := TStringList.Create;
  Outtext.Add('CAPTURED OUTPUT');
  HookCode(@WriteLine,@HookedWriteLine,OldFunc);
  if CallCmd(Cmd,Args) then
   Result := OutText.Text
  else
   Result := '';
 finally
  UnhookCode(OldFunc);
  OutText.Free;
 end;
end;



Moderiert von user profile iconNarses: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Mo 16.03.2009 um 14:26

_________________
Willst du Körper an Körper pressen? Atem spüren? Gerüche wahrnehmen? Verschiedene Stellungen probieren? Rein und raus? Von hinten nach vorne? Ja? Dann nimm den Bus!


Zuletzt bearbeitet von moddin am Mo 16.03.09 16:42, insgesamt 1-mal bearbeitet
moddin Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 75

WinXP Pro
Delphi 7 Enterprise ;-)
BeitragVerfasst: Mo 16.03.09 16:10 
UPDATE

weiß jetzt was falsch ist
jetzt funktioniert das Schreiben auf OutText

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
function HookedWriteLine(Const S:String):boolean;
var
 CorrectAddress : Pointer;
begin
 CorrectAddress := Pointer(DWord(@OutText) + ????????;
 TStringList(CorrectAddress).Add(S);
end;


die adressen werden hier relativ zueinande compiliert, wie kann ich jetzt ??????????, sprich den Offset errechen?

_________________
Willst du Körper an Körper pressen? Atem spüren? Gerüche wahrnehmen? Verschiedene Stellungen probieren? Rein und raus? Von hinten nach vorne? Ja? Dann nimm den Bus!
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 18.03.09 18:16 
Es ist eine GANZ schlechte Idee, aus einem Hook, der als Lokale Prozedur implementiert ist, heraus auf lokale Variablen der äußeren Funktion zuzugreifen. Hier wirst Du wohl Modullokal kurz deine gewünschte Dateninstanz irgendwo halten müssen.

Bessser jedoch wäre es, das Plugin so anzupassen, dass es nicht WriteLine, sondern eine Interface-Funktion deiner Anwendung für Text-Ausgaben verwendet.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mi 18.03.09 18:31 
Es hat wohl mehrere Fehler. Erstens darfst du den Pointer einer lokalen Funktion nicht nach "aussen" geben bzw. ausserhalb des Kontexts aufrufen. Das lässt Delphi auch nicht zu, ausser du verwendest direkt Pointer, dann kann er praktisch nicht wissen, was du tust. Lokale Variablen liegen auf dem Stack und wenn du die lokale Funktion von irgendwo anders ausführst hat's andere Sachen im Stack drin. Zweitens bist du sicher, dass die Aufrufkonvention stimmt?
moddin Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 75

WinXP Pro
Delphi 7 Enterprise ;-)
BeitragVerfasst: Fr 20.03.09 02:04 
Hi!

Das ganze soll für plugins transparent sein, dh

Client -> Sendet auszuführendes Komm ando übers Netz -> Server empfängt,compiliert und führt die Funktion aus
-> abgefangene Daten zurücksenden -> Client -> Ausgabe

WriteLine ist ja bereits die Schnittstelle für Plugins, worüber die Console (TRichEdit) beschrieben wird (hat nix mit WriteLN zu tun!!) oder wie ist das mit interface gemeint? IInterface ?

Habe das ganz jetzt über eine Globale-Stringliste gelöst, welche anstatt der OutText beschrieben wird

gäbe es da noch ne elegantere Lösung?

Man könnte natürlich auch immer das Ziel als formales parameter WriteLine mitgeben,aber dann müsste ich die ganze architektur umschrieben

_________________
Willst du Körper an Körper pressen? Atem spüren? Gerüche wahrnehmen? Verschiedene Stellungen probieren? Rein und raus? Von hinten nach vorne? Ja? Dann nimm den Bus!
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Fr 20.03.09 08:02 
Im Grunde, wenn Du die Funktion WriteLine schon selbst geschrieben hast, so kannst Du dort einfach die übergebenen Parameter auswerten. Wenn Du nun noch im globalen Status deiner Anwendung hinterlegst ob eine Umleitung erfolgen soll und wenn ja, wohin, dann brauchst Du keinen Hook.

Ansonsten macht man das i.d.R. so, dass man dem Plugin eine Tabelle von "öffentlichen Funktionen" übergibt und dann das Plugin diese einfach nur aufruft. Möchte man dann eine Funktion debuggen oder austauschen, setzt man einfach in der Tabelle, die man dem Plugin übergibt einen andren Funktionspointer.

Mit Interface kann sowohl die Menge aller Interface-Typen gemeint sein, als auch allgemein eine offene Schnittstelle zwischen Modulen. Ich meinte oben letzteres (auch wenn auch ersteres funktioniert, sich aber in Delphi blöd programmieren lässt).

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Fr 20.03.09 09:52 
Wenn im Aufruf die Liste nicht übergeben wird, aber die zu verwendende Liste nicht gobal sondern vom Kontext abhängig ist, dann muss der Aufruf implizit den Kontext enthalten.

Wenn für dich in Frage kommt, Funktionsreferenzen "of object" - sprich TMethod zu verwenden, dann ist gut. Wenn du "kontextlose" Funktionsreferenzen zulassen kannst/willst, musst du dir etwas analog zu MakeObjectInstance basteln. MakeObjectInstance erstellt eine kleine Redirect-Funktion zur Laufzeit und baut den Kontext (hier: eine Referenz auf das Objekt) in die Redirect-Funktion fest ein, und gibt einen Pointer darauf zurück.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Fr 20.03.09 12:32 
user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
Wenn im Aufruf die Liste nicht übergeben wird, aber die zu verwendende Liste nicht gobal sondern vom Kontext abhängig ist, dann muss der Aufruf implizit den Kontext enthalten.

Dafür gibt's den Sender-Parameter in Events, die von der VCL und vielen anderen Bibliotheken generiert werden.

user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
Wenn für dich in Frage kommt, Funktionsreferenzen "of object" - sprich TMethod zu verwenden, dann ist gut. Wenn du "kontextlose" Funktionsreferenzen zulassen kannst/willst, musst du dir etwas analog zu MakeObjectInstance basteln. MakeObjectInstance erstellt eine kleine Redirect-Funktion zur Laufzeit und baut den Kontext (hier: eine Referenz auf das Objekt) in die Redirect-Funktion fest ein, und gibt einen Pointer darauf zurück.

MakeObjectInstance ist eine Krücke. für mehr taugt es nicht. Von den Memory-Leaks die man sich damit einhandelt mal abgesehen ...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Fr 20.03.09 13:28 
@BenBE: Der Sender hat einen anderen Zweck. Dort geht es darum, dass der Eventhandler weiss, woher die Anfrage kam. Hier haben wir ein ganz anderes Problem. Es geht darum, dass die Funktion WriteLine selbst weiss, wohin er seine Sachen schreiben muss. Dem Aufrufer von WriteLine ist prinzipiell egal wohin WriteLine etwas schreibt. Der will nur etwas schreiben und dem WriteLine nicht auch noch mitteilen wohin. Ausserdem sind normale Funktionen semantisch gesehen praktisch das "Gegenteil" von Events (= Callbacks)...

MakeObjectInstance ist tatsächlich keine gute Lösung aber die einzige Lösung, wenn der Fall vorliegt, den ich beschrieben habe. Memory-Leaks hat man bei einer korrekten Implementation nicht.

Ich kann mich nur wiederholen. Entweder er macht's mit Methoden-Referenzen (, dort ist der Kontext mit dabei siehe TMethod = Ein Pointer auf den Kontext/Daten/Self und ein Pointer auf die eigentliche Funktion. Self wird dann als unsichtbarer erster Parameter automatisch mitgegeben und WriteLine kann mit Self auf das Objekt zugreifen, wo die StringListe dann liegt) oder er macht's mit einem "nackten" Pointer auf die Funktion. Da kommt man aber nicht um eine MakeObjectInstance ähnliche Implementation herum.

Oder man macht es nochmals ganz anders. Er übergibt nicht eine Menge von Funktionen sondern ein Objekt oder Interface und darin sind eine Menge von Funktionen enthalten.

Wie funktioniert HookCode? Bzw. wie funktioniert dein Plugin Konzept generell? Was wir wann übergeben.
moddin Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 75

WinXP Pro
Delphi 7 Enterprise ;-)
BeitragVerfasst: Sa 21.03.09 13:32 
Zitat:
Wie funktioniert HookCode? Bzw. wie funktioniert dein Plugin Konzept generell? Was wir wann übergeben.


@uallHook

1. Loader -> Alle plugins finden -> Exportierte "Initialize" des Plugins aufrufen -> Author, Name etc
2. Record (mit allen für das plugin zugänglichen funktionen) wird übergeben (WriteLine,RegisterCmd,...)
3. Plugin registriert über RegisterCmd alle unterstützen commandos und Netzerk-Callbacks
4. Nächstes Plugin ->*

Ich finde auch die Idee mit einem internen Schalter am besten, zumal das ganze ja noch multithreading-mutitab-fähig werden soll, dann muss zwangsweise ja ein Ziel (Stringlist,Memo) angegeben werden, damit das plugin auch aufs richtige tab schreibt

_________________
Willst du Körper an Körper pressen? Atem spüren? Gerüche wahrnehmen? Verschiedene Stellungen probieren? Rein und raus? Von hinten nach vorne? Ja? Dann nimm den Bus!
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Sa 21.03.09 18:07 
Irgendwie verstehe ich nicht, weshalb du HookCode verwendest, wenn du dem Plugin selbst die Funktion als Record übergibst. Du kannst ja gleich eine alternative Funktion übergeben, mit der Netzwerkfunktionalität bzw. einfach dein WriteLine erweitern.
Oder habe ich etwas falsch verstanden?

Das einfachste wäre wohl du übergibst statt ein Record in Interface.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
type
  IPlugin = interface
  ['{1C3AD56F-FC8D-4FFF-950A-A429BBB6DE03}']
    procedure WriteLine(const Value: string);
    procedure DoSomething;
  end;

  TPlugin = class(TInterfacedObject, IPlugin)
  private
    FStrings: TStrings;
  public
    constructor Create(AStrings: TStrings);
    procedure WriteLine(const Value: string);
    procedure DoSomething;
  end;

{ TPlugin }

constructor TPlugin.Create(AStrings: TStrings);
begin
  FStrings := AStrings;
end;

procedure TPlugin.DoSomething;
begin
  ShowMessage('Do something');
end;

procedure TPlugin.WriteLine(const Value: string);
begin
  FStrings.Add(Value);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  MyPlugin: IPlugin;
begin
  MyPlugin := TPlugin.Create(Memo1.Lines);
  // --> hier MyPlugin übergeben. Für jedes Plugin ein neues.
end;

// Achtung bei der Übergabe von Strings über Modulgrenzen
moddin Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 75

WinXP Pro
Delphi 7 Enterprise ;-)
BeitragVerfasst: Mo 23.03.09 13:03 
und wie würdest du dann das plugin aufrufen?

ausblenden Delphi-Quelltext
1:
2:
3:
MyPlugin.WriteLine := HookedWriteLine;
PluginAufrufen()
MyPlugIn.WriteLine := OldWriteLine;


oder einfach

ausblenden Delphi-Quelltext
1:
2:
3:
4:
Capture := TStrL.Create()
MyPlugin.Target := Capture;
PlugInAufRufen()
MyPlugin.Target := Old;


da plugin braucht dann nur die IInterface klasse, das object ist dann in der "Main" implmentiert, richtig?

_________________
Willst du Körper an Körper pressen? Atem spüren? Gerüche wahrnehmen? Verschiedene Stellungen probieren? Rein und raus? Von hinten nach vorne? Ja? Dann nimm den Bus!


Zuletzt bearbeitet von moddin am Mo 23.03.09 13:11, insgesamt 1-mal bearbeitet
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mo 23.03.09 13:07 
So wie dein zweiter Vorschlag wäre:
user profile iconmoddin hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
Capture := TStrL.Create()
MyPlugin.Target := Capture;
PlugInAufRufen()
MyPlugin.Target := Old;


Wobei das in dem Sinne nicht mehr notwendig ist, da eh jedes Plugin sein eigenes TStrings hat und damit von andren Plugins unabhängig ist.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
moddin Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 75

WinXP Pro
Delphi 7 Enterprise ;-)
BeitragVerfasst: Mo 23.03.09 13:30 
Danke! Cooler ansatz

Wie könnte man das ganze jetrzt threadfähig machen, wenn 2 threads auf das selbe plugin/function zugreifen?

_________________
Willst du Körper an Körper pressen? Atem spüren? Gerüche wahrnehmen? Verschiedene Stellungen probieren? Rein und raus? Von hinten nach vorne? Ja? Dann nimm den Bus!
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Mo 23.03.09 14:19 
Kommt etwas darauf an, um was für Funktionen es geht. Du kannst entweder eine Lock/Unlock Funktion zur Verfügung stellen oder im Hostprogramm alles synchronisieren bzw. dort alles locken.

Wenn du mehrere Locks hast musst du jedoch ziemlich gut aufpassen, dass du keine Deadlocks bekommst. Entweder machst du Locks hierarchisch (Lock 1 alleine erlaubt, Lock 2 aber nur mit Lock 1 zusammen), oder du sorgst dafür, dass man Locks nicht ineinander schachteln kann. Wenn du in ThreadA Lock1 innerhalb Lock2 anforderst, und im ThreadB Lock2 innerhalb Lock1, dann hast du potentiell ein Deadlock, je nach Timing... Sowas sollte man wenn möglich "by design" aussschliessen, weil die verschiedenen Plugins sollen idealerweise davon ausgehen können, dass sie alleine sind...

Wenn Performance kein Problem ist kannst du alle calls einfach synchronisieren. Ansonsten müsstest du prüfen, ob die Calls asynchron abgearbeitet werden können. Usw...

Ein Wundermittel gegen alle Probleme gibt's da nicht.