Win7: EnumServicesStatus liefert manchmal 0



  • Hallo

    Ich habe hier unter Win7 ein Problem beim Test, ob der Dnscache-Dienst
    läuft. Ich teste das mittels EnumServicesStatus.

    Starte ich das Programm normal (nicht als Admin) so funktioniert
    es immer tadellos.

    Starte ich es als Admin, so findet es "sporadisch" den Dienst
    nicht; obwohl er aktiv ist. Tritt das auf, fällt mir ansonsten
    nichts außergewöhnliches auf.

    Hat jemand eine Idee dazu ?

    P.S. Betreff geändert:

    Alter Betreff: Win7: EnumServicesStatus findet Dnscache-Dienst nicht immer



  • Ist das Problem so einzigartig, das niemand auch nur einen winzigen Hinweis hat?
    Das es also generell unter Win7 einen techn. Unterschied beim Anfragen
    per EnumServicesStatus und dem Auslesen der erhaltenen Daten bzgl. des Rechtestatus
    des Programms gibt? Und das dies evtl. auch andere Systemfunktionen betrifft?

    Oder weisst es ggf. auf ein Problem meiner Windows-Installation hin?

    Im Netz werde ich leider nicht fündig.

    Sicherheitshalber nochmal der besondere Punkt: Es funktioniert IMMER, wenn ich das
    Programm als Standarduser aufrufe. Starte ich es als admin, scheint es das Ergebnis
    zu erwürfeln.



  • Poste doch mal deinen Code, vielleicht kann es dann jemand nachvollziehen und dir weiterhelfen.



  • Hatte schon überlegt, den Code hier wiederzugeben. Scheint jedenfalls kein allzubekanntes
    Phänomen zu sein, zumal ich auch an diversen anderen Stellen gefragt hatte.

    Wichtige Ergänzung ! Ich erhalte, wenn das Problem auftritt, eine 0 von
    EnumServicesStatus. Sorry, für den kleinen Irrtum. Es geht also NICHT speziell
    um den DNS-Cachedienst.

    bool teste_ob_dienst_laeuft(LPSTR dienstname)  // Aufruf mit "Dnscache"
    {
        SC_HANDLE SC_H;
        BOOL dienstearray_erhalten;
        DWORD array_groesse,
        Anzahl_gefundene_Dienste,
        start_in_array,
        zaehler;
    
        bool dienst_gefunden;
    
        LPSTR nameP;
    
        LPENUM_SERVICE_STATUS arraySP;
    
        SC_H = OpenSCManager(
                     NULL,
                     SERVICES_ACTIVE_DATABASE,
                     SC_MANAGER_ENUMERATE_SERVICE
                 );
    
        if (SC_H)
        {
            /* Das erste Mal aufrufen, um bewusst Fehler zu provozieren, indem ungültige
            Arraygrössen angegeben werden. Ich erhalte dann in "array_groesse" die nötige
            Anzahl Bytes für das Array.
            */
    
            start_in_array = 0;
    
            dienstearray_erhalten = EnumServicesStatus(
                                        SC_H,
                                        SERVICE_DRIVER | SERVICE_WIN32 | SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS,
                                        SERVICE_ACTIVE,
                                        NULL,  // Um Arraygrösse zu erhalten, hier NULL setzen !
                                        0,// Um Arraygrösse zu erhalten, hier 0 setzen !
                                        &array_groesse,
                                        &Anzahl_gefundene_Dienste,
                                        &start_in_array
                                    );
    
            if (dienstearray_erhalten == 0) // MUSS 0 sein, weil ich oben bewusst den Fehler provoziert habe
            {
                // Nun Speicher für Array anfordern
                if (!(arraySP = (LPENUM_SERVICE_STATUS)malloc(array_groesse)))
                {
                    MessageBox(NULL, "Allocate Memory failed", "Error !", MB_OK | MB_APPLMODAL);
                    CloseServiceHandle(SC_H);
                    return false;
                }
    
                start_in_array = 0;
                dienst_gefunden = false;
    
                // Das zweite Mal aufrufen, um das Array zu füllen.
                dienstearray_erhalten = EnumServicesStatus(
                                            SC_H,
                                            SERVICE_DRIVER | SERVICE_WIN32 | SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS,
                                            SERVICE_ACTIVE,
                                            arraySP,
                                            array_groesse,
                                            &array_groesse,// Siehe Bemerkung oben !
                                            &Anzahl_gefundene_Dienste,
                                            &start_in_array
                                        );
    
                if (dienstearray_erhalten == 0)
                {
                    MessageBox(NULL, "No Services found !", "Error", MB_OK | MB_APPLMODAL);
                }
                else
                {
                    for (zaehler = 0; zaehler != Anzahl_gefundene_Dienste; zaehler++)
                    {
                        nameP = arraySP[zaehler].lpServiceName;
    
                        if (strcmp((const char*)nameP, dienstname) == 0)
                        {
                            dienst_gefunden = true;
                            break;
                        }
                    } // Ende zaehler-schleife
    
                    free(arraySP);
    
                    CloseServiceHandle(SC_H);
                } // Ende if-else dienste-array erhalten ok
            } // Ende dienstearray_erhalten == 0  (Bewusst herbeigeführter "Fehler")
        } // Handle von OpenSCManager erfolgreich erhalten
    
        if (dienst_gefunden == false)
        {
            return false;
        }
    
        return true;
    
    } // Ende teste_ob_dienst_laeuft
    


  • Das hat alles nichts mit dem Problem zu tun, aber trotzdem:

    1. Der Parameter "dienstname" ändert sich nicht, also mache den const (LPCSTR anstelle von LPSTR)

    2. "dienst_gefunden" wird erst viel zu spät mit false initialisiert. Wenn OpenSCManager in die Hose geht, warum auch immer, ist Deine Abfrage in Zeile 96 absolut sinnfrei. Überhaupt: Warum gibst Du "dienst_gefunden" nicht gleich direkt an den Aufrufer zurück?

    3. Du ruft EnumServicesStatus zusammen mit SERVICE_DRIVER auf. Wozu das? Was passiert, wenn Du das weglässst?

    4. Wenn der zweite Aufruf von EnumServicesStatus in die Hose geht, warum auch immer, gibst Du den zuvor per malloc reservierten Speicher nicht mehr frei. Das musst Du dringend korrigieren!



  • Henry Albrecht schrieb:

    Ich erhalte, wenn das Problem auftritt, eine 0 von EnumServicesStatus.

    Zeile 33 oder Zeile 59? Was sagt GetLastError, wenn der Fehler auftritt?



  • Danke für die Tips. Die Änderungen (Freigabe bei Fehlschlag usw. baue ich ein).

    Den Fehler werde ich in Testläufen noch ermitteln. Aber interessant bleibt die Frage,
    warum ein- und dieselbe Funktion im Standardusermodus immer erfolgreich abläuft, und
    im admin-modus der Zufallseffekt auftritt.

    Ich werde die beiden Tips (Fehlercode holen und SERVICE_DRIVER weglassen) abarbeiten.
    Spätestens Sonntag komme ich dazu und werde dann berichten.



  • 1: Normalerweise packt man sowas in einen retry-loop. Also

    while (!erfolgreich)
    {
        grösse = nötige grösse ermitteln
        array = array erzeugen(grösse)
        erfolgreich = array füllen(array, grösse)
    }
    

    Und natürlich Fehlerhandling, also z.B. Abbruch wenn ein anderer Fehler als ERROR_INSUFFICIENT_BUFFER passiert.

    2: Du solltest beim "Grösse Ermitteln" mit GetLastError prüfen ob der Fehlercode eh wirklich ERROR_INSUFFICIENT_BUFFER ist.

    3: Du solltest überhaupt GetLastError verwenden - und wenn's nur ist damit du im Debugger den Wert nachgucken kannst. Bzw. ein TRACE ist auch sehr einfach eingebaut.

    4: Das Kommentar "Das erste Mal aufrufen, um bewusst Fehler zu provozieren" ist (für mich) sehr verwirrend. Ich würde das nie als Fehler bezeichnen. Mir ist schon klar dass der Returnwert dabei "FALSE" ist, aber ... du verwendest ein offizielles Feature der Funktion EnumServicesStatus . Ich dachte erst wirklich dass du dich irgendwie mit dem Parametern gespielt hast, um einen Weg zu finden den hier in diesem Thread beschriebenen Fehler zu provozieren.
    Das ist z.B. das selbe wie wenn ne asynchrone IO Funktion FALSE mit ERROR_IO_PENDING zurückliefert. Das ist auch kein Fehler, einfach nur ein Mechanismus um zu kommunizieren was passiert ist.

    5: Das free(arraySP); muss auch im "if" Zweig gemacht werden, nicht nur im "else" Zweig => besser gleich aus dem "if" raus und nach dem if/else machen.



  • hustbaer schrieb:

    4: Das Kommentar "Das erste Mal aufrufen, um bewusst Fehler zu provozieren" ist (für mich) sehr verwirrend. Ich würde das nie als Fehler bezeichnen. Mir ist schon klar dass

    Ja. Das hatte ich so für mich kommentiert und vergessen, es fürs Forum anzupassen. Ich fand die Umschreibung "bewusst Fehler provozieren" als am passendsten.

    Zum Ergebnis:

    Wenn EnumServicesStatus mit 0 zurückkehrt, erhalte ich per GetLastError den Code 126. Das ist:

    ERROR_MOD_NOT_FOUND
    The specified module could not be found.

    Ich kann mir da keinen Reim drauf machen, was das mit admin-modus ja/nein zu tun haben soll ..

    ==> Zu Mox: SERVICE_DRIVER habe ich testweise weggelassen: keine Änderung.

    Da diese Funktion universell einsetzbar sein soll, fordere ich alle Optionen an; und somit auch SERVICE_DRIVER.



  • Zwischenstand. Ich habe ein Testprogramm an Freunde verteilt. Auf manchen Maschinen tritt der Fehler nicht auf, auf anderen tritt er auf.
    Damit ist ausgeschlossen, das mein Windows "eine Macke" hat.

    Ich behelfe mir jetzt so, das ich die Funktion im Fehlerfalle das Array mehrfach anfordern lasse. Bislang reichten 2 Versuche um Erfolg zu haben.

    Momentan gehe ich davon aus, das es sich um einen Windows-Fehler handelt.


Log in to reply