DLLs und Strings

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
ProgOldie
Beiträge: 236
Registriert: 19.05.2012 17:09
Computerausstattung: Windows11, Arduinos, Pi3, PureBasic 6.02

DLLs und Strings

Beitrag von ProgOldie »

Hallo,
ich habe bisher aus einer Datenbank heraus in PB selbst erstellte DLLs aufgerufen, was im Grundsatz gut geklappt hat. So konnte ich das Ergebnis einer Abfrage von der DLL in eine csv-Datei schreiben und von dort durch die externe Datenbank auslesen lassen. Nun will ich das ändern und das Ergebnis von der DLL als String zurückreichen lassen.

Was ist falsch an folgender Konstruktion?

Code: Alles auswählen

UseODBCDatabase()
Global Zeile.s



ProcedureDLL.s ODBC_to_str(query.s)
  
  Zeile=""
  ;ODBC  öffnen und Wert auslesen lassen
  ..........
  Zeile=   (wird korrekt berechnet)
   
    ProcedureReturn Zeile
  EndProcedure
Leider liefert aber der Aufruf in der Datenbank Erg:= ODBC_to_str( Anfrage) einen leeren String.
(Die DLL-Aufrufe sind dort korrekt definiert)

Oder muss ich den String in der Datenbank definieren und dann zurückreichen wie etwa ODBC_to_str(Anfrage,Erg)

Dank vorab!
Zuletzt geändert von ProgOldie am 26.09.2012 20:56, insgesamt 1-mal geändert.
Windows10 / PB5.70 / Arduino (-Due) / Raspberry Pi3 /Linux Mint 18
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: DLLs und Strings

Beitrag von ts-soft »

Eine DLL gibt niemals direkt einen String zurück, sondern meist einen Pointer auf den String.
PeekS(ODBC_to_str( Anfrage)) könnte funktionieren.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
ProgOldie
Beiträge: 236
Registriert: 19.05.2012 17:09
Computerausstattung: Windows11, Arduinos, Pi3, PureBasic 6.02

Re: DLLs und Strings

Beitrag von ProgOldie »

Zunächst Danke, wenngleich ich das nicht recht verstehe, weil ich ja die Daten in der aufrufenden Datenbank haben will. Oder ist folgendes gemeint:
In der DLL reiche ich den mit Peek () errechnet Speichbeginn sowie die Länge des Bereichs zurück (Wie macht man das mit zwei Werten?) und muss dann sehen, wie ich in der Datenbank den String wieder zusammenbastele?

Gruß
ProgOldie
Windows10 / PB5.70 / Arduino (-Due) / Raspberry Pi3 /Linux Mint 18
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: DLLs und Strings

Beitrag von ts-soft »

Ruft die Datenbank etwa die DLL auf?
Das aufrufende Programm muss den String von der Adresse, die die DLL zurückgibt, Peeken.
Besser wäre es übrigens, wenn der Funktion ein Buffer, sowie die Bufferlänge übergeben wird,
die DLL den String in den Buffer poked und als Ergebnis die länge des Strings in Byte zurückgibt,
wie es z.B. die WinAPI im allg. macht.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
ProgOldie
Beiträge: 236
Registriert: 19.05.2012 17:09
Computerausstattung: Windows11, Arduinos, Pi3, PureBasic 6.02

Re: DLLs und Strings

Beitrag von ProgOldie »

Hallo,

Dank für die Hilfen. Falls jemand auch 'mal eine Lösung dafür benötigt, dass ein rufendes Fremdprogramm einen String übergibt, dessen Wert in der DLL abgeändert werden muss.

Code: Alles auswählen

ProcedureDLL.i setstring(query.s, PString.l,maxlen.i)
  ;PString ist ein Pointer, der von externem Programm auf eine 
  ;dort def. Stringvariable (per var-Deklaration im Aufruf) verweist, 
  ;für die eine Länge von maxlen Zeichen vorbelegt ist. 
  ;In dieser Prozedur wird 'Inhalt' aus 'query' berechnet und über den Pointer
  ; an das rufende Windowsprogramm zurückgereicht.
  Protected res.i,Membedarf.i,Inhalt.s
  res.i=0
  ; Zur Demo eine primitive Wertzuweisung an 'Inhalt' (ohne Nutzung von 'query')
  Inhalt="Dieser Text wird in der DLL erzeugt"
  
  Membedarf.i=Len(Inhalt)
  If Membedarf<=maxlen
    CopyMemoryString(Inhalt,@PString)
    res=1
  Else
    MessageRequester("Zu wenig Speicher","reserviert:"+Str(maxlen)+"Byte"+Chr(13)+Chr(10)+"benötigt:"+Str(Membedarf)+"Byte")
  EndIf
  ProcedureReturn res
EndProcedure

Damit ist man doch wohl in jedem Fall vor Überschreibproblemen im Speicher geschützt, oder?


Das funktioniert so prima, wenngleich ein Problem bleibt:
Wie übermittele ich dem rufenden Fremdprogramm den erforderlichen Wert von 'maxlen'? Man will ja nicht eine Annäherung an einen sinnvollen Wert durch Probieren erreichen.
Macht es Sinn, Inhalt als für die DLL global zu definieren und dann die Berechnung von Inhalt in eine Prozedur useMem zu verlagern, die zunächst aufgerufen wird. Also etwa so:

Code: Alles auswählen

global Inhalt
ProcedureDLL.i setstring(PString.l,maxlen.i)
 Protected res.i,Membedarf.i
  res.i=0
   Membedarf.i=Len(Inhalt)
  If Membedarf<=maxlen
    CopyMemoryString(Inhalt,@PString)
    res=1
  Else
    MessageRequester("Zu wenig Speicher","reserviert:"+Str(maxlen)+"Byte"+Chr(13)+Chr(10)+"benötigt:"+Str(Membedarf)+"Byte")
  EndIf
  ProcedureReturn res
EndProcedure

ProcedureDLL.i  useMem(query.s)
  ;Demo Werzuweisung an Inhalt, der anhand der query berechnet wird
  Inhalt="Dieser Text wird in der DLL erzeugt"
  ProcedureReturn len(Inhalt)
EndProcedure
Dann aber müsste der Aufruf der DLL so erfolgen:
1) usemem berechnet Inhalt und reicht den erforderlichen Speicherplatz (=maxlen) zurück ans Fremdprogramm
2) Das Fremdprogramm belegt die Stringvariable mit maxlen Zeichen vor.
3) Das Fremdprogramm ruft setstring auf.

Hat jemand eine bessere Idee? Denn hier müsste ja die Aufrufreihenfolge strikt eingehalten werden!
Dank vorab!
Windows10 / PB5.70 / Arduino (-Due) / Raspberry Pi3 /Linux Mint 18
Benutzeravatar
HeX0R
Beiträge: 3042
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Re: DLLs und Strings

Beitrag von HeX0R »

Bevor du Dir jetzt noch einen abbrichst, mach lieber die Peek-Variante:

Code: Alles auswählen

Global Result.s

ProcedureDLL.s Bla(Whatever.s)
  Result = "Gugug"
  ProcedureReturn Result
EndProcedure
und aufrufend:

Code: Alles auswählen

*Pointer = CallFunction(#DLL, "Bla", "Test")
If *Pointer
  Result.s = PeekS(*Pointer)
  Debug Result
EndIf
Mal davon abgesehen, dass Deine PString-Variable vom Typ Integer sein muss, nicht Long.
Benutzeravatar
ProgOldie
Beiträge: 236
Registriert: 19.05.2012 17:09
Computerausstattung: Windows11, Arduinos, Pi3, PureBasic 6.02

Re: DLLs und Strings

Beitrag von ProgOldie »

Hallo HeX0R,

die von dir vorgeschlagene Lösung ist für PB als rufendes Programm o.K.
Ich aber habe eine Datenbank als aufrufendes Programm, die lediglich Strings übergeben kann und nicht über z.B. PeekS() verfügt.

Dank für den Hinweis auf den Integertyp des Pointers.

ProgOldie
Windows10 / PB5.70 / Arduino (-Due) / Raspberry Pi3 /Linux Mint 18
Benutzeravatar
HeX0R
Beiträge: 3042
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Re: DLLs und Strings

Beitrag von HeX0R »

Hmm... eine Datenbank die eine DLL aufruft?
Naja, ich muss ja nicht alles verstehen.

Wie wäre es denn dann, wenn deine SetString()-Procedure die Länge zurückgibt, die dein String benötigt?
Also du fütterst erst SetString mit PString=0.
Dann weiß die Prozedur, o.k., der Aufrufer will nur die Länge wissen und gibt die zurück.
Ist PString <> 0, weist du ihr den String zu.
Antworten