XProfan - kein freier Callback

  • Hallo zusammen.


    Habe eine Problematik, zu der ich einfach keine Lösung finde. Wer kann helfen?


    Mein Programm läuft in Schleife, liest XML Dateien ein und generiert PDF Dateien (PDF-Builder).

    Da die PDF Dateien mehrseitig sein können, mache ich einen Aufruf in dieser Art.

    Code
    PDF_SetProcHeader(@procaddr("Kopfzeile_Rechnung",0))

    Da es aber nur 5 Callback-Funktionen gleichzeitig geben kann, erhalte ich die Fehlermeldung "kein freier Callback",

    sobald ich das sechste PDF generiere.

    Laut Hilfe soll man Callbackplätze mit einem Minus vor dem Parameter wieder freigeben können.

    So rufe ich am Ende meiner Prozedur folgendes auf:


    Code
    ProcAddr("Kopfzeile_Rechnung",-0)

    Bringt aber keinen Erfolg?


    Was mache ich falsch?

    Gruß und Dank - Erasmus

  • Ich kenne mich jetzt nicht so mit den Callback-Funktionen aus.

    Vielleicht hat RGH 0 Parameter nicht vorgesehen.

    Ich würde es mal mit mid. 1 Parameter probieren und dann mit -1.

    Man braucht ja diesen Parameter nicht unbedingt auszuwerten

    bzw. zu benutzen.


    Müßtest du mal ausprobieren. Ich habe jetzt auch kein adäquates Beispiel, um

    selber zu testen. Ich sehe das jetzt mal mehr aus mathematischer Sicht. Wenn

    5 Callbackfunktionen vorgesehen sind :

    5 - 0 = 5 und 0 - 0 ändert ja auch nichts.

    aber z.b. 5 - 5 (oder 5 - 3 usw.) ergibt 0 bzw. weniger als 5

    Ich weiß zwar nicht, wie RGH das umgesetzt hat, könnte mir aber sowas

    ähnliches vorstellen. Jedenfalls bekomme ich bei -0 so ein komisches Gefühl <X


    Evtl. weiß ja auch noch jemand anderes einen Rat.

    PS: Brauchst du jetzt unbedingt so einen Callback oder geht es vlt. auch anders ?

    2 Mal editiert, zuletzt von H.Brill ()

  • Eine Idee wäre noch, die Parameter nicht zu ändern und anstatt

    ProcAddr("Kopfzeile_Rechnung",-0)

    Code
    ProcAddr("Kopfzeile_Rechnung",-1)

    zu schreiben. Könnte evtl. auch helfen, da sich die Callbacks dann in der Schleife zwischen 4 und 5 bewegen.

    Damit käme man dann auch nie über die 5 max. Callbacks hinaus.

  • -1 löscht die Callback-Funktion mit einem Parameter. Das hat nichts mit 4 oder 5 Parametern zu tun. Die nutzt er ja nicht. Seine Funktion hat 0 Parameter, kann also nur mit 0 definiert werden. Allerdings die -0 macht mir auch etwas Kopfzerbrechen. Prinzipiell wäre es machbar, je nach dem, wie die Codezeile ausgewertet wird, aber rein rechnerisch gibt es kein -0. Wenn der Parameter immer rein numerisch ausgewertet wird, geht das nicht.


    Aber mal eine Überlegung: Du nutzt immer die gleiche Callback-Funktion. Deren Adresse ist ja immer gleich. Also einmal


    Var Long MyProc = ProcAddr("Kopfzeile_Rechnung", 0)


    Und weiter im Code immer dann einsetzen


    PDF_SetProcHeader(MyProc)


    Gruß Volkmar

  • Insofern hat Volkmar schon recht. Sonst würde das Beispiel in der Hilfe ja nicht laufen.

    Es gibt ja bestimmt mehr, als 5 Fonts.

    Aber RGH schreibt nun mal, daß man mit - vor der Parameteranzahl in ProcAddr() die Callbacks zurück

    setzen kann, obwohl die Parameteranzahl nichts mit der Anzahl der Callbackfunktionen zu tun hat.

    Es können ja auch nur 1, 2 Parameter oder gar keiner, wie in unserem Falle, der Callbackprozedur

    übergeben werden.


    Vielleicht wollte RGH eine weitere SET() - Funktion vermeiden und hat einfach ProcAddr() hergenommen.

    Ein

    Code
    Set("Callbacks", 0)

    wäre da besser gewesen.

    Es kommt ja darauf an, wie RGH das intern umgesetzt hat. Und wie Volkmar, wie auch ich, schon sagen, daß

    das -0 nicht so sauber ist. Und wenn RGH das Minus (-) intern wirklich so übernimmt, wundert es mich auch

    bei -0 nicht. 5 - 0 bleibt eben 5 (Max. der Callbacks). Da beißt die Maus keinen Faden ab.

    Deshalb mein Vorschlag, mal nur einen Parameter zu verwenden und mit -1 zurücksetzen oder auch nur mal

    -1 bei ProcAddr() verwenden.

    Wie gesagt, müßte man die Interna kennen. In RGH's Beispiel

    Code
    ProcAddr("Fontliste",-4)

    wird ja nur der aktuell benutzte Callbackplatz zurück gesetzt und nicht alle 5. Deshalb ist es auch

    in ProcAddr() so gemacht.


    Vielleicht suchen wir aber auch an falscher Stelle. Hast du auch das RETURN 1 bei Erfolg

    und RETURN 0, wenn nichts mehr gefunden wird, drin ? Könnte ja auch daran hängen

    und man die Callbacks gar nicht zurücksetzen muß. Da müßtest du nur einen Mechanismus

    finden. Wenn keine Datei zum Umwandeln mehr da ist, ein Return 0 zu geben. So, jedenfalls,

    verstehe ich das Beispiel von RGH.


    Da müßte man mal mit einem Beispiel, aber ohne API, experimentieren. Vielleicht hat

    Volkmar eine passende Idee (code) dazu oder mir fällt noch was passendes ein.

    3 Mal editiert, zuletzt von H.Brill ()

  • Hallo zusammen.


    Danke für eure intensiven und ausführlichen Ideen.


    Was habe ich nun gemacht?

    Habe als Parameter "1" mitgegeben.

    Dazu am Ende der PROC mit "-1" gelöscht (aber auch mal zum Test auskommentiert).


    Ich kriege eine Speicherverletzung und Profan crashed.


    Offensichtlich mag "PDF_Builder.inc" keine Aufrufe mit einem Parameter.

    Übrigens "2", "3", "4" und "5" brachten keine Alternative.


    Ratlos.


    Erasmus

  • Wie rufst du denn das Konvertieren auf ?

    Im RGH's Beispiel erwartet ja ~EnumFontFamilies eine ProcAdrr() einer Prozedur.

    ~EnumFontFamilies macht ja dann einen CALL auf eben diese Adresse. Also müßte

    man die ProcAddr() bei einer eigenen Funktion als Integer bzw. Long übergeben und

    diese ruft wiederum die CallbackProc auf. Jetzt ist die Frage, funktioniert das einfach

    so oder muß man das z.b. mit CALL machen ? Ansonsten bräuchte man ja kein ProcAddr().

    Ist evtl. auch eine Frage der XProfan-Interna, da RGH die externen Funktionen in einer

    anderen Liste verwaltet. Wie und worin werden dann die eigenen geschriebenen Procs verwaltet ?

    Da hätte RGH in der Hilfe auch mal ein Beispiel OHNE API zeigen können, damit man den

    Zusammenhang besser versteht.


    Vielleicht könntest du uns mal so ein grobes Programm-Gerüst zeigen, was du machst.

  • Geht ja nicht ohne API. Ein Callback ist einfach in einer Funktion ein eingebauter Aufruf (Call) einer wahlfreien Funktion. Im Beispiel bei EnumFonts eben ein Call zu der Funktion, die das Ergebnis aufnimmt. Jedesmal, wenn ein Font gefunden wurde, wird diese Callbackfunktion aufgerufen mit dem gefundenen Wert als Parameter.

    In Profan gibt es sowas nicht. Ersatzweise könnte man sich das so vorstellen:

    Code
    Proc Wunderwerk
      Parameters ??? ' Aufrufadresse der Callbackfunktion
      Ergebnis = TuWas
    
      While Call ???, Ergebnis
    
      EndWhile
    EndProc


    Anstelle der Fragezeichen setzt Du nun die Aufrufadresse einer beliebigen Funktion ein, die dann entweder 0 oder 1 zurückliefern muß. 1 für Weiter oder 0 für Abbrechen. Macht als Profancode keinen Sinn, da wirst Du im Code direkt Deine aufzurufende Funktion einsetzen.

    Das das nun alles etwas verzwickt zu machen ist, liegt einfach daran, daß die Parameterübergabe immer über den Stack läuft. Und darauf hast Du mit Profanmitteln keinen Zugriff. Also hat Roland da 5 wahlfrei belegbare "Adapter" eingebaut.


    Gruß Volkmar

  • Ich habe mal gerade bei der PDF-Builder.dll geschaut. Da steht dann, daß

    Code
    PDF_SetProcHeader(@procaddr("Kopfzeile_Rechnung",0))

    eine Callback-Prog braucht. In deinem Falle Kopzeile_Rechnung.

    Da steht auch nichts von einem Rückgabewert.

    Also, wenn du da nur den Header auf die jeweilige Seite der Pdf schreibst, dürfte ja nichts schiefgehen.

    Deswegen braucht es auch keine Parameter. Oder machst du sonst noch was in der Proc, was

    dann kollidieren könnte ? Da die DLL ja mehrerer Funktionen, die einen Callback benötigen, hat,

    ist die Frage, ob du schon vorher Callbackfunktionen angelegt hast. Da könnte es vielleicht eng

    werden. Wenn dem so ist, so könntest du mal schauen, ob diese Parameter haben. Und wenn,

    dann könntest du diese mit - zurücksetzen.

    Ist ja auch für XProfan gedacht, da eine .inc + .ph mitgeliefert wird. Wie weit der Autor seine DLL

    mit XProfan ausgetestet hat, weiß man ja nicht.

    Ansonsten vermute ich mal, daß nur in der Proc Kopzeile-Rechnung etwas schief läuft.

  • Ich brauche in meinem Programm halt die unterschiedlichsten Dokumente, die aus einer XML Datei entstehen könnten.


    Bsp:

    PDF_SetProcHeader(@procaddr("Kopfzeile_Firma1_Rechnung",0))

    PDF_SetProcHeader(@procaddr("Kopfzeile_Firma1_Lieferschein",0))

    PDF_SetProcHeader(@procaddr("Kopfzeile_Firma1_Ruecksendung",0))

    PDF_SetProcHeader(@procaddr("Kopfzeile_Firma1_Datenblatt",0))


    jetzt kommen aber in den folgenden PDFs womöglich andere Firmen (weil ganz anderes Layout!)

    PDF_SetProcHeader(@procaddr("Kopfzeile_Firma2_Rechnung",0))

    PDF_SetProcHeader(@procaddr("Kopfzeile_Firma2_Lieferschein",0))

    *BAMMM* sechster Aufruf - klappt nicht weiter ...


    Genau deshalb würde mir soviel daran liegen, die Callbacks wieder zu schließen.

    Das wäre ja theoretisch nach jeder PDF Generierung sofort möglich.

    Klappt aber (wie ja oben beschrieben) in der Praxis nicht :(


    Erasmus

  • Dann hängt es ja doch an den höchstens 5 Callbackfunktionen.

    Ich, an deiner Stelle, würde meine Callbackfunktion über eine

    globale Variable steuern und die entsprechenden Header bzw.

    Kopfzeilen entsprechend setzen. Diese Kopfzeilen kannst du

    ja entweder in einer separaten Datei (auch .ini), als Ressource

    oder halt als Speicherbereich oder auch vl. noch anders vorhalten.

    Je nach Wert der globalen Variablen den entsprechenden Header

    bzw. Kopfzeile schreiben. Da sind deiner Fantasie ja keine Grenzen

    gesetzt. Da kommst du dann mit einer einzigen Callbackfunktion hin.

  • Ich hatte ja schon den Vorschlag gemacht, siehe #4. Einmal am Anfang die Callbackfunktion in eine Longvariable speichern und dann diese Longvaraible jedesmal als Callback in den Code einbauen. Du mußt ja an die externe Funktion, die den Callback nutzen soll nur die Anfangsadresse Deiner Funktion übergeben, sonst nichts.

    Es geht nicht um irgendwelche Header, die Callbackfunktion muß ja auch was tun. Genau deshalb ist sie da. Um nochmal beim Beispiel EnumerateFonts zu bleiben, die ruft die angegebene Callbackfunktion bei jedem Schleifendurchlauf auf. Mit der Callbackfunktion baust Du gewissermaßen in die aufgerufene Funktion Deinen eigenen Code ein, der bei jedem Schleifendurchlauf mit ausgeführt werden soll. Zum Beispiel einfügen in eine Liste bei einem gefundenen Font. Aber der Programmierer, der Enumerate geschrieben hat, wußte ja nicht, wozu Du das nutzen willst und hat deshalb einen Aufruf vorgesehen, wo Du Deine eigene Funktion einklinken kannst.

    Anderes Beispiel: EnumerateWindows liefert alle Fenster. Eben an eine Callbackfunktion und nicht in eine Liste. Es bleibt nur Dir überlassen, was Du mit allen Fenstern machen willst. In eine Liste aufnehmen oder alle Fenster verkleinern oder alle Fenster mit einem bestimmten Stil schließen ....


    Gruß Volkmar

  • Naja, bin mal von der beiliegenden Hilfe ausgegangen :

    Vielleicht kann man auch steuern, bzw. rausbekommen, welche Seite gerade aktuell ist und entsprechend ausgeben.

    Da müßte sich mal Erasmus mit der DLL befassen. Ist mir jetzt etwas zu aufwändig. Da gibt es vl. eine Lösung.

  • Meint wohl, einen Header (Kopfzeile) auf dem Dokument ausgeben. Auf jeder Seite des Dokumentes, was Du bearbeitet, kannst Du eine Zeile mit wahlfreiem Inhalt, wie zum Beispiel "<Dokumentname> Seite x von y" ausgeben. Da der Autor nicht wußte, was Du machen willst, hat einen Callback vorgesehen. Hier hängst Du Deine eigene Funktion ein, in der der Du dann reinpackst, ob und was bei jeder Seite passieren soll.


    Gruß Volkmar

  • Sowas ähnliches meinte ich ja auch. Die Automation ist ja, auf jeder neuen Seite automatisch eine Kopzeile

    zu schreiben. Da sich aber die Themen ändern können, wurde ein Callback vorgesehen.

    Sonst könnte man ja die Kopfzeile nur einmal definieren und diese würde dann auf jede Seite gedruckt. Dafür

    bräuchte es ja keinen Callback. Um aber da eingreifen zu können, ist der Callback da.


    Er müßte die Procs

    in einer Proc vereinen und jenachdem, welches Thema ansteht (Rechnung, Lieferschein usw.)

    entsprechend die Kopzeile neu definieren. z.b. kommt ja auf ein Datenblatt keine Kundenadresse o. ä.

    Weil er ja die Daten linear in die PDF runterschreibt, weiß er ja, wo er sich befindet (Firma1_Rechnung,

    Firma1_Lieferschein, Datenblatt usw.).

    So in etwa verstehe ich mal das Ganze.

  • Ja, so ungefähr. Da die Ausgabe ein String sein sollte, wäre auch denkbar, eine globale Stringvariable zu nehmen. Die könnte dann je nach Anwendungsfall bestückt werden, ohne die Callbackfunktion wechseln zu müssen.


    Gruß Volkmar

  • Ich werde das prüfen, glaube aber nicht, dass es mit einer Variable laufen wird, solange ich den Callback NICHT WIEDERAUFHEBE.


    Variable hin oder her, ich werde in einem Programmaufruf mehr als 5 Callbacks haben und damit den Crash.


    Gruß Erasmus

  • Was ich meinte ist, du sollst die ganzen Callbackroutinen in einer einzigen vereinen.

    Dann je nach Wert der globalen Variablen die entsprechende Kopfzeile setzen.

    Vorraussetzung dafür ist, daß du weißt, welches Thema (Firma1_Rechnung,

    Firma2_Datenblatt usw.) gerade abgearbeitet wird und ob die nächste Seite

    noch dazu gehören wird.


    Ich kenne deine XML-Dateien jetzt nicht. Dort müßtest du dann schauen, wann

    der nächste Knoten für das nächste Thema anfängt und dann am Ende des Themas

    entsprechend die globale Variable mit einem Wert bestücken. Dieser bestimmt dann

    im Callback den Text der Kopfzeile. Die Themen müßtest du natürlich vor zählen.

    Wenn du z.b. 8 Themen hast, könntest du z.b. eine Datei anlegen :

    1,Text, Adresse, Rechnung, Firma1 (halt alles, was zur Kopfzeile dazugehört)

    2,Text, Adresse, Lieferschein, Firma1 (halt alles, was zur Kopfzeile dazugehört)

    3,Text, Adresse, Rücksendung, Firma1 (halt alles, was zur Kopfzeile dazugehört)

    4,Text, Artikel, Datenblatt, Firma1 (halt alles, was zur Kopfzeile dazugehört)

    5,Text, Adresse, Rechnung, Firma2(halt alles, was zur Kopfzeile dazugehört)

    6,Text, Adresse, Lieferschein, Firma2 (halt alles, was zur Kopfzeile dazugehört)

    7,Text, Adresse, Rücksendung, Firma2 (halt alles, was zur Kopfzeile dazugehört)

    8,Text, Artikel, Datenblatt, Firma2 (halt alles, was zur Kopfzeile dazugehört)

    usw.

    Vielleicht kann man auch die benötigten Daten direkt aus der XML rauslesen.

    Dann würde statt einer Datei auch so eine Art HashTabelle oder 2dim. Array genügen.


    Anhand der Nummer (1-8) , die in der globalen Variablen steht, hast du dann auch

    die entsprechende Kopfzeile.


    Ist jetzt alles etwas theoretisch gemeint.

    Einmal editiert, zuletzt von H.Brill ()

  • Zitat

    Was ich meinte ist, du sollst die ganzen Callbackroutinen in einer einzigen vereinen.

    Dann je nach Wert der globalen Variablen die entsprechende Kopfzeile setzen.

    Vorraussetzung dafür ist, daß du weißt, welches Thema (Firma1_Rechnung,

    Firma2_Datenblatt usw.) gerade abgearbeitet wird und ob die nächste Seite

    noch dazu gehören wird.


    Das hört sich nach einer richtig geilen Idee an, stimmt. Werde ich am Wochenende checken.

    Gruß - Erasmus

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!