functionality for sc query and queryex
supports sc query <service>
         sc query type= <...>
         sc query state <...>
output as per MS utility
added usage information for query functionality
Modified: trunk/reactos/subsys/system/sc/query.c
Modified: trunk/reactos/subsys/system/sc/usage.c

Modified: trunk/reactos/subsys/system/sc/query.c
--- trunk/reactos/subsys/system/sc/query.c	2005-11-11 16:18:46 UTC (rev 19132)
+++ trunk/reactos/subsys/system/sc/query.c	2005-11-11 17:28:13 UTC (rev 19133)
@@ -8,27 +8,32 @@
  *           Ged Murphy 20/10/05 Created
  *
  */
+/*
+ * TODO:
+ * Allow calling of 2 options e.g.:
+ *    type= driver state= inactive
+ */
 
 #include "sc.h"
 
 /* local function decs */
 VOID PrintService(BOOL bExtended);
-BOOL EnumServices(DWORD ServiceType, DWORD ServiceState);
+BOOL EnumServices(LPCTSTR ServiceName, DWORD ServiceType, DWORD ServiceState);
+BOOL QueryService(LPCTSTR ServiceName, BOOL bExtended);
 
 /* global variables */
 static ENUM_SERVICE_STATUS_PROCESS *pServiceStatus = NULL;
+DWORD NumServices = 0;
 
 
-BOOL Query(LPCTSTR ServiceName, LPCTSTR *ServiceArgs, BOOL bExtended)
+BOOL
+Query(LPCTSTR ServiceName, LPCTSTR *ServiceArgs, BOOL bExtended)
 {
             
-    if (! ServiceName)
+    if (! ServiceName) /* display all running services and drivers */
     {
-        /* display all running services and drivers */
-        _tprintf(_T("No service name, displaying all services\n")); // test
-
         /* get default values */
-        EnumServices(SERVICE_WIN32, SERVICE_ACTIVE);
+        EnumServices(NULL, SERVICE_WIN32, SERVICE_ACTIVE);
         
         /* print default values */
         PrintService(bExtended);
@@ -37,13 +42,12 @@
     {
         LPCTSTR Type = *ServiceArgs;
         
-        _tprintf(_T("got type\narg = %s\n"), Type); // test
         if (_tcsicmp(Type, _T("driver")) == 0)
-            EnumServices(SERVICE_DRIVER, SERVICE_STATE_ALL);
+            EnumServices(NULL, SERVICE_DRIVER, SERVICE_ACTIVE);
         else if (_tcsicmp(Type, _T("service")) == 0)
-            EnumServices(SERVICE_WIN32, SERVICE_STATE_ALL);
+            EnumServices(NULL, SERVICE_WIN32, SERVICE_ACTIVE);
         else if (_tcsicmp(Type, _T("all")) == 0)
-            EnumServices(SERVICE_DRIVER|SERVICE_WIN32, SERVICE_STATE_ALL);
+            EnumServices(NULL, SERVICE_DRIVER|SERVICE_WIN32, SERVICE_ACTIVE);
         else
         {
             _tprintf(_T("\nERROR following \"type=\"!\n"));
@@ -56,12 +60,10 @@
     {
         LPCTSTR State = *ServiceArgs;
 
-        if (_tcsicmp(State, _T("active")) == 0)
-            EnumServices(SERVICE_DRIVER|SERVICE_WIN32, SERVICE_ACTIVE);
-        else if (_tcsicmp(State, _T("inactive")) == 0)
-            EnumServices(SERVICE_DRIVER|SERVICE_WIN32, SERVICE_INACTIVE);
+        if (_tcsicmp(State, _T("inactive")) == 0)
+            EnumServices(NULL, SERVICE_WIN32, SERVICE_INACTIVE);
         else if (_tcsicmp(State, _T("all")) == 0)
-            EnumServices(SERVICE_DRIVER|SERVICE_WIN32, SERVICE_STATE_ALL);
+            EnumServices(NULL, SERVICE_WIN32, SERVICE_STATE_ALL);
         else
         {
             _tprintf(_T("\nERROR following \"state=\"!\n"));
@@ -77,35 +79,138 @@
 
     else if(_tcsicmp(ServiceName, _T("group=")))
 */
-    else
+    else /* print only the service requested */
     {
-        /* print only the service requested */
-        printf("Service name %s\n", ServiceName); // test
+        QueryService(ServiceName, bExtended);
+    }
+    
+    return TRUE;
+}
 
-        /* get default values */
-        EnumServices(SERVICE_WIN32, SERVICE_ACTIVE);
 
-        /* print default values */
-        PrintService(bExtended);
+BOOL
+QueryService(LPCTSTR ServiceName, BOOL bExtended)
+{
+    SERVICE_STATUS_PROCESS *pServiceInfo = NULL;
+    SC_HANDLE hSc;
+    DWORD BufSiz = 0;
+    DWORD BytesNeeded = 0;
+    DWORD Ret;
+
+    hSc = OpenService(hSCManager, ServiceName, SERVICE_QUERY_STATUS);
+
+    if (hSc == NULL)
+    {
+        _tprintf(_T("QueryService: openService failed\n"));
+        ReportLastError();
+        return FALSE;
     }
+
+    Ret = QueryServiceStatusEx(hSc,
+                SC_STATUS_PROCESS_INFO,
+                NULL,
+                BufSiz,
+                &BytesNeeded);
+
+    if ((Ret != 0) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
+    {
+        _tprintf(_T("QueryService: First call to QueryServiceStatusEx failed : "));
+        ReportLastError();
+        return FALSE;
+    }
+    else /* Call function again if required size was returned */
+    {
+        /* reserve memory for service info array */
+        pServiceInfo = (SERVICE_STATUS_PROCESS *)
+            HeapAlloc(GetProcessHeap(), 0, BytesNeeded);
+        if (pServiceInfo == NULL)
+        {
+            _tprintf(_T("QueryService: Failed to allocate memory : "));
+            ReportLastError();
+            return FALSE;
+        }
+
+        /* fill array with service info */
+        if (! QueryServiceStatusEx(hSc,
+                    SC_STATUS_PROCESS_INFO,
+                    (LPBYTE)pServiceInfo,
+                    BytesNeeded,
+                    &BytesNeeded))
+        {
+            _tprintf(_T("QueryService: Second call to QueryServiceStatusEx failed : "));
+            ReportLastError();
+            HeapFree(GetProcessHeap(), 0, pServiceInfo);
+            return FALSE;
+        }
+    }
+
     
+    _tprintf(_T("SERVICE_NAME: %s\n"), ServiceName);
+
+    _tprintf(_T("\tTYPE               : %x  "),
+         (unsigned int)pServiceInfo->dwServiceType);
+    switch (pServiceInfo->dwServiceType)
+    {
+        case 1 : _tprintf(_T("KERNEL_DRIVER\n")); break;
+        case 2 : _tprintf(_T("FILE_SYSTEM_DRIVER\n")); break;
+        case 16 : _tprintf(_T("WIN32_OWN_PROCESS\n")); break;
+        case 32 : _tprintf(_T("WIN32_SHARE_PROCESS\n")); break;
+        default : _tprintf(_T("\n")); break;
+    }
+
+    _tprintf(_T("\tSTATE              : %x  "),
+        (unsigned int)pServiceInfo->dwCurrentState);
+
+    switch (pServiceInfo->dwCurrentState)
+    {
+        case 1 : _tprintf(_T("STOPPED\n")); break;
+        case 2 : _tprintf(_T("START_PENDING\n")); break;
+        case 3 : _tprintf(_T("STOP_PENDING\n")); break;
+        case 4 : _tprintf(_T("RUNNING\n")); break;
+        case 5 : _tprintf(_T("CONTINUE_PENDING\n")); break;
+        case 6 : _tprintf(_T("PAUSE_PENDING\n")); break;
+        case 7 : _tprintf(_T("PAUSED\n")); break;
+        default : _tprintf(_T("\n")); break;
+    }
+
+//        _tprintf(_T("\n\taccepted         : 0x%x\n\n"),
+//            pServiceStatus[i].ServiceStatusProcess.dwControlsAccepted);
+//            (STOPPABLE,NOT_PAUSABLE,ACCEPTS_SHUTDOWN)
+
+    _tprintf(_T("\tWIN32_EXIT_CODE    : %d  (0x%x)\n"),
+        (unsigned int)pServiceInfo->dwWin32ExitCode,
+        (unsigned int)pServiceInfo->dwWin32ExitCode);
+    _tprintf(_T("\tSERVICE_EXIT_CODE  : %d  (0x%x)\n"),
+        (unsigned int)pServiceInfo->dwServiceSpecificExitCode,
+        (unsigned int)pServiceInfo->dwServiceSpecificExitCode);
+    _tprintf(_T("\tCHECKPOINT         : 0x%x\n"),
+        (unsigned int)pServiceInfo->dwCheckPoint);
+    _tprintf(_T("\tWAIT_HINT          : 0x%x\n"),
+        (unsigned int)pServiceInfo->dwWaitHint);
+    if (bExtended)
+    {
+        _tprintf(_T("\tPID                : %lu\n"),
+            pServiceInfo->dwProcessId);
+        _tprintf(_T("\tFLAGS              : %lu\n"),
+            pServiceInfo->dwServiceFlags);
+    }
+    
+    HeapFree(GetProcessHeap(), 0, pServiceInfo);
+
     return TRUE;
-
 }
 
 
-BOOL EnumServices(DWORD ServiceType, DWORD ServiceState)
+BOOL
+EnumServices(LPCTSTR ServiceName, DWORD ServiceType, DWORD ServiceState)
 {
-    //SC_HANDLE hSc;
     DWORD BufSize = 0;
     DWORD BytesNeeded = 0;
-    DWORD NumServices = 0;
     DWORD ResumeHandle = 0;
-    
-//    hSc = OpenService(hSCManager, ServiceName, SERVICE_QUERY_STATUS);
+    DWORD Ret;
 
     /* determine required buffer size */
-    if (! EnumServicesStatusEx(hSCManager,
+    Ret = EnumServicesStatusEx(hSCManager,
                 SC_ENUM_PROCESS_INFO,
                 ServiceType,
                 ServiceState,
@@ -114,39 +219,45 @@
                 &BytesNeeded,
                 &NumServices,
                 &ResumeHandle,
-                0))
+                0);
+
+    if ((Ret != 0) && (GetLastError() != ERROR_MORE_DATA))
     {
-        /* Call function again if required size was returned */
-        if (GetLastError() == ERROR_MORE_DATA)
+        _tprintf(_T("EnumServices: First call to EnumServicesStatusEx failed : "));
+        ReportLastError();
+        return FALSE;
+    }
+    else /* Call function again if required size was returned */
+    {
+        /* reserve memory for service info array */
+        pServiceStatus = (ENUM_SERVICE_STATUS_PROCESS *)
+                HeapAlloc(GetProcessHeap(), 0, BytesNeeded);
+        if (pServiceStatus == NULL)
         {
-            /* reserve memory for service info array */
-            pServiceStatus = (ENUM_SERVICE_STATUS_PROCESS *) malloc(BytesNeeded);
+            _tprintf(_T("EnumServices: Failed to allocate memory : "));
+            ReportLastError();
+            return FALSE;
+        }
 
-            /* fill array with service info */
-            if (! EnumServicesStatusEx(hSCManager,
-                        SC_ENUM_PROCESS_INFO,
-                        SERVICE_DRIVER | SERVICE_WIN32,
-                        SERVICE_STATE_ALL,
-                        (LPBYTE)pServiceStatus,
-                        BufSize,
-                        &BytesNeeded,
-                        &NumServices,
-                        &ResumeHandle,
-                        0))
-            {
-                _tprintf(_T("Second call to EnumServicesStatusEx failed : "));
-                ReportLastError();
-                return FALSE;
-            }
-        }
-        else /* exit on failure */
+        /* fill array with service info */
+        if (! EnumServicesStatusEx(hSCManager,
+                    SC_ENUM_PROCESS_INFO,
+                    ServiceType,
+                    ServiceState,
+                    (LPBYTE)pServiceStatus,
+                    BytesNeeded,
+                    &BytesNeeded,
+                    &NumServices,
+                    &ResumeHandle,
+                    0))
         {
-            _tprintf(_T("First call to EnumServicesStatusEx failed : "));
+            _tprintf(_T("EnumServices: Second call to EnumServicesStatusEx failed : "));
             ReportLastError();
+            HeapFree(GetProcessHeap(), 0, pServiceStatus);
             return FALSE;
         }
     }
-    
+
     return TRUE;
 }
 
@@ -154,26 +265,64 @@
 VOID
 PrintService(BOOL bExtended)
 {
-    _tprintf(_T("SERVICE_NAME: %s\n"), pServiceStatus->lpServiceName);
-    _tprintf(_T("DISPLAY_NAME: %s\n"), pServiceStatus->lpDisplayName);
-    _tprintf(_T("TYPE               : %lu\n"),
-        pServiceStatus->ServiceStatusProcess.dwServiceType);
-    _tprintf(_T("STATE              : %lu\n"),
-        pServiceStatus->ServiceStatusProcess.dwCurrentState);
-                        //    (STOPPABLE,NOT_PAUSABLE,ACCEPTS_SHUTDOWN)
-    _tprintf(_T("WIN32_EXIT_CODE    : %lu \n"),
-        pServiceStatus->ServiceStatusProcess.dwWin32ExitCode);
-    _tprintf(_T("SERVICE_EXIT_CODE  : %lu \n"),
-        pServiceStatus->ServiceStatusProcess.dwServiceSpecificExitCode);
-    _tprintf(_T("CHECKPOINT         : %lu\n"),
-        pServiceStatus->ServiceStatusProcess.dwCheckPoint);
-    _tprintf(_T("WAIT_HINT          : %lu\n"),
-        pServiceStatus->ServiceStatusProcess.dwWaitHint);
-    if (bExtended)
+    int i;
+    
+    for (i=0; i < NumServices; i++)
     {
-        _tprintf(_T("PID                : %lu\n"),
-            pServiceStatus->ServiceStatusProcess.dwProcessId);
-        _tprintf(_T("FLAGS              : %lu\n"),
-            pServiceStatus->ServiceStatusProcess.dwServiceFlags);
+
+        _tprintf(_T("SERVICE_NAME: %s\n"), pServiceStatus[i].lpServiceName);
+        _tprintf(_T("DISPLAY_NAME: %s\n"), pServiceStatus[i].lpDisplayName);
+
+        _tprintf(_T("\tTYPE               : %x  "),
+            (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwServiceType);
+        switch (pServiceStatus[i].ServiceStatusProcess.dwServiceType)
+        {
+            case 1 : _tprintf(_T("KERNEL_DRIVER\n")); break;
+            case 2 : _tprintf(_T("FILE_SYSTEM_DRIVER\n")); break;
+            case 16 : _tprintf(_T("WIN32_OWN_PROCESS\n")); break;
+            case 32 : _tprintf(_T("WIN32_SHARE_PROCESS\n")); break;
+            default : _tprintf(_T("\n")); break;
+        }
+
+        _tprintf(_T("\tSTATE              : %x  "),
+            (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwCurrentState);
+
+        switch (pServiceStatus[i].ServiceStatusProcess.dwCurrentState)
+        {
+            case 1 : _tprintf(_T("STOPPED\n")); break;
+            case 2 : _tprintf(_T("START_PENDING\n")); break;
+            case 3 : _tprintf(_T("STOP_PENDING\n")); break;
+            case 4 : _tprintf(_T("RUNNING\n")); break;
+            case 5 : _tprintf(_T("CONTINUE_PENDING\n")); break;
+            case 6 : _tprintf(_T("PAUSE_PENDING\n")); break;
+            case 7 : _tprintf(_T("PAUSED\n")); break;
+            default : _tprintf(_T("\n")); break;
+        }
+
+    //        _tprintf(_T("\n\taccepted         : 0x%x\n\n"),
+    //            pServiceStatus[i].ServiceStatusProcess.dwControlsAccepted);
+    //            (STOPPABLE,NOT_PAUSABLE,ACCEPTS_SHUTDOWN)
+
+        _tprintf(_T("\tWIN32_EXIT_CODE    : %d  (0x%x)\n"),
+            (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwWin32ExitCode,
+            (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwWin32ExitCode);
+        _tprintf(_T("\tSERVICE_EXIT_CODE  : %d  (0x%x)\n"),
+            (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwServiceSpecificExitCode,
+            (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwServiceSpecificExitCode);
+        _tprintf(_T("\tCHECKPOINT         : 0x%x\n"),
+            (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwCheckPoint);
+        _tprintf(_T("\tWAIT_HINT          : 0x%x\n"),
+            (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwWaitHint);
+        if (bExtended)
+        {
+            _tprintf(_T("\tPID                : %lu\n"),
+                pServiceStatus[i].ServiceStatusProcess.dwProcessId);
+            _tprintf(_T("\tFLAGS              : %lu\n"),
+                pServiceStatus[i].ServiceStatusProcess.dwServiceFlags);
+        }
+
+            _tprintf(_T("\n"));
     }
+    
+    _tprintf(_T("number : %lu\n"), NumServices);
 }

Modified: trunk/reactos/subsys/system/sc/usage.c
--- trunk/reactos/subsys/system/sc/usage.c	2005-11-11 16:18:46 UTC (rev 19132)
+++ trunk/reactos/subsys/system/sc/usage.c	2005-11-11 17:28:13 UTC (rev 19133)
@@ -8,11 +8,13 @@
  *           Ged Murphy 20/10/05 Created
  *
  */
-
+#include <conio.h>
 #include "sc.h"
 
 INT MainUsage(VOID)
 {
+    TCHAR c;
+
     _tprintf(_T("DESCRIPTION:\n")
     _T("\tSC is a command line program used for communicating with\n")
     _T("\tthe Service Control Manager and its services.\n")
@@ -52,6 +54,43 @@
 //    "\t  Lock           : Locks the SCM Database\n")
 //    "\t  QueryLock      : Queries the LockStatus for the SCM Database\n")
 
+    _tprintf(_T("\nWould you like to see help for the QUERY and QUERYEX commands? [ y | n ]: "));
+    c = _getch(); // _gettch isn't defined in our tchar.h
+    _tprintf(_T("%c\n"), c);
+    if (tolower(c) == 'y')
+    {
+        _tprintf(_T("QUERY and QUERYEX OPTIONS :\n")
+        _T("        If the query command is followed by a service name, the status\n")
+        _T("        for that service is returned.  Further options do not apply in\n")
+        _T("        this case.  If the query command is followed by nothing or one of\n")
+        _T("        the options listed below, the services are enumerated.\n")
+        _T("    type=    Type of services to enumerate (driver, service, all)\n")
+        _T("             (default = service)\n")
+        _T("    state=   State of services to enumerate (inactive, all)\n")
+        _T("             (default = active)\n")
+/*
+        _T("    bufsize= The size (in bytes) of the enumeration buffer\n")
+        _T("             (default = 4096)\n")
+        _T("    ri=      The resume index number at which to begin the enumeration\n")
+        _T("             (default = 0)\n")
+        _T("    group=   Service group to enumerate\n")
+        _T("             (default = all groups)\n")
+*/
+        _T("SYNTAX EXAMPLES\n")
+        _T("sc query                - Enumerates status for active services & drivers\n")
+        _T("sc query messenger      - Displays status for the messenger service\n")
+        _T("sc queryex messenger    - Displays extended status for the messenger service\n")
+        _T("sc query type= driver   - Enumerates only active drivers\n")
+        _T("sc query type= service  - Enumerates only Win32 services\n")
+        _T("sc query state= all     - Enumerates all services & drivers\n")
+//        _T("sc query bufsize= 50    - Enumerates with a 50 byte buffer.\n")
+//        _T("sc query ri= 14         - Enumerates with resume index = 14\n")
+//        _T("sc queryex group= ""    - Enumerates active services not in a group\n")
+        _T("sc query type= service type= interact - Enumerates all interactive services\n"));
+//        _T("sc query type= driver group= NDIS     - Enumerates all NDIS drivers\n"));
+    }
+
+
     return 0;
 }