Seite 1 von 2

String von D richtig an PB DLL schicken [gelöst]

Verfasst: 03.02.2009 12:05
von gekkonier
Hallihallo!

Ich habe folgendes Anliegen:

Ich würde gerne eine DLL für die Programmiersprache D basteln, und zwar in Purebasic. Die soll ned viel machen, eigentlich nur ein vorhandes JPEG resizen und dann abspeichern.
Den Pfad vom JPEG will ich mit einem String übergeben, woraus dann in PB so etwas in der Art wird (reduziertes Beispiel - ich mach da schon andere Dinge, aber so ähnlich sieht die ProcedureDLL halt aus):

Code: Alles auswählen

ProcedureDLL dll2(var.s)
   MessageRequester("hallo", var, 0)
EndProcedure
Damit ich einen wohlgeformten PB String übergeben kann brauch ich jetzt nur noch eine Information: Sind die Purebasic Strings so terminiert wie in C, oder gelten hier andere Konventionen?

Falls die Frage ein Quatsch ist steinigt mich bitte nicht, ich bin nur neugierig wie das alles Funktioniert und lerne durch ausprobieren ;)

Verfasst: 03.02.2009 12:50
von R4z0r1989
hey gekkonier,

wenn ich mich nicht täusch muss man bei einer dll von purebasic das ganze im memory machen.

da ich aber nu keine zeit hab kann ich dir wenn nicht andre schneller sind später ein beispiel posten ;-)

Verfasst: 03.02.2009 13:34
von gekkonier
Ich habe jetzt im Forum gefunden, dass purebasic einen Pointer auf einen nullterminierten String verlangt.

Ich würde das jetzt so in der DLL dann machen:

Code: Alles auswählen

ProcedureDLL dll2(*ptr)
   MessageRequester("pb MessageRequester", PeekS(*ptr))
EndProcedure
Wäre das eine richtige Vorgehensweise, oder ist das falsch?

Verfasst: 03.02.2009 13:37
von R4z0r1989
ja genau so denk ich dass es funktionier ;-)

wenn nicht kann ich dir leider auch nicht mehr helfen ^^

Verfasst: 03.02.2009 13:38
von cxAlex
gekkonier hat geschrieben:Ich habe jetzt im Forum gefunden, dass purebasic einen Pointer auf einen nullterminierten String verlangt.

Ich würde das jetzt so in der DLL dann machen:

Code: Alles auswählen

ProcedureDLL dll2(*ptr)
   MessageRequester("pb MessageRequester", PeekS(*ptr))
EndProcedure
Wäre das eine richtige Vorgehensweise, oder ist das falsch?
Das hier reicht vollkommen aus:

Code: Alles auswählen

ProcedureDLL dll2(Str.s)
  MessageRequester("pb MessageRequester", Str)
EndProcedure

CallFunctionFast(@dll2(), @"TestString")
Ich übergebe in PX auch Pointer auf Strings an PB Dlls, und PB kann das ganz einfach nativ.

Verfasst: 03.02.2009 13:55
von DarkDragon
PB terminiert die Strings mit Zero. Desshalb verwendest du in D einfach toStringz(deinstring) (Z steht üblicherweise für Zero) zum konvertieren :wink: .

Code: Alles auswählen

ProcedureDLL dll2(Str.s)
  MessageRequester("pb MessageRequester", Str)
EndProcedure 
Muss also so aufgerufen werden:

Code: Alles auswählen

dll2(toStringz("Hallo, Welt!"));
Nun kommt es noch drauf an ob du Tango oder Phobos nutzt und welche Version. Bei einer alten Tango version hieß toStringz anders.

Verfasst: 03.02.2009 14:09
von gekkonier
Ah, danke für die Erläuterungen!

Ich habs jetzt so geplant:

PB Dll:

Code: Alles auswählen

ProcedureDLL dll2(*ptr)
   MessageRequester("pb MessageRequester", PeekS(*ptr))
EndProcedure
D Programm, welches die DLL verwendet:

Code: Alles auswählen

import tango.stdc.stringz;
extern (C) void dll2(char* str);

void main() {
	dll2(toStringz("Hallo von D"));
}
Funktioniert prächtig.
Ein Problem hab ich nur noch:

Wenn ich das D Programm dann aufrufe erscheint wie gewüncht der Requester mit dem übergebenen "Hallo von D".
Aber nach Beendigung des Programmes kommt noch ein object.Exception: Access Violation, welches sicher von der D Seite daherkommt.
Das lustige daran ist aber, wenn ich dll2(toStringz("Hallo von D")); 2x aufrufe kommt diese Fehlermeldung nicht mehr.

Vermutlich mache ich da was auf der D Seite falsch - mit Pointern und so Kram bin ich sehr unbeholfen, und zumal ich so oder so relativ selten grössere Programme schreibe und deshalb alles schön simpel halten kann.

Falls man mit D eine PB Dll verwenden will muss man noch folgendes machen:

1. Compilieren der DLL in pb
2. die lib file die pb generiert NICHT verwenden
3. eine eigene lib file für d machen:
implib /s pbdll.lib pbdll.dll
4. D Programm wie oben
5. compilieren mit dmd main.d pbdll.lib

Wobei mit den Pointern auf Speicher usw, das hab ich in C schon nicht kapiert und verwende ich normalerweise auch nicht, deshalb könnte das falsch sein *g*

EDIT: Ich habe den Threadtitel jetzt angepasst, damit man besser weiss worum es eigentlich geht.

Verfasst: 03.02.2009 14:20
von milan1612
Unicode-Ascii Kollision?

Verfasst: 03.02.2009 14:21
von DarkDragon

Code: Alles auswählen

import tango.sys.SharedLib;
import tango.stdc.stringz;

typedef extern (C) void function(char* arg) tdll2;
tdll2 dll2;

void main() {
    auto library = SharedLib.load("Test.dll");
    if(library !is null) {
        dll2 = cast(tdll2) library.getSymbol("dll2");
        dll2(toStringz("Hallo von D"));

        library.unload();
    }
}
Ganz nach diesem Tutorial hier:
http://www.dsource.org/projects/tango/wiki/TutDLL

Funktioniert doch wunderbar ;-) .

Verfasst: 03.02.2009 14:25
von gekkonier
Wohooooo, das funktioniert!
Danke danke danke!
:praise: