Entwickler-Ecke
Sonstiges (Delphi) - DLL-Kompatible Dynamische Arrays
Martok - Mi 06.01.10 04:36
Titel: DLL-Kompatible Dynamische Arrays
Aloha!
Ein kleines Plugininterface müsste eigentlich so etwas wie dynamische Arrays übertragen. Also einen Datenblock, der eine variable Anzahl von Werten übermittelt.
Das ganze soll natürlich auch in anderen Sprachen ansprechbar sein, also geht ein einfaches dynamisches Array nicht. Ich hab da schon etwas gegrübelt, aber viel weiter als ein Interface zu definieren, und dem Plugin eine Factory mit zu übergeben bin ich da nicht gekommen... das konnte ich bis jetzt schön umgehen, und würde es auch gern dabei belassen.
Momentan sieht die Struktur ungefähr so aus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| TSingleArray = array[0..0] of Single; PSingleArray = ^TSingleArray; TDynArray = record Count: integer; Data: PSingleArray; end; |
Das klappt momentan recht gut, indem das einfach "irgendwo" initialisiert wird, weil alle Verwendungen dann an einer Stelle vorbeikommen, wo ich aufräumen kann. Aber schön ist was anderes, und die Speicherlecks sind in späteren Stufen schon absehbar.
Andere kreative Ideen? Achja, einigermaßen schnell sollte zumindest das Erzeugen auch sein...
Danke schonmal,
Sebastian
Flamefire - Mi 06.01.10 12:15
Hm. Was hällt dich davon ab, in der DLL eine Funktion wie folgt zu definieren?
Delphi-Quelltext
1:
| procedure foo(count:Integer;memory:Pointer) |
Aufruf dürfte klar sein.
Ansonsten wäre eher sinnvoll:
Delphi-Quelltext
1: 2: 3: 4:
| TDynArray = record Count: integer; Data: Array of Single; end; |
Data ist schon ein Pointer auf den Inhalt des Arrays. Problem hier ist nur die Redundanz und Mehraufwand beim Verwalten von Count.
Der Aufbau eines dyn.Arrays in Delphi ist:
Delphi-Quelltext
1: 2: 3: 4: 5:
| TDynArray<T>=record RefCount:Cardinal; Count:Cardinal; Data: Array[0..Count-1] of <T>; end; |
Also wäre die obere Procedure noch am Besten.
in Delphi definieren als:
Delphi-Quelltext
1:
| procedure foo(count:Integer;Memory:TBytes);stdcall;external... |
und in anderen Sprachen dann eben z.b. als:
C#-Quelltext
1:
| function foo(int Count,PByte Memory); |
BenBE - Mi 06.01.10 14:36
Abhängig davon, in welche Richtung die Daten ausgetauscht werden müssen, wäre auch die häufig in der WinAPI anzutreffende Variante mit der Übergabe eines Puffers (und ggf. Offset) auf den Datenbereich überlegenswert.
Alternativ bietet es sich, je nach Anzahl der Strukturen) auch an, einfach den Memory-Manager an die fremde Anwendung\das Plugin herauszureichen (Record TMemoryManager in System.pas IIRC) und so dem Plugin dynamisch zu erlauben, sich den nötigen Speicher zu holen.
Martok - Mi 06.01.10 15:51
BenBE hat folgendes geschrieben : |
Abhängig davon, in welche Richtung die Daten ausgetauscht werden müssen, wäre auch die häufig in der WinAPI anzutreffende Variante mit der Übergabe eines Puffers (und ggf. Offset) auf den Datenbereich überlegenswert. |
In jede Richtung, das ist ja das Problem. Mal muss das Plugin Daten loswerden, mal kriegt es welche geliefert. Ersteres ginge so wie
Flamefire vorschlägt, aber das Problem ist grade die andere Richtung. Und die Tatsache, dass ich mir gerne das doppelt umkopieren sparen würde, sonst könnte ja einfach der Caller das Ding wieder freigeben.
BenBE hat folgendes geschrieben : |
Alternativ bietet es sich, je nach Anzahl der Strukturen) auch an, einfach den Memory-Manager an die fremde Anwendung\das Plugin herauszureichen (Record TMemoryManager in System.pas IIRC) und so dem Plugin dynamisch zu erlauben, sich den nötigen Speicher zu holen. |
Funktioniert das vernünftig? Dann wäre das durchaus denkbar.
Dann kann ich aber gleich ein ordentlich referenzgezähltes IDynArray bauen.
BenBE - Mi 06.01.10 16:17
Die Variante mit dem Übergeben des Speichermanagers funktioniert sehr stabil und wird in vielen Plugin-Systemen von C-Programmen durchaus regelmäßig so praktiziert. Schau dir ggf. mal VirtualDub an; die machen das so und das Teil läuft SEHR stabil.
Gegenüber der Nutzung von Interfaces hat das zudem den Vorteil, dass man den Overhead, den die Verwaltung der Referenzen mit sich bringt vermeidet und das Plugin zudem intern bereits sich den Speicher aus dem Pool der Hauptanwendung holen kann und damit nicht nur Daten über das Interface problemlos verwaltet werden können, sondern auch zusätzliche Puffer, die intern im Plugin verwendet werden. Somit erspart man sich auch bei extrem verschachtelten Strukturen das Umkopieren, weil das Plugin die benötigten Strukturen ohne Umwege direkt im Speicher alloziieren kann.
Martok - Mi 06.01.10 16:53
BenBE hat folgendes geschrieben : |
Die Variante mit dem Übergeben des Speichermanagers funktioniert sehr stabil und wird in vielen Plugin-Systemen von C-Programmen durchaus regelmäßig so praktiziert. Schau dir ggf. mal VirtualDub an; die machen das so und das Teil läuft SEHR stabil. |
Ah stimmt, hab auch grade erstmal genau gelesen was du geschrieben hast ;) TMemoryManager sind ja nur die 3 Funktionspointer, nicht der IMemoryManager der das nochmal verpackt. Hab wohl zuviel mit Interfaces gearbeitet...
BenBE hat folgendes geschrieben : |
Gegenüber der Nutzung von Interfaces hat das zudem den Vorteil, dass man den Overhead, den die Verwaltung der Referenzen mit sich bringt vermeidet |
Jap, das würde sich hier lohnen. RefCounting werd ich zwar eh machen müssen, aber das kann man dann genau da machen wo es gebraucht wird.
Das klingt erstmal gut, ich meld mich dann nochmal ;)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!