Seite 1 von 1

DllCall auf eine unicode-DLL

Verfasst: Di, 29. Okt 2013 14:31
von Jan
Ich habe gerade das problem, das ich mit DllLoad() eine DLL lade, dann aber bei dem folgenden DllCall() scheitere mit der Meldung, das DllPrepareCall() die aufgerufene Funktion nicht finden kann.

Code: Alles auswählen

nDll := DllLoad("DieDll.dll")
IF nDll > 0
   dummy := dllCall(hdll, DLL_CDECL, "DerFunktionsAufruf", "DerErsteParameter", "DerNaechsteParameter")
OK, ich selber benutze ja garkein DllPrepareCall(), aber DllCall() macht das anscheinend intern.

Ich habe das Forum durchstöbert und bin auf den Hinweis gestoßen, das bei Unicode-DLL die Variablen anders behandelt werden müssen. Aber wie soll ich das machen?

Jan

Re: DllCall auf eine unicode-DLL

Verfasst: Di, 29. Okt 2013 14:52
von brandelh
zunächst prüfen ob es darin Funktionen für ANSI gibt ;-) bzw. eine ANSI Version von der dll.

Und dann nimm die ot4xb !

Wenn du dir meine HBPrintPDF ansiehst, wird dir auffallen wie man die genauen Parametertypen gegenüber der DLL angibt.
Es gibt dort auch einen für unicode strings. Mit Umwandlung von ANSI nach UNICODE und zurück, das macht die ot4xb automatisch wenn man den richtigen Typ angibt.
Ich nutze auch eine Funktion, die intern OEM nach ANSI umsetzt wenn das nötig ist, daher kann meine Klasse unabhängig von der set charset Einstellung immer richtig arbeiten ;-)

Re: DllCall auf eine unicode-DLL

Verfasst: Di, 29. Okt 2013 14:58
von Jan
Hallo Hubert,

Danke für den Hinweis. Wenn ich jetzt auch nicht weiß, was ich machen soll. ot4xb ist ja kein Problem, die habe ich ohnehin im Einsatz. Aber wie soll ich die benutzen, welche Funktion dadrin?

Und nein, die DLL gibt es nicht als ANSI.

Jan

Re: DllCall auf eine unicode-DLL

Verfasst: Di, 29. Okt 2013 15:16
von brandelh
Hallo Jan,

lade dir meine Klasse runter und sieh dir die Syntax an !

dann reden wir weiter ;-)

Am besten baust du dir auch so eine Klasse, sie kann ja zunächst auf die nötigen Funktionen beschränkt sein.
Gegenüber von Xbase kann man so eine einheitliche einfache Syntax hinbiegen und nur intern die komplexeren Dinge behandeln.
Z.B. Zeichensatz, Default Texte, Formatumwandlungen, Rückgabe 0/1 => .f./.t. und und und ...
Beispiel für DrawText() hat geschrieben:int DPLAppendText(int InstanceID, wchar_t * Text);

Code: Alles auswählen

// -------------------------------------------------------------------------------------------------------------------
METHOD HBPrintPDF:DrawText(nXPos, nYPos, sText)
   sText := ::ForceAnsi(sText)
return FpQCall( {::_hdll_,"DPLDrawTextA"} ,"__sl__sl__f8__f8__pt",::_id_,nXPos, nYPos, sText)
wie man sieht, übernimmt die Klasse das Handling des DLL-Handle (hier InstanceID), in diesem Beipspiel liefert die Funktion einen numerischen Wert zurück, der aber hier nicht benötigt wird.
In anderen Fällen liefern Funktionen 0/1 zurück und ich setze um auf return 0 # FpQCall etc.

Falls der Anbieter seine DLL ändert (was dummerweise vorkommt) kann man viele Änderungen elegant in der Klasse abfangen, ohne jedesmal den Quellcode der anderen Programme anzupassen.

Re: DllCall auf eine unicode-DLL

Verfasst: Di, 29. Okt 2013 15:41
von brandelh
hier die Parameter Erklärung:

der 1. FormatStringParameter (hier __sl) ist der Typ den die Funktion zurückgeben soll, hier LONG.
Ein ANSI Parameter String wird als __pt angegeben, auch wenn der Text geändert werden kann.
Ein UNICODE String wird mit c_sw übergeben, wobei er auf Xbase++ Seite ein normaler ANSI String ist.

Code: Alles auswählen

#xtranslate AS STR2WIDE                => AS QTYPE "c_sw"
Falls du eine Funktion mit Rückgabewert auf einen String hast, wird es komplexer, da der Speicher welcher die DLL nutzt wieder freigegeben werden muss.
Es gibt auch noch den c@sw, da muss ich in meinen alten eMails nachsehen für was der ist ;-)

Code: Alles auswählen

#xtranslate AS STR2WIDE_W              => AS QTYPE "c@sw"

Re: DllCall auf eine unicode-DLL

Verfasst: Di, 29. Okt 2013 16:14
von brandelh
Das ist so eine Funktion, die einen Unicode String (besser den Pointer darauf) zurückliefert:
wchar_t * DPLDrawHTMLTextBox(int InstanceID, double Left, double Top,
double Width, double Height, wchar_t * HTMLText);
und DOUBLE Variablen werden auch benötigt: __f8

Code: Alles auswählen

// -------------------------------------------------------------------------------------------------------------------
METHOD HBPrintPDF:DrawHTMLTextBox(nLeft, nTop, nWidth, nHeight, sHTMLText)
   sHTMLText := ::ForceAnsi(sHTMLText)
return ::ReadString(::_str_result_(FpQCall( {::_hdll_,"DPLDrawHTMLTextBoxA"} ,"__pt__sl__f8__f8__f8__f8__pt",::_id_,nLeft, nTop, nWidth, nHeight, sHTMLText)))
In dieser Klasse richte ich mich bei der Parameterübergabe and die ActiveX Schnittstelle (also ohne 1. Parameter) und ::setze OEM auf ANSI um.
_str_result_() ist eine Funktion im Quellcode von Pablo, die den Text abholt und den Speicher freigibt.

Re: DllCall auf eine unicode-DLL

Verfasst: Di, 29. Okt 2013 16:52
von brandelh
Hier ist die richtige Anleitung ...

Code: Alles auswählen

Autoconvert Ansi to Unicode: 	c_sw  statt  __pt  >> nur wenn Parameter LPSTR oder LPCSTR nach LPWSTR oder LPCWSTR wurden.
Parameter per Reference mit :   c@sw

Rückgabewerte c_sw statt c_sz liefern einen Xbase++ Ansi String statt dem Pointer.
Der letzte Pointer kann mit qfpGetLastPointer() ermittelt werden um Speicher frei zu geben ...
Also ist ein Rückgabewert eines Strings c_sz statt __pt ... wenn man keinen Pointer möchte, aber ob dann der Speicher freigegeben wird ?

Re: DllCall auf eine unicode-DLL

Verfasst: Di, 29. Okt 2013 16:53
von brandelh
PS: du darfst natürlich meine Klasse als Vorlage nutzen inkl. Pablos Sonderfunktionen()