Blitzeigene CallbackProc-Funktion addressieren?

Übersicht BlitzBasic Allgemein

Neue Antwort erstellen

KnorxThieus

Betreff: Blitzeigene CallbackProc-Funktion addressieren?

BeitragMo, Jul 06, 2015 18:57
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

Wie bereits in einem weiteren Thread ersichtlich, setze ich mich gerade mit API-Funktionen auseinander und widme mich neben der TaskDialog-Funktion jetzt auch der TaskDialogIndirect-Funktion. (Userlib-Code: [AUSKLAPPEN]
.lib "Comctl32.dll"
api_TaskDialogIndirect%(pTaskConfig*, pnButton*, pnRadioButton*, pfVerificationFlagChecked*) : "TaskDialogIndirect"
Achtung: Lässt sich nur als kompilierte Exe mit durch den Resource Hacker beigelegter Manifest-Resource ausführen: Code: [AUSKLAPPEN]
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
    version="1.0.0.0"
    processorArchitecture="X86"
    name="MyCompany.MyLabel.MyAppName"
    type="win32"
/>
<description>MultiMedia BoardCast/Scheduler.</description>
<dependency>
    <dependentAssembly>
        <assemblyIdentity
            type="win32"
            name="Microsoft.Windows.Common-Controls"
            version="6.0.0.0"
            processorArchitecture="X86"
            publicKeyToken="6595b64144ccf1df"
            language="*"
        />
    </dependentAssembly>
</dependency>
</assembly>
)
Mit geringen C++-Kenntnissen habe ich mich da erstmalig versucht einzulesen, Structs, Pointer, … ich bin aber letztendlich auf den theoretischen Rohcode wie folgt gekommen: BlitzBasic: [AUSKLAPPEN]
;Fenster: für B+ler hier auskommentiert, der Rest kann es 1:1 mit einem Grafikfenster nachvollziehen
;window = CreateWindow("TaskDialogIndirect Test", 200, 200, 400, 400)
;hwnd = QueryObject(window, 1)

Graphics 800, 600, 32, 2
hwnd = api_GetActiveWindow()




bank = CreateBank() ;Das wird dieser große TASKDIALOGCONFIG struct!

PokeInt bank, 4, hwnd
PokeInt bank, 8, 0
PokeByte bank, 12, $1 + $2 + $4 + $10 + $20 + $40 + $200 + $400 + $1000
PokeByte bank, 13, $2 + $4 + $8
PokeString bank, 14, "TaskDialogIndirect"
PokeString bank, 18, "Tun Sie irgendetwas"
PokeString bank, 22, "Keine Ahnung, was weiß ich?"
PokeInt bank, 26, 2

buba1 = CreateBank()
PokeInt buba1, 0, $101
PokeString buba1, 4, "Apokalypse"

PokeInt bank, 30, buba1

buba1 = CreateBank()
PokeInt buba1, 0, $102
PokeString buba1, 4, "Hilfe"

PokeInt bank, 30, buba2
PokeInt bank, 34, 0
PokeInt bank, 38, 0
PokeInt bank, 42, 0
PokeString bank, 46, "Nicht mehr anzeigen"
PokeString bank, 50, "Bei Hilfe wenden Sie sich <a href=" + Chr$(34) + "http://gidf.de" + Chr$(34) + "hieran</a>." + Chr$(13) + "Wink"
PokeString bank, 54, "Zeig mal mehr!"
PokeString bank, 58, "Zeig mal weniger!"
PokeInt bank, 62, 0
PokeInt bank, 66, 0
PokeString bank, 70, "Für weitere Informationen beehren Sie bitte <a href=" + Chr$(34) + "http://www.KnorxThieus.esy.es" + Chr$(34) + ">unsere Webseite ..." + Chr$(13) + Chr$(10) + "... oder versuchen Sie es <a href" + Chr$(34) + "calc" + Chr$(34) + "hiermit</a>."
PokeInt bank, 74, 0 ;<--- HIER! pfCallback
PokeInt bank, 78, 0 ;<--- HIER! lpCallbackData
PokeInt bank, 82, 0
PokeInt bank, 0, BankSize(bank) + 4


outbut = CreateBank(4)
outrad = CreateBank(4)
outcb = CreateBank(1)


CreateLabel "Return: " + api_TaskDialogIndirect(bank, outbut, outrad, outcb), 0, 0, 400, 15, window


Repeat : Until WaitEvent() = $803



Function PeekString$(bank, offset)
Local txt$

txtbank = PeekInt(bank, offset)
For a = 1 To BankSize(txtbank)
txt$ = txt$ + Chr$(PeekByte(txtbank, a - 1))
Next

Return txt$
End Function
Theoretisch soweit. Aber praktisch musste ich feststellen, dass man da die auf programmeigene Callbackfunktion verweisen muss! (Dicke Markierung bei etwa Zeile 40) Sad
Ich weiß gerade noch so, dass diese Prozedurfunktion, die alle Messages und Notifications von Windows abarbeitet, per Zeiger übergeben wird, um dann von Win aufgerufen zu werden … aber weder von den CallbackData habe ich eine Ahnung, noch irgendeine Idee, wie ich diese bei BB doch intern verwalteten Funktionszeiger auslesen soll! Eine Funktion wie GetWindowCallback habe ich nicht gefunden.
Habt ihr noch irgendwelche Ideen? Embarassed Es wäre so doof, jetzt aufzuhören! Sad

Mit freundlichen Grüßen,
KnorxThieus

@Moderation: Ich denke schon, dass ich hier unter Allgemein richtig bin, schließlich läuft ja auch B3D in Fenster und müsste daher ein WindowProc haben, richtig?

Silver_Knee

BeitragMo, Jul 06, 2015 20:02
Antworten mit Zitat
Benutzer-Profile anzeigen
Callback-Funktion heißt, du schreibst selbst eine Funktion, gibst die der api_TaskDialogIndirect mit und die api_TaskDialogIndirect ruft in Ihrem aufruf, deine Funktion auf.

Das geht mit B3D Boardmitteln nicht. Es gibt aber verschiedene "Hacks", die verschieden gut sowas realisieren können. Das Stichwort heißt hierzu "function pointer". Da gibt's lösungen hier und im englischen Forum.

Ohne solche Hacks, musst du eine DLL schreiben, die api_TaskDialogIndirect aufruft in einer Sprache die Funktionspointer unterstützt. In der selbstgeschriebene DLL kannst du dann in den Callback-Funktionen variablen setzen, die du dan mit B3D wieder abrufen kannst.

KnorxThieus

BeitragMo, Jul 06, 2015 20:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

Danke für deine Antwort.

Ich dachte, da könnte ich die Blitz-Standard-Callback-Funktion nehmen, die es eh schon gibt! Oder muss die hier tatsächlich etwas Spezifisches tun, was sie nicht automatisch täte?

Wenn ich einen Hack verwende, muss ich die Funktion dann selber schreiben? Und wenn ja, was gehört da rein?
Nach "function pointer" habe ich in beiden Foren gesucht, das einzige Brauchbare schien mir die FastPointer-Bibliothek hier. Tut es die? Confused

Na ja, für meine Kenntnisse kommt selber eine DLL Schreiben nicht infrage Sad

Mit freundlichen Grüßen,
KnorxThieus
Version: BlitzPlus / Blitz+

Silver_Knee

BeitragMo, Jul 06, 2015 21:59
Antworten mit Zitat
Benutzer-Profile anzeigen
So. Ich hab jetzt deinen ersten Thread gelesen und die API von MS überflogen.

Was du machen willst ist zunächst in Blitz3D einfach nicht vorgesehen. api_TaskDialog arbeitet synchron. Es hält dein Programm an und du kannst den Rückgabewert auswerten. Ein Thread. Ein Programmablauf. Ganz einfach. Das wäre ein typischer Blitz3D-Ansatz.
api_TaskDialogIndirect will das asynchron lösen. Du rufst die Funktion auf und die ruft dann irgendwann eine Funktion in deinem Code auf. Wie die Funktion aussehen muss, kannst du auch nachlesen:
https://msdn.microsoft.com/en-...85%29.aspx
Da siehst du übrigens den Parameter dwRefData und unten steht dann, dass der das lpCallbackData ist. Du kannst also bei deinem Aufruf von api_TaskDialogIndirect etwas übergeben, was deine Callback-Funktion bekommt, damit sie weiß von wo der Aufruf ursprünglich kam (kann z.B. ein Pointer auf einen Type sein)
"Ist ja alles schön und gut aber wie komm ich an den Funktionspointer?" - Die FastPointer-Dll ist ganz okay, ob du aber die Übergabeparameter rein bekommst, wenn du deine Funktion gemäß der API schreibst, kann ich dir nicht sagen. Das müsstest du ausprobieren, ansonsten müsstest du nen anderen Hack ausprobieren. Außerdem weiß ich nicht "wann" die Callback-Funktion aufgerufen wird:
Zitat:
[TaskDialogCallbackProc] receives messages from the task dialog when various events occur.
könnte heißen während Flip (Bei B3D) oder WaitEvent (Bei BlitzPlus) oder in einem ganz eigenen Thread. Das würde es gelten herauszufinden.

KnorxThieus

BeitragMo, Jul 06, 2015 22:08
Antworten mit Zitat
Benutzer-Profile anzeigen
Uff, scheint das aufwendig … kann man das als C- oder Java-Programmierer mit wenig Aufwand in eine kompakte DLL fassen? Dann könnte ich mal herumbitten Wink

Silver_Knee hat Folgendes geschrieben:
Das würde es gelten herauszufinden.
Und wie, wo ich ja die Funktion mangels Zeiger gar nicht erst ausführen kann? Sad
Version: BlitzPlus / Blitz+

Silver_Knee

BeitragMo, Jul 06, 2015 22:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Eine passende DLL in C zu schreiben, geht normalerweise. Nennt sich Wrapper. Bin leider selbst kein C-Programmierer, kenne nur das grobe Konzept.

In Java hast du mit DLLs meist nix am Hut, weil es für fast alles eine fertige, plattformunabhängige, eingebaute Lösung gibt (etwa wie BlitzMax' MaxGUI oder Monkey es versuchen). Wenn du doch an DLLs musst, kommst du, glaube ich, bei callback-Funktionen auch nicht weiter. Da hast du normalerweise auch Wrapper für Java. In Java kannst du keine Wrapper schreiben, weil du keine DLLs compilen kannst - rein von der Art, wie Java funktioniert schon nicht.

Du kannst eine Funktion schreiben, die der Definition in dem Link entspricht, dir mit FastPointer den Funktionspointer holen und ihn an die entsprechende Stelle in der config schreiben. Wenn du Glück hast, kommen die Parameter an, wenn du Pech hast, schmiert dein Programm ab. Dann kannst du noch andere Hacks versuchen.

Zitat:
Das würde es gelten herauszufinden.


...war an dich gerichtet. Wenn du einen B3D-Hack gefunden hast, mit dem du die Parameter bekommst, kannst du mal austesten, wo und wann die Funktion aufgerufen wird und ob sie dir Probleme macht. Das mit dem zweiten Thread kriegst du raus, wenn du in deine Hauptschleife Stop schreibst, der Dialog immernoch funktioniert und beim Klick auf nen Button deine Callback-Funktion aufgerufen wird, obwohl ja eigentlich dein Programm stehen sollte. Dann ist ein zweiter Thread am Werk, der unabhängig von deinem Programm/Hauptthread arbeitet. Da wird's etwas knifflig. Ansonsten ist DebugLog dein Freund.

Wenn alles nichts hilft, bleibt ja auch die Frage, ob das Problem, was du mit der Windows-Funktion lösen willst, nicht auch einfach mit Blitz-Mitteln zu lösen ist.

Thunder

BeitragMo, Jul 06, 2015 23:01
Antworten mit Zitat
Benutzer-Profile anzeigen
Oder ob nicht Visual Basic .NET für deine Zwecke geeigneter ist, wenn dir die Windows API so am Herzen liegt...
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit

KnorxThieus

BeitragDi, Jul 07, 2015 8:18
Antworten mit Zitat
Benutzer-Profile anzeigen
Morgen!

Silver_Knee hat Folgendes geschrieben:
Du kannst eine Funktion schreiben [… und] dir mit FastPointer den Funktionspointer holen […]
Ich habe mir Pummelies Code noch einmal genauer angeschaut und es mal versucht:
Oben, unter der Fensterinitialisierung, füge den Code ein: BlitzBasic: [AUSKLAPPEN]
cwp = FunctionPointer()
Goto skip
WaitEvent()
.skip
Unten, ersetze die beiden Zeile bzgl. CallbackProc durch BlitzBasic: [AUSKLAPPEN]
PokeInt bank, 78, CWP		;<--- HIER! pfCallback
cwp_data = CreateBank(1)
PokeInt bank, 82, cwp_data ;<--- HIER! lpCallbackData

Leider stürzt dies – kompiliert – immer bei der FastPointer.dll ab … was mache ich falsch?

Und abgesehen davon, verstehe ich immer noch nicht wie FunctionPointer() funktioniert! Was hat das mit GoTo zu tun? Ich werde nicht daraus schlüssig!


Zum Sinn in BB: Nun ja, generell fühle ich in BlitzPlus ja (trotz der grottenmäßigen IDE …) ziemlich wohl, wenngleich ich für die GUI-mäßigen Feinheiten schwärme … ich bin wohl einfach zu faul, umzurüsten. Aber wenn es hier klappt, lerne ich dazu noch etwas!Very Happy
Version: BlitzPlus / Blitz+

Silver_Knee

BeitragMi, Jul 08, 2015 1:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Die Funktion WaitEvent ist nicht aufgebaut wie in der API beschrieben. Die funktion in der Goto-Klammer sollte so aussehen.

Code: [AUSKLAPPEN]
TaskDialogCallbackProc(
  _In_ HWND     hwnd,
  _In_ UINT     uNotification,
  _In_ WPARAM   wParam,
  _In_ LPARAM   lParam,
  _In_ LONG_PTR dwRefData
);


Das ergibt dann so etwas wie:

BlitzBasic: [AUSKLAPPEN]
cwp = FunctionPointer()
Goto skip
MeinCallback()
.skip

...


Function MeinCallback(hwnd%,uNotification%,wParam%,lParam%,dwRefData%)
DebugLog "ich wurde aufgerufen mit: "+hwnd+", "+uNotification+", "+wParam+", "+lParam+", "+dwRefData
End Function


Der Trick mit Goto bewirkt, dass Blitzbasic zwar den code "rufe die Funktion MeinCallback auf" mit in dein Programm packt, aber dank Goto da dran vorbei läuft und die Funktion gar nicht aufruft. Die Funktion FunctionPointer() liest in deiner CPU die aktuelle Code-Stelle raus, geht an dem Goto vorbei und schaut sich die Addresse der Funktion MeinCallback an. Die steht ja in "rufe die Funktion MeinCallback auf". Die Addresse bekommst du dann als Rückgabewert. Das ist ein ziemliches rumgefrickel auf Seite der FunctionPointer-Funktion.

Jetzt gibst du die Addresse in der Config an die richtige Stelle und dann versucht TaskDialogIndirect zu gegebener Zeit die übergebene Addresse als Funktion aufzurufen.

Wenn dein Programm gar nicht erst startet und die FastPointer.dll vermisst, musst du die DLL in dein decls-Verzeichns kopieren und später deiner EXE mitgeben.

Thunder

BeitragMi, Jul 08, 2015 1:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Abstürzen dürfte es trotz der falschen Funktionssignatur nicht.
Außer die Funktion erwartet per stdcall aufgerufen zu werden (imho unwahrscheinlich), aber dann hast du mit BB ein weiteres Problem, das schwer zu lösen ist...
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit

KnorxThieus

BeitragMi, Jul 08, 2015 17:11
Antworten mit Zitat
Benutzer-Profile anzeigen
So, ich habe jetzt (wiederum an anderer Stelle) den Hinweis erhalten, einmal das Beispiel auf dem MSDN-Artikel zu betrachten – kurz, dort wird überhaupt keine CallbackProc-Funktion angegeben; es ist ja wohl davon auszugehen, dass das Beispiel von Microsoft trotzdem läuft (oder?), der Parameter also optional ist.

Ich habe mir jetzt nochmal den Rest angeschaut und festgestellt: Die Absturzmeldung rührte von den nicht nach Unicode kodierten Strings her. Passt man sie mit dem hier an: BlitzBasic: [AUSKLAPPEN]
Function AnsiToUnicode$(ansi$)
Local a, unicode$
For a = 1 To Len(ansi$)
unicode$ = unicode$ + Mid$(ansi$, a, 1) + Chr$(0)
Next
Return unicode$
End Function
(Benutzung dürfte sich verstehen)
, so stürzt nix mehr ab. Stattdessen erhalte ich kein TaskDialog-Fenster und einen Rückgabewert von -2147024809 (entspräche einem Wert von -458839 als UNSIGNED_INT – das ergibt (auch) keinen Sinn.). Irgendjemand eine Ahnung, was das heißt? S_OK, E_OUTOFMEMORY, E_INVALIDARG und E_FAIL sind meiner Erinnerung nach alle positiv.

Silver_Knee hat Folgendes geschrieben:
Wenn dein Programm gar nicht erst startet und die FastPointer.dll vermisst, musst du die DLL in dein decls-Verzeichns [sic!] kopieren und später deiner EXE mitgeben.
So viel weiß ich auch schon … Nein, ich meinte, dass der Fehlermodulname mit FastPointer.dll beschriftet war.
Version: BlitzPlus / Blitz+

Thunder

BeitragMi, Jul 08, 2015 17:57
Antworten mit Zitat
Benutzer-Profile anzeigen
1. Ein unsigned int ist immer positiv
2. Wenn ein unsigned int nicht positiv ist, tritt Regel 1 inkraft Very Happy

du hast dich irgendwie verrechnet: (unsigned int) -2147024809 == +2147942487 = 0x80070057

Das entspricht genau E_INVALIDARG, siehe Liste: https://msdn.microsoft.com/en-...p/aa378137(v=vs.85).aspx

Der C++ Code funktioniert übrigens - hab ihn getestet. In BlitzPlus kann ich ja wie schon gesagt nichts testen...
Ich vermute aber (da das ja nicht dokumentiert ist, muss ich spekulieren), dass TaskDialogIndirect auf die Nutzereingabe wartet, wenn du keinen Callback übergibst. Also dein restliches Programm wäre währenddessen angehalten.
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit

KnorxThieus

BeitragMi, Jul 08, 2015 18:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Thunder hat Folgendes geschrieben:
1. Ein unsigned int ist immer positiv
2. Wenn ein unsigned int nicht positiv ist, tritt Regel 1 inkraft Very Happy
Okay, dann habe ich mich wohl verrechnet Embarassed – daher auch kein Sinn.

Ungültiges Argument? Super. An welchem es bloß liegen mag …? Nun ja, ich werde nach her mal versuchen, möglichst viele Parameter rauszustreichen (die optionalen).

Zitat:
Also dein restliches Programm wäre währenddessen angehalten.
Super, das ist ja genau das, was ich will! Smile

Edit oder AW folgt später, wenn ich weitere Ergebnisse habe.
–KnorxThieus
Version: BlitzPlus / Blitz+

Neue Antwort erstellen


Übersicht BlitzBasic Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group