tutorials.de Buch-Aktion 05/2012
ERLEDIGT
NEIN
ANTWORTEN
6
ZUGRIFFE
992
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    JeyB JeyB ist offline Mitglied Silber
    Registriert seit
    Jul 2007
    Beiträge
    63
    Hallo,

    ich möchte eine Instanz in PHP von einer DLL erstellen, welche in C# geschrieben wurde und mit dem .Net Framework 4.0 kompiliert wurde. PHP findet allerdings die zu ladende dll, welche sich im globalen Assembly Cache (neuerdings unter dem Microsoft.Net Verzeichnis) befindet, nicht:

    Failed to instantiate .Net object [CreateInstance] [0x80070002] Das System kann die angegebene Datei nicht finden.
    Ich vermute, dass PHP nur in dem globalen Assembly Cache unter dem "Windows\assembly" Verzeichnis nach der DLL schaut, nicht aber unter dem neuen Verzeichnis. Diese Vermutung hat sich bei mir verstärkt, da das Erstellen einer Instanz funktioniert hatte, sofern die DLL im globalen Assembly Cache unter Windows registriert war. Hat jemand eine Idee ob die DOTNET Klasse von PHP auch bei Assemblies, welche mit .Net Framework 4.0 kompiliert wurden, verwendet werden können? Oder gibt es eine Möglichkeit die .Net 4.0 DLL mittels gacutil 4.0 in den alten globalen assembly cache zu registrieren? Mein Aufruf sieht folgendermaßen aus:

    PHP-Code:
    $lFullAssemblyName "Assembly Name, Version=x.x.x.x, Culture=neutral, ".
    "PublicKeyToken=xxxxxxxxxxxxxxxx, processorArchitecture=MSIL";
    $lFullClassName "Namespace.Classname";

    try
    {
            
    $lDotNet = new DOTNET($lFullAssemblyName$lFullClassName);
    }
    catch(
    Exception $lEx)
    {
            die(
    "Error occurred:<br>".$lEx->getMessage());

    Zur Erinnerung: Der Aufruf funktioniert bei Assemblies, die im alten globalen Assembly Cache installiert sind (windows\assembly). Die Abhängigkeiten der DLL wurden auch alle gefunden (überprüft mit dem Dependency Walker). Außerdem würde das Fehlen einer Abhängigkeit explizit in der Fehlermeldung erscheinen.

    Gruß, JeyB
    Geändert von JeyB (02.12.10 um 17:25 Uhr)
     

  2. #2
    Avatar von Flex
    Flex Flex ist offline (aka Felix Jacobi)
    tutorials.de Moderator
    Registriert seit
    Nov 2001
    Ort
    Wuppertal
    Beiträge
    5.295
    Blog-Einträge
    65
    Soweit ich das einsehen kann, ruft die Klasse grundsätzlich nur DLLs aus dem GAC auf...

    I can't explain the whole process as I'm not even sure. But as far as I know, in order to get PHP's DOTNET() to work with it, the dll must be registered in the GAC (see: en.wikipedia.org/wiki/Global_Assembly_Cache). Before that though, within the dll, you must jump through the required hoops to get your dll classes and methods to be COM visible (see: msdn.microsoft.com/en-us/library/zsfww439.aspx). Since you have the source, you can clean it up, set it up for COM usage, recompile, then register in the GAC where DOTNET() can find and use it.
    Quelle
     
    KIDS Kinderbetreuungsdienst
    Xing

    "When you play the game of thrones, you win or you die. There is no middle ground."
    by Cersei Lannister in "A Game Of Thrones"

  3. #3
    JeyB JeyB ist offline Mitglied Silber
    Registriert seit
    Jul 2007
    Beiträge
    63
    Das habe ich auch befürchtet. Gibt es aber keine andere Möglichkeit die .Net 4.0 DLL aus der PHP DotNet Klasse heraus zu verwenden oder diese in den alten GAC zu registrieren?

    Vielen Dank für jede weitere Antwort.

    Gruß, JeyB
     

  4. #4
    Avatar von Flex
    Flex Flex ist offline (aka Felix Jacobi)
    tutorials.de Moderator
    Registriert seit
    Nov 2001
    Ort
    Wuppertal
    Beiträge
    5.295
    Blog-Einträge
    65
    Ich habe den Beitrag mal ins .NET Forum verschoben, weil ich vermute dass hier die Leute mit mehr Ahnung sitzen und nicht den PHP Bereich checken
     
    KIDS Kinderbetreuungsdienst
    Xing

    "When you play the game of thrones, you win or you die. There is no middle ground."
    by Cersei Lannister in "A Game Of Thrones"

  5. #5
    JeyB JeyB ist offline Mitglied Silber
    Registriert seit
    Jul 2007
    Beiträge
    63
    Also ich habe Änderungen in der com_dotnet.c Datei vorgenommen.
    Statt die Assembly direkt vom GAC zu laden (mittels CreateInstance) habe ich die Funktion CreateInstanceFrom verwendet. Danach habe ich PHP 5.3.3 nts (not thread safe) kompiliert und getestet. Ich kann jetzt direkt statt den vollständigen Assemblynamen, den Pfad der DLL angeben und es wird eine Instanz der angegebenen Klasse erstellt. Mein Aufruf sieht jetzt folgendermaßen aus:

    PHP-Code:
    $lAssemblyPath "C:\\bin\\Assembly.dll";
    $lFullClassName "Namespace.Classname";

    try
    {
            
    $lDotNet = new DOTNET($lAssemblyPath$lFullClassName);
    }
    catch(
    Exception $lEx)
    {
            die(
    "Error occurred:<br>".$lEx->getMessage());

    Nachteile:
    -Es dauert etwas länger bis die Assembly geladen wurde (laden aus dem GAC ist schneller)
    -Ich kann nur eine Instanz von einer Assembly Klasse, welche mit .Net Framework < 4.0 kompiliert wurde, erzeugen.

    Der Fehler, dass er die Assembly nicht findet, erscheint nicht mehr, dafür aber dieser Fehler:
    Failed to instantiate .Net object [CreateInstance] [0x8013101b]
    Anscheinend kann ich keine Instanz einer Klasse erzeugen, die mit .Net 4.0 kompiliert wurde.
    Hat noch jemand eine Idee? Lasst euch nicht von dem [CreateInstance] verwirren. Das steht nur da drin, weil dieser Wert zuvor in einer Variablen gespeichert wurde. Ich verwende also wirklich die Funktion CreateInstanceFrom.

    Gruß, JeyB
    Geändert von JeyB (03.12.10 um 13:24 Uhr)
     

  6. #6
    Avatar von Shakie
    Shakie Shakie ist offline Mitglied Diamant
    Registriert seit
    May 2004
    Ort
    Europa
    Beiträge
    2.048
    Habe noch nie was mit PHP gemacht. Den einzigen Satz, den ich verstehe, ist der über die COM-Sichtbarkeit. Besitzt du den Quellcode der Assembly bzw. wurde sie als COM-Sichtbar kompiliert? Das ist in VisualStudio nämlich standardmäßig deaktiviert.
     

  7. #7
    JeyB JeyB ist offline Mitglied Silber
    Registriert seit
    Jul 2007
    Beiträge
    63
    Habe die Assembly COM-Sichtbar kompiliert. Es funktioniert ja, sofern ich für die Assembly .Net Framework < 4.0 verwende. Habe nun in der com_dotnet.c Datei gesehen, das die Schnittstelle von System.AppDomain für die Instanziierung einer .Net Klasse verwendet wird. Zum laden wird die GUID angegeben. Mittels oleview konnte ich die GUID der Schnittstelle, welche in der mscorlib.dll definiert ist, herausfinden und habe diese GUID von .Net 2.0 durch die von .Net 4.0 ersetzt.

    PHP-Code:
    // .Net 2.0 GUID der Schnittstelle System.AppDomain
    //const GUID IID_mscorlib_System_AppDomain = {
    //0x05F696DC, 0x2B29, 0x3663, {0xAD, 0x8B, 0xC4, 0x38, 0x9C, 0xF2, 0xA7, 0x13 }};

    // .Net 4.0 GUID der Schnittstelle System.AppDomain
    const GUID IID_mscorlib_System_AppDomain = {
    0x5FE0A1450xA82B0x3D96, {0x940xE30xFD0x210x4C0x9D0x6E0xB9 }}; 
    Nun erhalte ich folgenden Fehler:

    Failed to init .Net runtime [QI: System._AppDomain] Schnittstelle nicht unterstützt
    D.h. er scheitert beim Aufruf der Funktion "IUnknown_QueryInterface".

    PHP-Code:
    static HRESULT dotnet_init(char **p_where TSRMLS_DC)
    {
        
    HRESULT hr;
        
    struct dotnet_runtime_stuff *stuff;
        
    IUnknown *unk NULL;
        
    char *where "";

        
    stuff malloc(sizeof(*stuff));
        
    memset(stuff0sizeof(*stuff));

        
    where "CoCreateInstance";
        
    hr CoCreateInstance(&CLSID_CorRuntimeHostNULLCLSCTX_ALL,
                &
    IID_ICorRuntimeHost, (LPVOID*)&stuff->dotnet_host);

        if (
    FAILED(hr))
            goto 
    out;

        
    /* fire up the host and get the domain object */
        
    where "ICorRuntimeHost_Start\n";
        
    hr ICorRuntimeHost_Start(stuff->dotnet_host);
        if (
    FAILED(hr))
            goto 
    out;
        
        
    where "ICorRuntimeHost_GetDefaultDomain";
        
    hr ICorRuntimeHost_GetDefaultDomain(stuff->dotnet_host, &unk);
        if (
    FAILED(hr))
            goto 
    out;

        
    where "QI: System._AppDomain";
            
    // Dieser Aufruf verläuft nicht positiv
        
    hr IUnknown_QueryInterface(unk, &IID_mscorlib_System_AppDomain, (LPVOID*)&stuff->dotnet_domain);
        if (
    FAILED(hr))
            goto 
    out;
            
        
    COMG(dotnet_runtime_stuff) = stuff;

    out:
        if (
    unk) {
            
    IUnknown_Release(unk);
        }
        if (
    COMG(dotnet_runtime_stuff) == NULL) {
            
    /* clean up */
            
    if (stuff->dotnet_domain) {
                
    IUnknown_Release(stuff->dotnet_domain);
            }
            if (
    stuff->dotnet_host) {
                
    ICorRuntimeHost_Stop(stuff->dotnet_host);
                
    ICorRuntimeHost_Release(stuff->dotnet_host);
            }
            
    free(stuff);

            *
    p_where where;

            return 
    hr;
        }

        return 
    S_OK;

    Im Anhang befindet sich die vollständige com_dotnet.c Datei.
    Habe auch nachgeschaut ob in anderen Dateien eine Verwendung einer .Net 2.0 Assembly gemacht wird , konnte aber dies bezüglich nichts finden. Hat sonst noch jemand eine Idee? Bin für jede weitere Antwort dankbar.

    Gruß, JeyB
    Angehängte Dateien Angehängte Dateien
     

Ähnliche Themen

  1. DotNet in PHP
    Von JeyB im Forum PHP
    Antworten: 26
    Letzter Beitrag: 16.12.10, 19:32
  2. Windows Messages in DOTNet
    Von MarioR im Forum .NET Windows Forms
    Antworten: 0
    Letzter Beitrag: 29.09.09, 10:32
  3. dotNet und Soap Problem
    Von The Nephilim im Forum .NET Web und Kommunikation
    Antworten: 0
    Letzter Beitrag: 23.10.06, 16:28
  4. Antworten: 5
    Letzter Beitrag: 12.06.06, 07:28
  5. myodbc & dotNET Performance-/Stabilitätsprobleme
    Von C-H im Forum Relationale Datenbanksysteme
    Antworten: 1
    Letzter Beitrag: 10.06.05, 11:36