DLLCall mit dynamischer Pufferlänge

  • Hallo AutoIt Gurus,

    auf dem engl. Forum wurde ich mit der Frage konfrontiert, wie man bei einem DLL Aufruf einen Puffer mit dynamischer Länge angibt. Beispiel in Funktion _ClipBoard_GetFormatName:

    [autoit]

    Local $aResult = DllCall("user32.dll", "int", "GetClipboardFormatNameW", "uint", $iFormat, "wstr", "", "int", 4096)

    [/autoit]

    Ich sehe nur folgende Möglichkeiten

    • DIe Länge des Puffers vorab berechnen (wird aber nicht immer möglich sein)
    • Angeben, dass die aufgerufene DLL die Pufferlänge selbst bestimmt und einen entsprechend großen Puffer zurückgibt
    • Es wird eine fixe Pufferlänge angegeben und die DLL gibt mit einem Returncode an, dass noch mehr Daten vorhanden sind und die DLL nochmals aufgerufen werden muss um weitere Daten zu übergeben

    An der Beschreibung seht Ihr schon, dass ich von DLLs etc. nicht viel Ahnung habe.
    Gibt's eine Möglichkeit die fixe Pufferlänge zu umgehen?

    Vielen Dank!

  • Es gibt noch zwei weitere Varianten:
    - Die DLL erstellt den Buffer selbst und bietet zusätzlich noch eine Funktion zum Freigeben an
    - Die DLL erstellt einen Buffer der bis zum nächsten Aufruf einer Funktion, die den Buffer benötigt gültig ist.
    - Du gibst der DLL die Pointer zu Funktionen zum allokieren, reallokieren und löschen von Speicher. Die DLL nimmt diese Funktion um den Buffer zu allokieren und du machst dann später damit was du willst.

  • Vielen Dank für Eure Rückmeldungen!
    Wie würdet Ihr das konkret bei meinem Beispiel aus dem ersten Post machen?

    • Offizieller Beitrag

    Wie würdet Ihr das konkret bei meinem Beispiel aus dem ersten Post machen?


    Wenn die Funktion erfolgreich ist, wird die Länge der in den Puffer kopierten Zeichen zurückgegeben.
    Also:
    - überlangen Puffer bereitstellen
    - 1. Aufruf liefert Länge des notwendigen Puffers
    - Puffer mit dieser Länge erstellen
    - 2. Aufruf zum Befüllen auf exakte Puffergröße

  • Für GetClipboardFormatName kannst du nur einen überlangen Puffer angeben und dann den String passend zuschneiden mit StringLeft. Weder die Funktion och die DLL enthält Funktionalität um die benötigte Größe festzustellen. Mehr als 512 Zeichen werden hier meiner Meinung nach nie benötigt.

    • Offizieller Beitrag

    Weder die Funktion och die DLL enthält Funktionalität um die benötigte Größe festzustellen.

    Zitat von MSDN

    If the function succeeds, the return value is the length, in characters, of the string copied to the buffer.


    Hab es nicht getestet, aber laut MSDN ist die Funktionalität gegeben.

    Edit:

    Habe gerade noch wesentliche Informationen in der Diskussion entdeckt:

    Zitat

    lpszFormatName is NUL terminated
    The API documentation fails to mention that the data dropped into the lpszFormatName buffer is always NUL (zero) terminated. The length returned is the number of characters not including the terminating NUL. Thus if the returned length is one less than the size of your lpszFormatName (in characters) then it's possible the format name was truncated.

    This document also fails to mention what the maximum possible size is for a name that could get dropped into the lpszFormatName buffer Microsoft's example code uses an 80 character buffer. The RegisterClipboardFormat() API documentation is also silent on this other than to note that it's a case-insensitive string. A scan of the registered formats from 0xC000 to 0xFFFF finds the names range from 3 to 113 characters on my system at this instant. Testing finds that RegisterClipboardFormat() returns error 87 ERROR_INVALID_PARAMETER if lpszFormatName is 256 characters or longer. Attempts to register a zero length name result in error 123 ERROR_INVALID_NAME. In other words, the lpszFormatName can be from 1 to 255 characters plus the terminating NUL. Thus using a 256 character buffer will work for most, if not all, systems.


    Also, der Puffer darf nicht größer als 256 Zeichen sein und muß Nulltermination berücksichtigen.

  • Hab es nicht getestet, aber laut MSDN ist die Funktionalität gegeben.


    Ich sehe es nicht so. Du musst schon einen übergroßen Buffer erstellen, erst danach bekommst du die Größe. Um die nötige Größe zu finden bevor man den Buffer erstellt, muss die Funktion bei einer Bufferlänge von 0 die nötige Größe angeben oder es muss eine Funktion "GetClipboardFormatNameLength" geben. Beides ist aber nicht vorhanden.

    Zitat

    If the function succeeds, the return value is the length, in characters, of the string copied to the buffer.


    Die Größe des Strings im Buffer, ja. Wenn du einen 12-Zeichen Buffer hast und der String 24 lang ist, dann hast du am Ende 11 oder 12 Zeichen im Buffer und das ist dann auch der Rückgabewert. So lese ich das jedenfalls, testen kann ich gerade nicht weil meine Windows8-VM abgelaufen ist ;)

  • Danke für die Infos! Ich werde sie weitermelden, mal sehen, was dabei rauskommt!