Ankündigung

Einklappen
Keine Ankündigung bisher.

Erstellung einer Extension mit Einbindung externer DLL

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Erstellung einer Extension mit Einbindung externer DLL

    Hallo,

    ich bin ganz neu hier und das, weil ich bei einem Problem einfach nicht weiter weiß. Vielleicht kann mir jemand den entscheidenden Tipp geben zur Lösung des Problems.

    Lange Rede, kurzer Sinn, es geht um die Erstellung einer PHP Extension die eine andere DLL (keine PHP Bibliothek) einbindet und Funktionen aus dieser verwenden soll.

    Das ganze programmiere ich in Visual Studio C++ 2005 (Express Edition).
    Eine simple Extension, die anhand von Parametern eine Berechnung macht oder einen Paramter als Text ausgibt, habe ich geschrieben (unter Zuhilfenahme dieses Tutorials) und sie funktioniert auch in meiner PHP Umgebung (Windows Server 2003, IIS, PHP, MySQL).
    Gehe ich nun jedoch dazu über, eine externe Bibliothek einzubinden, kompiliere das ganze (ohne Fehler) und lade diese Extension in PHP, so funktionieren weder die vormals lauffähigen Funktionen noch die neuen, die auf die externe DLL zugreifen. Genauer gesagt wird die Extension nicht mal von PHP geladen, denn sie taucht in der php.ini nicht mehr auf.
    Die externe DLL ist eine Windows DLL des Little Color Management.
    Im Anschluss habe ich mal meinen Code der Extension, woran vielleicht schon erkannt werden kann, was mein Fehler ist.
    PHP-Code:
    #include "stdafx.h"
    #include "LittleCMS.h"

    /* declaration of functions to be exported */
    ZEND_FUNCTION(DoubleUp);
    PHP_FUNCTION(hello_greetme);
    PHP_FUNCTION(convert_rgb_to_cmyk);

    /* compiled function list so Zend knows what's in this module */
    zend_function_entry CustomExtModule_functions[] = {
        
    ZEND_FE(DoubleUpNULL)
        
    PHP_FE(hello_greetmeNULL)
        
    PHP_FE(convert_rgb_to_cmykNULL)
        {
    NULLNULLNULL}
    };

    /* compiled module information */
    zend_module_entry CustomExtModule_module_entry = {
        
    STANDARD_MODULE_HEADER,
        
    "CustomExt Module",
        
    CustomExtModule_functions,
        
    NULLNULLNULLNULLNULL,
        
    NO_VERSION_YETSTANDARD_MODULE_PROPERTIES
    };

    /* implement standard "stub" routine to introduce ourselves to Zend */
    ZEND_GET_MODULE(CustomExtModule)

    /* DoubleUp function */
    /* This method takes 1 parameter, a long value, returns the value multiplied by 2 */
    ZEND_FUNCTION(DoubleUp)
    {
        
    long paramValue 0;
        if (
    zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC"l", &paramValue) == FAILURE) {
            
    RETURN_STRING("Bad parameters!"true);
        }
        
    paramValue *= 2;
        
    RETURN_LONG(paramValue);
    }

    /* hello_greetme function */
    /* This method takes 1 parameter, a string value, returns the value combined with a Hello... */
    PHP_FUNCTION(hello_greetme)
    {
        
    char *name;
        
    int name_len;

        if (
    zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC"s", &name, &name_len) == FAILURE) {
            
    RETURN_NULL();
        }

        
    php_printf("Hello %s "name);

        
    RETURN_TRUE;
    }

    /* Transform an image from RGB->CMYK */
    /* This method takes 3 parameters:
        - a string with the rgb profile filename
        - a string with the cmyk profile filename
        - a string with the image file to be transformed */
    PHP_FUNCTION(convert_rgb_to_cmyk)
    {
        
    char *imagefilename;
        
    char *rgbprofilename;
        
    char *cmykprofilename;
        
        
    CLittleCMS cms;
        
    cmsHPROFILE profileRgb;
        
    cmsHPROFILE profileCMYK;

        if(!
    cms.init("LCMS.DLL"))
        {
            
    printf("Failed to load the lcms DLL\n");
            
    //return(0);
        
    }

        if (
    zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC"s", &imagefilename, &rgbprofilename, &cmykprofilename) == FAILURE)
        {
            
    RETURN_STRING("Wrong parameters!"true);
        }

        
    // Load ICC profiles
        
    profileRgb cms.cmsdOpenProfileFromFile(rgbprofilename"r");
        
    profileCMYK cms.cmsdOpenProfileFromFile(cmykprofilename"r");
        
        
    php_printf("Opened Profile: %s "cms.cmsdTakeProductName(profileRgb));
        
    php_printf("Opened Profile: %s "cms.cmsdTakeProductName(profileCMYK)); 

        
    cms.cmsdCloseProfile(profileRgb);
        
    cms.cmsdCloseProfile(profileCMYK);
        
        
    RETURN_TRUE;

    Die Kompilierung des Projektes funktioniert, wie bereits geschrieben, tadellos. Ich habe Zugriff auf die Methoden der lcms DLL.
    Wenn diese nun kompilierte Extension jedoch eingebunden werden soll, wird sie das nicht. In der Windows Ereignisanzeige konnte ich keinen Eintrag finden, dass die DLL beim Starten des IIS nicht korrekt geladen werden konnte, daher weiß ich leider auch nicht weiter, wie ich herausfinden kann, woran es liegt.
    Die lcms DLL habe ich sowohl im Linker des Projektes mit der zugehörigen .lib angegeben, als auch wie zu sehen, die Header Datei in die Quelltextdatei eingebunden.


    Bis denne, Han Solo

  • #2
    Zitat von Han Solo Beitrag anzeigen
    Genauer gesagt wird die Extension nicht mal von PHP geladen, denn sie taucht in der php.ini nicht mehr auf.
    Damit ist die Ausgabe von phpinfo() gemeint?
    Windows muss die "andere" DLL zur Laufzeit finden können. Wo liegen denn die Dateien?

    Kommentar


    • #3
      Ja genau, es wird nicht mit phpinfo() angezeigt.
      Inzwischen jedoch, nachdem ich die andere DLL, also die, die ich in meine Extension einbinde, noch einmal neu kompiliert habe, funktioniert die Extension.
      Das ist aber zuviel gesagt, zwar sind die simplen Methoden der Berechnung und Textausgabe funktionsfähig, doch beim ausführen der anderen, neuen Methode, die intern Methoden der eingebundenen DLL aufruft, bekomme ich nun die Fehlermeldung PHP has encountered an Access Violation at 01D041FB.
      Die externe DLL liegt im "ext" Verzeichnis von PHP, genau wie eben die Extension, die diese auch nutzt. Der IIS hat Lese- und Schreibrechte, inklusive Ausfürhren, was also auch irgendwie nicht der Grund sein kann.
      Zuerst habe ich vermutet, der IIS bzw. PHP kann die DLL nicht includieren, aber scheint ja nicht so zu sein.
      Wird die Methode, welche die DLL Methode anspricht, nicht aufgerufen, gibt es keine Zugriffsverletzung.


      Bis denne, Han Solo

      Kommentar


      • #4
        Bau mal in die Funktion einen DebugBreak() ein und lass Dir einen Debug-Build erstellen. Dann kannst Du Dich mit dem Debugger im Visual Studio ein bisschen umsehen. DebugBreak Function (Windows)

        In den Compiler-Flags von beiden DLLs solltest Du jeweils eines der folgenden Flags finden: /MD, /MT, /LD (beim Debug-Build hängt da immer noch ein kleines d dran). Welches dieser drei Flags ist bei den Projekten gesetzt?

        Kommentar


        • #5
          In meiner PHP Extension ist /MTd bei den Compileroptions angegeben.

          Es besteht leider das Problem, dass ich auf einem Vista Rechner mit Studio 2005 die Extension erstelle, dort jedoch kein PHP mit IIS installiert habe. Ausgeführt wird das ganze dann auf einem anderen PC, der widerum kein Studio installiert hat.

          Was ich auch noch anmerken möchte. Wie mir gerade aufgefallen ist. Der Access Violation Fehler wird auch geworfen wenn ich die Methode aufrufe ohne irgendetwas zu tun. Genauer gesagt, nachdem ich die Anzahl der Parameter der Methode auf 3 erhöht habe.

          Mein PHP Extension Code sieht aktuell so aus:
          PHP-Code:
          #include "stdafx.h"
          #include "lcms.h"
          #include "icc34.h"

          bool file_exists(const char filename)
          {
              if (
          FILE file fopen(filename"r"))
              {
                  
          fclose(file);
                  return 
          true;
              }
              return 
          false;
          }

          /* declaration of functions to be exported */
          ZEND_FUNCTION(DoubleUp);
          PHP_FUNCTION(hello_greetme);
          PHP_FUNCTION(convert_rgb_to_cmyk);

          /* compiled function list so Zend knows what's in this module */
          zend_function_entry CustomExtModule_functions[] = {
              
          ZEND_FE(DoubleUpNULL)
              
          PHP_FE(hello_greetmeNULL)
              
          PHP_FE(convert_rgb_to_cmykNULL)
              {
          NULLNULLNULL}
          };

          /* compiled module information */
          zend_module_entry CustomExtModule_module_entry = {
              
          STANDARD_MODULE_HEADER,
              
          "CustomExt Module",
              
          CustomExtModule_functions,
              
          NULLNULLNULLNULLNULL,
              
          NO_VERSION_YETSTANDARD_MODULE_PROPERTIES
          };

          /* implement standard "stub" routine to introduce ourselves to Zend */
          ZEND_GET_MODULE(CustomExtModule)

          /* DoubleUp function */
          /* This method takes 1 parameter, a long value, returns the value multiplied by 2 */
          ZEND_FUNCTION(DoubleUp)
          {
              
          long paramValue 0;
              if (
          zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC"l", &paramValue) == FAILURE) {
                  
          RETURN_STRING("Bad parameters!"true);
              }
              
          paramValue *= 2;
              
          RETURN_LONG(paramValue);
          }

          /* hello_greetme function */
          /* This method takes 1 parameter, a string value, returns the value combined with a Hello... */
          PHP_FUNCTION(hello_greetme)
          {
              
          char *name;
              
          int name_len;

              if (
          zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC"s", &name, &name_len) == FAILURE) {
                  
          RETURN_NULL();
              }

              
          php_printf("Hello %s "name);

              
          RETURN_TRUE;
          }

          /* Transform an image from RGB->CMYK */
          /* This method takes 3 parameters:
              - a string with the rgb profile filename
              - a string with the cmyk profile filename
              - a string with the image file to be transformed */
          PHP_FUNCTION(convert_rgb_to_cmyk)
          {
              
          char *imagefilename;
              
          char *rgbprofilename;
              
          char *cmykprofilename;
              
              
          cmsHPROFILE profileRgb;
              
          cmsHPROFILE profileCMYK;

              
              if (
          zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC"sss", &imagefilename, &rgbprofilename, &cmykprofilename) == FAILURE)
              {
                  
          RETURN_STRING("Wrong parameters!"true);
              }

              
          // Load ICC profiles
              //profileRgb = cms.cmsdOpenProfileFromFile(rgbprofilename, "r");
              //profileCMYK = cms.cmsdOpenProfileFromFile(cmykprofilename, "r");
              //profileRgb = cmsOpenProfileFromFile(rgbprofilename, "r");
              //profileCMYK = cmsOpenProfileFromFile(cmykprofilename, "r");
              
              //php_printf("Opened Profile: %s ", cms.cmsdTakeProductName(profileRgb));
              //php_printf("Opened Profile: %s ", cms.cmsdTakeProductName(profileCMYK));
              //php_printf("Opened Profile: %s ", cmsTakeProductName(profileRgb));
              //php_printf("Opened Profile: %s ", cmsTakeProductName(profileCMYK));

              //cms.cmsdCloseProfile(profileRgb);
              //cms.cmsdCloseProfile(profileCMYK);
              //cmsCloseProfile(profileRgb);
              //cmsCloseProfile(profileCMYK);

              
          RETURN_TRUE;

          Der Aufruf der Methode in PHP sieht wie folgt aus:
          PHP-Code:
          <?php
          $value 
          14;
          $result DoubleUp($value);
          print 
          "Calling DoubleUp($value) returned $result";


          echo 
          "<br />";
          $name "Blub";
          hello_greetme($name);

          // imagefilename, rgbprofilename, cmykprofilename
          convert_rgb_to_cmyk("""rgb.icm""cmyk.icc");
          ?>

          Bis denne, Han Solo

          Kommentar


          • #6
            Zitat von Han Solo Beitrag anzeigen
            Es besteht leider das Problem, dass ich auf einem Vista Rechner mit Studio 2005 die Extension erstelle, dort jedoch kein PHP mit IIS installiert habe.
            Kannst Du das ändern? Oder auf dem IIS Rechner die Remote Debugger Komponenten installieren (wobei ich nicht weiss, ob die Express Version das mitmacht)?
            Die "externe" Bibliothek hast Du nicht selbst übersetzt?

            Kommentar


            • #7
              Das wird ein Produktivsystem, wo ich nicht allzuviel schrauben will. Bin kein Systemadministrator, muss aber in dem Fall sehr viel von dessen Arbeit übernehmen. Daher sind mir Eingriffe, die ich nicht 100%ig sicher machen kann, und wo ich nicht gewähren kann, dass damit keine Sicherheitslücken entstehen, nicht sehr willkommen.
              Das schränkt ungemein ein, ich weiß, doch leider bleibt mir nichts anderes übrig.

              Die andere DLL hab ich selber kompiliert. Damit war es mir möglich, sie überhaupt fehlerfrei zu laden und es wurde die Extension von PHP erkannt.
              Bei der DLL handelt es sich um das Little Color Management. Als Source nutzte ich diesen, ludt das Visual Studio VC Projekt und kompilierte nur das lcms Projekt. Bekam damit eine lcmsd.lib und eine lcmsd.dll. Alles entsprechend in mein PHP Extension Projekt kopiert, im Linker eingebunden (die .lib), die .h includiert und hab damit Zugriff auf die Methoden der DLL.

              Was mir nun jedoch auch auffällt ist, dass auch bei auskommentierten Codezeilen die Extension den Zugriffsfehler erzeugt. Ich habe die auskommentierten Codezeilen zum erzeugen von Variablen eines Typs der lcms DLL jetzt nochmal komplett rausgeworfen und die Methode warf keinen Error beim simplen php_printf() zum Anzeigen des übergebenen Parameters.
              Danach erweiterte ich die Methode auf 3 Parameter
              PHP-Code:
              if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC"sss", &imagefilename, &rgbprofilename, &cmykprofilename) == FAILURE
              und war auch gewillt, diese auszugeben, bekam dann jedoch sofort wieder eine Access Violation.
              Irgendwie will mir das nicht in den Kopf gehen, was das Problem daran ist und warum beim ändern der Parameteranzahl schon einen Zugriffsfehler bekomme. Auch bei den anderen Methoden, die mit einem Parameter funtkionieren, tritt der Zugriffsfehler auf, wenn ich die Parameteranzahl erhöhe und entprechend viele Parameter übergebe. Werden zu wenig Parameter übergeben, gibt PHP die Fehlermeldung
              Warning: hello_greetme() expects exactly 2 parameters, 1 given in C:\Inetpub\wwwroot\testext.php on line 9
              aus. Bei zuvielen Parametern wie gesagt die Access Violation.

              Mache ich einen Fehler bei der Definition der Anzahl der Parameter oder beim instanzieren der Variablen des eingebundenen DLL?


              Bis denne, Han Solo

              Kommentar


              • #8
                Debugger auf dem Produktivsystem geht nicht, ok. Geht IIS auf dem Entwicklungsrechner? Wenn nicht, versuch es doch mal mit einem Apache auf dem Entwicklungsrechner.

                Kommentar


                • #9
                  Ich habe nun auf dem Entwicklungssystem den IIS inklusive PHP eingerichtet und die Extension eingebunden. Es tritt der gleiche Fehler auf.
                  Sowie ich mehr als einen Parameter an die Funktionen übergebe (die z.B. 2 erwartet) wird die Access Violation geworfen.

                  Also wäre an dieser Stelle ein Debuggen der PHP Extension sinnvoll? Nur wie mache ich das, wenn die im ./ext Verzeichnis von PHP liegt.

                  Diese PHP Extension Programmierung ist für mich totales Neuland und deswegen mögen manche Fragen komisch klingen.


                  Bis denne, Han Solo

                  Kommentar


                  • #10
                    Zitat von David Beitrag anzeigen
                    Bau mal in die Funktion einen DebugBreak() ein und lass Dir einen Debug-Build erstellen. Dann kannst Du Dich mit dem Debugger im Visual Studio ein bisschen umsehen. DebugBreak Function (Windows)
                    Genau das. Wenn Du einen Debug-Build erstellst bekommst Du .pdb Dateien (IIRC) in denen weitere Debug-Informationen für den Debugger stehen. Die kannst Du auch einfach in das ext Verzeichnis kopieren. Wenn nicht, fragt das Visual Studio bei Bedarf nach dem Ort der .pdb Datei (wie gesagt, wenn ich mich richtig erinnere).
                    Sobald das Programm auf die DebugBreak Anweisung trifft, wird eine Ausnahme erzeugt und Windows fragt nach, ob und womit das Programm debugged werden soll (es sei denn ein entsprechender handler wurde eingebaut)

                    Kommentar


                    • #11
                      Hab das jetzt mal entsprechend geschachtelt bei einer Methode und versucht den DebugBreak anzuwenden, aber mich dabei wohl falsch verhalten.
                      Es wird weiterhin die Access Violation geworfen anstatt ein Debugger angefragt.

                      Die .pdb zusammen mit der .dll der extension liegt im ./ext Verzeichnis von PHP.

                      Zur Veranschaulichtung und eventuellen Fehlerdiagnose, der Code der Funktion, die den DebugBreak nutzen soll:
                      PHP-Code:
                      PHP_FUNCTION(hello_user)
                      {
                          
                      __try 
                          
                      {
                              
                      char *username;
                              
                      char *secondname;

                              if (
                      zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC"ss", &username, &secondname) == FAILURE) {
                                  
                      RETURN_NULL();
                              }

                              
                      php_printf("Hallo %s %s!"usernamesecondname);   
                          }
                          
                      __except(GetExceptionCode() == EXCEPTION_BREAKPOINT EXCEPTION_EXECUTE_HANDLER EXCEPTION_CONTINUE_SEARCH
                          {
                              
                      DebugBreak();
                          }

                          
                      RETURN_TRUE;


                      Bis denne, Han Solo

                      Kommentar


                      • #12
                        Ich habe eher an
                        Code:
                        PHP_FUNCTION(hello_user)
                        {
                            char *username;
                            char *secondname;
                        
                            DebugBreak();
                        
                            if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &username, &secondname) == FAILURE) {
                                RETURN_NULL();
                            }
                        
                            php_printf("Hallo %s %s!", username, secondname);   
                        
                            RETURN_TRUE;
                        }
                        gedacht.
                        Ist PHP als Modul im IIS installiert oder wird es vom IIS per CGI aufgerufen?

                        Kommentar


                        • #13
                          So hatte ich es bereits, dann bekam ich die freundliche Mitteilung, es würde einen nicht abgefangenen Exception Code geben (PHP has encountered an Unhandled Exception Code -2147483645 at 77357DFE).
                          Aus dem Grund hab ich dann versucht es mit try/catch abzufangen, da jedoch wurde nichts abgefangen sondern einfach weiter der Fehler ausgegeben. Also als würde der try/catch Block nicht greifen.

                          Interessant ist, dass dieses Verhalten scheinbar nur im Zusammengang IIS und PHP auftritt. Eine wahre Lösung konnte ich bis heute nicht finden, weil sie scheinbar keiner kennt.

                          PHP ist im IIS per isapi eingebunden.


                          Bis denne, Han Solo

                          Kommentar


                          • #14
                            Zitat von Han Solo Beitrag anzeigen
                            So hatte ich es bereits, dann bekam ich die freundliche Mitteilung, es würde einen nicht abgefangenen Exception Code geben (PHP has encountered an Unhandled Exception Code -2147483645 at 77357DFE).
                            Das passiert auf dem Computer mit Visual Studio?
                            Welche Wahlmöglichkeiten hast Du im Dialog, der diese Meldung anzeigt?

                            Kommentar


                            • #15
                              Jap, genau das passiert auf dem Rechner mit Visual Studio C++ 2005 Express Edition.
                              Es kommt kein Dialog, es ist eine Fehlermeldung, die als Text auf der Webseite ausgegeben wird, die als Testseite dient um die Funktionsaufrufe der neuen Extension zu simulieren.


                              Bis denne, Han Solo

                              Kommentar

                              Lädt...
                              X