DllCall() und String als Rückgabe [erledigt]

Fragen rund um diverse Windows-Versionen, ihr Verhalten unter Xbase++ und den Umgang mit der API

Moderator: Moderatoren

Antworten
Benutzeravatar
Werner_Bayern
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2121
Registriert: Sa, 30. Jan 2010 22:58
Wohnort: Niederbayern
Hat sich bedankt: 30 Mal
Danksagung erhalten: 72 Mal

DllCall() und String als Rückgabe [erledigt]

Beitrag von Werner_Bayern »

Servus,

mache gerade die ersten Gehversuche mit einer C-DLL, funktioniert so bisher alles, jedoch liefert ja DllCall() immer einen numerischen Rückgabewert. Was macht man, wenn man aber einen String zurückbekommt?

Geht das mit Bordmittel oder brauche ich dazu die otx4b.dll und ReadStr()?
Zuletzt geändert von Werner_Bayern am Mo, 12. Nov 2012 22:54, insgesamt 1-mal geändert.
es grüßt

Werner

<when the music is over, turn off the lights!>
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: DllCall() und String als Rückgabe

Beitrag von brandelh »

Hallo,

das kommt auf den Rückgabewert der C-DLL an.
dllcall() gibt bei Fremd-DLL immer einen numerischen Wert zurück.
Dies könnte ein Pointer auf einen ASCIIZ String sein ( char* in C ).
Oft wird aber nur der Erfolg ( meist 0 OK, Rest Fehlermeldung, oder 0 Fehler, sonst Handle) bzw. Handles zurückgegeben
und Werte über die Parameter (so kann man Strings zurückbekommen mit pur Xbase++), wenn nicht, hilft (nur) die ot4xb.

Bei der QuickPDF habe ich Funktionen für die Behandlung von String (Pointer) Rückgabewerten von Pablo abgekupfert ;-) :

Code: Alles auswählen

METHOD HBPrintPDF:GetDefaultPrinterName()
return ::ReadString(::_str_result_(FpQCall( {::_hdll_,"QuickPDFGetDefaultPrinterNameA"} ,"__pt__sl",::_id_)))

INLINE METHOD ReadString( cString ) // The DLL needs ANSI Parameters, if not UTF8 !
          DEFAULT cString TO ""
          if ::UseAutoConvUTF8  // string parameter == ANSI/OEM
             if ::nCharSet = 1    // ANSI => OEM
                cString := ConvToOemCP(cString)
             endif              // OK OEM
          else
             // wenn ! ::UseAutoConvUTF8, erhält man UTF8, verwenden mit z.b. ReadUTF8()
             // return value is UTF8, use it !
          endif
          Return cString

   INLINE METHOD _str_result_(p)
       local cb
       if Empty(p) ; RETURN "" ; end
       cb := ::StringResultLength()  // maximale Stirnglänge bei der Bibliothek, sollte in Doku stehen.
       return PeekStr(p,0,cb) // ASCIIZ Strings, was zu lange ist wird hinter dem Stringendezeichen ( chr(0) ) abgeschnitten

Gruß
Hubert
Benutzeravatar
Werner_Bayern
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2121
Registriert: Sa, 30. Jan 2010 22:58
Wohnort: Niederbayern
Hat sich bedankt: 30 Mal
Danksagung erhalten: 72 Mal

Re: DllCall() und String als Rückgabe

Beitrag von Werner_Bayern »

Servus Hubert,

danke, so hab ich es jetzt inzwischen auch gemacht:

Code: Alles auswählen

local nPointer := dllcall("C-lib.dll", DLL_CDECL, "libFunctionsName", nParameter1)
return Peekstr(nPointer, 0, -1)
scheint zu funktionieren.
es grüßt

Werner

<when the music is over, turn off the lights!>
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: DllCall() und String als Rückgabe

Beitrag von brandelh »

Hallo Werner,

ich weiß nicht, was passiert wenn der Rückgabewert NIL oder 0 ist und ob das überhaupt vorkommen kann,
aber wenn Pablo diese Zeile als Schutz eingebaut hat, würde ich das auch tun ;-)

Code: Alles auswählen

if Empty(p) ; RETURN "" ; end
Außerdem musste ICH feststellen, dass eine fehlende DLL die man so aufruft eine sehr seltsame Fehlermeldung bringt, ich würde also DllLoad() nutzen.

Wenn du zusätzlich noch dllcall gegen Pablos nFpCall() tauschst, brauchst du dir um STDCALL and CDECL keine Gedanken manchen.

Code: Alles auswählen

function MyStringFunc(nParameter1)
     local nDll, nPointer, cReturn := ""
     nDll := DllLoad("C-lib.dll")
     if empty(nDll)
        msgbox("DLL konnte nicht geladen werden, fehlt sie ?")
     else
        nPointer := nFpCall( { nDLL, "libFunctionsName" }, nParameter1, ... ) // 
        if ! empty(nParameter1)
           cReturn := Peekstr(nPointer, 0, -1)
        endif
        // DllUnLoad(nDLL) 
     endif
return 
Aus der QuickPDF habe ich eine Klasse gemacht, da ich die DLL nur einmal öffnen muss und interne Variablen halten kann.
DllUnload() führe bei der QuickPDF zu einem Speicherloch (diese gab den Speicher intern nicht frei), aber eigentlich
dürfte es kein Problem sein die DLL einfach offen zu halten, der zweite Aufruf lädt sie nicht neu, eventuell nutzt er aber ein neues Handle.

Pablo hat noch eine interessante Kurzschreibweise und die obige Parameter Erklärung hier:

http://www.xbwin.com/ot4xbXHlp/
=> Tutorial => The ot4xb nFpCall() function
Gruß
Hubert
Benutzeravatar
Werner_Bayern
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2121
Registriert: Sa, 30. Jan 2010 22:58
Wohnort: Niederbayern
Hat sich bedankt: 30 Mal
Danksagung erhalten: 72 Mal

Re: DllCall() und String als Rückgabe

Beitrag von Werner_Bayern »

Danke, auf die Funktion von Pablo war ich auch schon gestoßen, denke aber, dass es so schneller (wenn auch nicht komfortabler) geht.

Das mit dem Rückgabewert werde ich mit einbauen, guter Hinweis.

Ja, auch mein Kenntnisstand ist, dass dllload die DLL nur 1x in den Speicher lädt. Deshalb verzichte ich bewusst auf die ständigen Aufrufe von dllLoad und dllUnload.
es grüßt

Werner

<when the music is over, turn off the lights!>
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: DllCall() und String als Rückgabe

Beitrag von brandelh »

Werner_Bayern hat geschrieben:Danke, auf die Funktion von Pablo war ich auch schon gestoßen, denke aber, dass es so schneller (wenn auch nicht komfortabler) geht.
wenn du SCHREIBEN von Quellcode meinst, hast du sicher recht.
Bei der Ausführung, dürften beide gleich schnell sein, die Sicherheitsabfragen fallen nicht ins Gewicht.

Außerdem, DLLFUNCTION ... wird vom Präprozessor in mehrere Funktionaaufrufe aufgeteilt ;-)
Gruß
Hubert
Benutzeravatar
Werner_Bayern
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2121
Registriert: Sa, 30. Jan 2010 22:58
Wohnort: Niederbayern
Hat sich bedankt: 30 Mal
Danksagung erhalten: 72 Mal

Re: DllCall() und String als Rückgabe

Beitrag von Werner_Bayern »

Nein, ich nutze doch dllCall().
Aber Du hast Recht, ich hab testweise Mal nFpCall anstatt dllCall() verwendet, konnte aber keine erkennbaren Unterschiede feststellen. Bei sowas bleibe ich dann lieber bei den Xbase++-Funktionen. Den Typus kenne ich und die zu übergebenden Variablen konvertiere ich bei Bedarf lieber selbst.

Der Syntax von nFpCall ist übrigens in der Hilfe falsch beschrieben. Die ersten beiden Parameter müssen als Array übergeben werden.
es grüßt

Werner

<when the music is over, turn off the lights!>
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: DllCall() und String als Rückgabe

Beitrag von brandelh »

Werner_Bayern hat geschrieben:Der Syntax von nFpCall ist übrigens in der Hilfe falsch beschrieben.
Die ersten beiden Parameter müssen als Array übergeben werden.
unter Funktionen fehlt die Option, dass man es AUCH als Array übergeben kann, mein Link zeigt auf das Tutorial wo es erwähnt wird.
nFpCall() ist da sehr flexibel, ich selbst nutzte aber die Funktion (siehe Quellcode oben) in der die Typen übergeben werden.

PS: hauptsache es geht :D
Gruß
Hubert
Antworten