Announcement

Collapse
No announcement yet.

Win32-API Funktionsparameter nicht kompatibel

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Win32-API Funktionsparameter nicht kompatibel

    Hallo Leute,<br>
    ich verwende jetzt des öfteren API-Funktionen und musste dabei feststellen, dass gewisse Typen (Parameter-Variablen) nicht mit Delphi kompatibel sind. Davon zeugt jedenfalls die Fehlermeldung "Formale und Tatsächliche Parameter müssen übereinstimmen". Dabei habe ich doch schon den in der API-Hilfe angegebenen Variablentyp verwendet, aber der bringt's auch nicht. Kann mir (bitte, bitte) jemand helfen?<br>
    Vielen Dank,<br>
    Leonhardt

  • #2
    Hallo,

    wie sieht das konkrete Problem an einem Beispiel aus?

    Delphi hat an verschiedenen Stellen je verwendete Version Probleme mit den Win32-Funktionsparametern, wobei sich diese Probleme in 2 Kategorien einteilen lassen: <br>
    1. Falscher verwendeter Datentyp <br>
    2. Falsche Deklaration eines VAR-Parameters

    Zum Beispiel hatte Delphi 4 ein Problem mit der folgenden Deklaration:
    <pre>
    OffsetViewPortOrgEx( ,,,,, var Points);
    </pre>
    Der letzte Parameter ist falsch - richtig wäre P:PPoint, denn als Point kann kein nil-Wert übergeben werden! Um dies zu korrigieren, konnte (wenn ich mich richtig erinnere) über die Typumwandlung nachgebessert werden:
    <pre>
    OffsetViewPortOrgEx(0, 0, 0, PPoint(nil)^ );
    </pre>

    P.S: Borland verwendet ein eigenes Tool, das die Header-Dateien aus dem SDK automatisch in Object Pascal-Units konvertiert. Somit kommt es immer wieder vor, das in einer neuen Delphi-Version ein Fehler wieder auftaucht, der bereits im UpdatePack der letzten Version beseitigt wurde.

    &#10

    Comment


    • #3
      Mit der Typumwandlung funktioniert es nicht, siehe meine neue Diskussion im Win32-Ordner. Das Problem tritt bei fast allen Pointern und STRUCTs auf.

      Der Code sieht ungefähr so aus:
      <font color="#00AA00">
      <p><b>var</b><br>
      S:TSearchRec;<br>
      info:TSHFileInfo;<br>
      si:INTeger;<br>
      <b>begin</b><br>
      .<br>
      .<br>
      .<br>
      si:=SizeOf(info);<br>
      ShellApi.SHGetFileInfo(PChar(S.Name),S.Attr,@info, si,SHGFI_TYPENAME);<br>
      .<br>
      .<br>
      .<br>
      <b>end;</b><br></p></font>

      <br>Im voraus Danke für Ihre Hilfe,<br>
      Leonhard

      Comment


      • #4
        Hallo,

        der Grund für diese Probleme liegt in der falschen Herangehensweise. Angenommen, mit Delphi 5 wird folgendes im Programm geschrieben:
        <pre>
        uses ShellAPI;

        procedure TForm1.Button1Click(Sender: TObject);
        var
        S:TSearchRec;
        info:TSHFileInfo;
        si:INTeger;
        begin
        si:=SizeOf(info);
        ShellApi.SHGetFileInfo(PChar(S.Name),S.Attr,@info, si,SHGFI_TYPENAME);
        end;
        </pre>
        Delphi beschwert sich beim Compilieren zu Recht mit dem Hinweis "<i>Die Typen der tatsächlichen und formlane VAR-Parameter müssen übereinstimmen</i>".

        Mit einem Mausklick auf SHGetFileInfo bei gedrückter STRG-Taste springt Delphi 5 sofort in die Unit, in der diese Funktion deklariert wurde. Und dort findet man die folgende Zeile:
        <pre>
        function SHGetFileInfo(pszPath: PAnsiChar; dwFileAttributes: DWORD;
        var psfi: TSHFileInfo; cbFileInfo, uFlags: UINT): DWORD; stdcall;
        </pre>
        Ein Blick auf diese Deklaration genügt, um gleich 2 Unterschiede zu erkennen: <br>
        1. Der VAR-Parameter psfi ist <b>kein</b> Zeiger, also darf kein @ verwendet werden. <br>
        2. Die beiden letzten Parameter sind UINT, was jedoch nicht weiter stört (INTEGER ist in diesem Fall kompatibel).

        Somit reicht es aus, den fehlerhaften Aufruf wie folgt umzuformulieren:
        <pre>
        procedure TForm1.Button1Click(Sender: TObject);
        var
        S : TSearchRec;
        info : TSHFileInfo;
        si : UINT;
        begin
        si := SizeOf(info);
        SHGetFileInfo(PChar(S.Name),S.Attr,info,si,SHGFI_T YPENAME);
        end;
        </pre&gt

        Comment


        • #5
          Vielen Dank Herr Kosch,<br>
          mit Ihrer Hilfe hat es letztendlich doch funktioniert..

          Comment


          • #6
            Sehr geehrter Herr Korsch,

            leider stimmt Ihre Aussage aber nicht immer. In C werden Zeiger nämlich in zweierlei Kontext benutzt (es gibt noch mehr Kontexte)
            1.) Tatsächlich als Verweis der dann auch NULL sein kann.
            2.) Wenn Referenz Variablen übergeben werden sollen. (in Pascal Var Parameter).

            Leider gibt es keine Möglickheit aus dem C Quelltext herauszufinden, welche der Möglichkeite vorliegt. Offensichtlich scheint das Tool von Borland hier auch Probleme zu haben.

            Weiterhin hat die Win32 API ein schlimme Unsitte: die Grösse von Strukturen ist nich fix! Oftmals wird im ersten Feld der Struktur eingetragen wie gross die Struktur tatsächlich ist. In C werden Strukturen eigentlich immer als Zeiger übergeben (dies ist ein weiterer Kontext, hier werden Zeiger verwendet weil dies effizienter ist). Wird nun solch ein Zeiger bei der Übersetzung in Pascal zu einem Var Parameter umgewandelt ist es meines Wissens nach nicht möglich die flexible Grösse der Strukturen in Pascal zu realisieren.

            Ich möchte dies an einem konkreten Beispiel verdeutlichen.

            Ich versuche den Dialog für die Konfiguration eines Modems aufzurufen. Leider komme ich damit nicht so ganz klar.
            Es gibt beim Code von unten eine Zugriffsverletzung. Was mache ich falsch. Sind die Definitionen der importierten Kernel32.dll Funktionen in windows.pas richtig??

            procedure ModemConfigDialog(const modemName:string; handle:HWND);
            var
            pcc:PCommConfig;
            sizeWord;
            begin
            GetMem(pcc, sizeof(TCommConfig));
            try
            FillChar(pcc^, sizeof(TCommConfig), 0);
            pcc^.dwSize:=sizeof(TCommConfig);
            if not GetDefaultCommConfig(PChar(modemName), pcc^, size) then begin
            FreeMem(pcc); // structure is too small
            GetMem(pcc, size);
            pcc^.dwSize:=size;
            end;
            if not CommConfigDialog(PChar(modemName), handle, pcc^) then
            RaiseLastWin32Error;
            finally
            FreeMem(pcc);
            end;
            end;

            Mit freundlichen Grüßen

            Hansjörg Reister

            ___________________________________
            Robert Bosch GmbH s QI/RZS4
            s Systemtechnik 4 Integrationslabor s
            s System Technology 4 Integration Laboratory s
            * Postfach 300220 s Heilbronner Str. 300-302 s 70442 Stuttgart
            ( 0(049)711/811-30212
            7 0(049)711/811-2631433
            - Geschäftlich: [email protected]
            / Privat: [email protected]

            Comment


            • #7
              Hallo,

              mit dem folgenden Beispiel kann ich unter Windows NT 4 den Konfigurations-Dialog problemlos aufrufen. Gegenüber der o.g. Version habe ich 3 Änderungen vorgenommmen: <br>
              1. Klassischer nullterminierter String anstelle der Typumwandlung<br>
              2. GetDefaultCommConfig-Parameter dwSize wird vorher initialisiert<br>
              3. Keine Zeigervariablen, sondern direkt die beiden Strukturen übergeben (d.h. keine dynamische Speicheranforderung):
              <pre>
              procedure TForm1.Button1Click(Sender: TObject);
              var
              szName : array[0..5] of char;
              aCC : TCommConfig;
              dwSize : DWORD;
              aCOMMCONFIG : _COMMCONFIG;
              begin
              szName := 'COM1' + #0;
              // beim alten Aufruf war "Size" undefiniert, SDK fordert aber [in/out]
              dwSize := SizeOf(TCommConfig);
              aCC.dwSize := dwSize;
              ShowMessage(Format('%d Bytes im Puffer Platz.', [dwSize]));
              if not GetDefaultCommConfig(szName, aCC, dwSize) then
              RaiseLastWin32Error;
              ShowMessage(Format('%d Bytes kopiert.', [dwSize]));
              if not CommConfigDialog(szName, Handle, aCOMMCONFIG) then
              RaiseLastWin32Error;
              end;
              </pre>

              P.S: Ich habe immer nur die Datentypen verwendet, die Delphi 5 in seiner Programmier-Hilfe (<b>Code-Parameter</b>) haben wollte

              Comment

              Working...
              X