mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
424 lines
15 KiB
424 lines
15 KiB
/*
|
|
NETSVC.C -- a sample program demonstrating NetService API functions.
|
|
|
|
This program requires that you have admin privilege on the specified
|
|
server.
|
|
|
|
usage: netsvc [-s \\server] [-v servicename] [-l level]
|
|
|
|
where: \\server = Name of the server. A servername must be preceded
|
|
by two backslashes (\\).
|
|
servicename = Name of the service.
|
|
level = Level of detail requested.
|
|
|
|
API Used to...
|
|
================= ================================================
|
|
NetServiceInstall Install the specified service
|
|
NetServiceControl Check progress of installation and uninstall the
|
|
specified service
|
|
NetServiceEnum List services and their status
|
|
NetServiceGetInfo Show one service and its status
|
|
|
|
This code sample is provided for demonstration purposes only.
|
|
Microsoft makes no warranty, either express or implied,
|
|
as to its usability in any given situation.
|
|
*/
|
|
|
|
#define NOSERVICE // Avoid <winsvc.h> vs. <lmsvc.h> conflicts.
|
|
|
|
#ifndef UNICODE
|
|
#define UNICODE // Net APIs all require this.
|
|
#endif
|
|
|
|
#include <windows.h> // MS Windows base header files, Sleep(), etc.
|
|
#include <lmcons.h> // LanMan constants, etc.
|
|
|
|
#include <lmapibuf.h> // NetApiBufferFree().
|
|
#include <lmerr.h> // NERR_, ERROR_, and NO_ERROR equates.
|
|
#include <lmsvc.h>
|
|
|
|
#include <samples.h> // SafeMalloc routines.
|
|
#include <stdio.h> // C run-time header files
|
|
#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, _CRTAPI1.
|
|
|
|
#define A_SERVICE SERVICE_TIMESOURCE // Default servicename
|
|
#define DEFAULT_WAITTIME 150 // 0.1 seconds; 150 = 1.5 sec
|
|
#define MAX_POLLS 5 // Max. checks (5*1.5 sec = 20 sec)
|
|
#define WAIT_MULT 10
|
|
|
|
void InstallService (LPTSTR pszServer, LPTSTR pszService);
|
|
void ShowServices (DWORD dwLevel, LPVOID lpArrayStart, DWORD dwCount);
|
|
void UninstallService (LPTSTR pszServer, LPTSTR pszService);
|
|
void Usage(char * pszString);
|
|
|
|
int _CRTAPI1
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
LPTSTR pszServer = TEXT(""); // Default to local machine
|
|
LPTSTR pszService = A_SERVICE; // Servicename
|
|
LPBYTE pbBuffer; // Buffer for return data
|
|
DWORD cEntriesRead; // Count of entries in buffer
|
|
DWORD cTotalEntries; // Count available
|
|
int iCount; // Arg index and loop counter
|
|
DWORD dwLevel = 0; // Level of detail
|
|
NET_API_STATUS apiRet; // API function return code
|
|
LPSERVICE_INFO_0 pSvc0; // Service info; level 0
|
|
LPSERVICE_INFO_1 pSvc1; // Service info; level 1
|
|
LPSERVICE_INFO_2 pSvc2; // Service info; level 2
|
|
|
|
for (iCount = 1; iCount < argc; iCount++)
|
|
{
|
|
if ((*argv[iCount] == '-') || (*argv[iCount] == '/'))
|
|
{
|
|
switch (tolower(*(argv[iCount]+1))) // Process switches
|
|
{
|
|
case 's': // -s servername
|
|
pszServer = SafeMallocWStrFromStr(argv[++iCount]);
|
|
break;
|
|
case 'v': // -v servicename
|
|
pszService = SafeMallocWStrFromStr(argv[++iCount]);
|
|
break;
|
|
case 'l': // -l level
|
|
dwLevel = (DWORD)(atoi(argv[++iCount]));
|
|
break;
|
|
default:
|
|
Usage(argv[0]);
|
|
}
|
|
}
|
|
else
|
|
Usage(argv[0]);
|
|
} // End for loop
|
|
|
|
//======================================================================
|
|
// NetServiceInstall and NetServiceControl
|
|
//
|
|
// This API installs a service. Reassure the user that installation is
|
|
// proceeding by using NetServiceControl.
|
|
//======================================================================
|
|
|
|
InstallService(pszServer, pszService);
|
|
|
|
//====================================================================
|
|
// NetServiceGetInfo
|
|
//
|
|
// This API gets the status for one service.
|
|
//====================================================================
|
|
|
|
apiRet = NetServiceGetInfo(pszServer, // Server name
|
|
pszService, // Service name
|
|
dwLevel, // Info level
|
|
& pbBuffer ); // Alloc buffer and set ptr
|
|
printf("NetServiceGetInfo returned %lu\n", apiRet);
|
|
if (apiRet == NERR_Success)
|
|
{
|
|
ShowServices( dwLevel, pbBuffer, 1 );
|
|
NetApiBufferFree(pbBuffer);
|
|
} // End if successful return
|
|
|
|
//====================================================================
|
|
// NetServiceEnum
|
|
//
|
|
// This API displays a list of installed services.
|
|
//====================================================================
|
|
|
|
apiRet = NetServiceEnum(pszServer, // Servername
|
|
dwLevel, // Info level
|
|
& pbBuffer, // Alloc buffer and set ptr
|
|
100, // Prefered max size (arbitrary)
|
|
&cEntriesRead, // Count of entries read
|
|
&cTotalEntries, // Count of entries available
|
|
NULL); // No resume handle
|
|
|
|
pSvc0 = (LPSERVICE_INFO_0) pbBuffer; // If dwLevel == 0
|
|
pSvc1 = (LPSERVICE_INFO_1) pbBuffer; // If dwLevel == 1
|
|
pSvc2 = (LPSERVICE_INFO_2) pbBuffer; // If dwLevel == 2
|
|
|
|
printf("NetServiceEnum returned %lu\n", apiRet);
|
|
if (apiRet == NERR_Success)
|
|
{
|
|
|
|
printf("Services installed");
|
|
if ((pszServer == NULL) || (*pszServer == '\0'))
|
|
printf(" on local server:\n");
|
|
else
|
|
printf(" on server %ws:\n", pszServer);
|
|
|
|
ShowServices( dwLevel, pbBuffer, cEntriesRead );
|
|
|
|
NetApiBufferFree(pbBuffer);
|
|
} // End if successful return
|
|
|
|
//====================================================================
|
|
// NetServiceControl
|
|
//
|
|
// This API uninstalls the service.
|
|
//====================================================================
|
|
|
|
UninstallService(pszServer, pszService);
|
|
return (EXIT_SUCCESS);
|
|
}
|
|
|
|
//====================================================================
|
|
// NetServiceInstall
|
|
//
|
|
// This API installs the service. Reassure the user that installation
|
|
// is proceeding by using NetServiceControl.
|
|
//====================================================================
|
|
|
|
void InstallService (LPTSTR pszServer, LPTSTR pszService)
|
|
{
|
|
DWORD dwTimeElapsed = 0;
|
|
DWORD dwOldCheck = 0;
|
|
DWORD dwNewCheck = 0;
|
|
DWORD dwWaitTime;
|
|
NET_API_STATUS apiRet;
|
|
LPSERVICE_INFO_2 lpStatBuf;
|
|
|
|
apiRet = NetServiceInstall(pszServer, // Servername
|
|
pszService, // Servicename
|
|
(DWORD) 0, // Zero command-line args
|
|
NULL, // No ptr to command-line args
|
|
(LPBYTE *) (LPVOID) &lpStatBuf); // Level 2 ret buff (alloc)
|
|
printf("NetServiceInstall %ws returned %lu\n", pszService, apiRet);
|
|
switch (apiRet)
|
|
{
|
|
case NERR_Success:
|
|
(void) NetApiBufferFree( lpStatBuf );
|
|
break;
|
|
/*
|
|
* NERR_BadServiceName and ERROR_FILE_NOT_FOUND can be caused
|
|
* by the absence of the service entry in the LANMAN.INI file
|
|
* or when the entry points to a directory that does not contain
|
|
* the executable service program.
|
|
*/
|
|
case NERR_BadServiceName:
|
|
case ERROR_FILE_NOT_FOUND:
|
|
printf("\n%ws could not be installed\n", pszService);
|
|
return;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
do // Poll every few seconds.
|
|
{
|
|
apiRet = NetServiceControl(pszServer, // Servername
|
|
pszService, // Servicename
|
|
SERVICE_CTRL_INTERROGATE, // Opcode
|
|
0, // Service-specific args
|
|
(LPBYTE *) (LPVOID) &lpStatBuf); // Alloc return buffer
|
|
|
|
switch (lpStatBuf->svci2_status & SERVICE_INSTALL_STATE)
|
|
{
|
|
case SERVICE_INSTALLED:
|
|
printf ("\n%ws successfully installed\n", pszService);
|
|
ShowServices (2, lpStatBuf, 1);
|
|
(void) NetApiBufferFree( lpStatBuf );
|
|
return;
|
|
|
|
case SERVICE_INSTALL_PENDING:
|
|
printf(".");
|
|
break;
|
|
|
|
default:
|
|
printf ("\nService %ws failed to install\n", pszService);
|
|
printf ("NetServiceControl returned status %ld\n",
|
|
(DWORD) (lpStatBuf->svci2_status & SERVICE_INSTALL_STATE));
|
|
ShowServices (2, lpStatBuf, 1);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Check the service timing hints. As long as the hints are being
|
|
* changed, assume that the service is still alive.
|
|
*/
|
|
if (lpStatBuf->svci2_code & SERVICE_CCP_QUERY_HINT)
|
|
{
|
|
dwNewCheck = (lpStatBuf->svci2_code & SERVICE_CCP_CHKPT_NUM);
|
|
if (dwNewCheck != dwOldCheck) // Hints are being changed
|
|
{
|
|
dwTimeElapsed = 0;
|
|
dwOldCheck = dwNewCheck;
|
|
}
|
|
}
|
|
|
|
// Get wait time from data structure.
|
|
|
|
dwWaitTime = WAIT_MULT * ( ( lpStatBuf->svci2_code
|
|
& SERVICE_IP_WAIT_TIME )
|
|
>> SERVICE_IP_WAITTIME_SHIFT);
|
|
|
|
// Provide a default wait time if the service doesn't give one.
|
|
|
|
if (dwWaitTime == 0)
|
|
dwWaitTime = DEFAULT_WAITTIME;
|
|
|
|
// If we've gone maximum amount of time without an update, fail.
|
|
|
|
if (dwTimeElapsed >= (DWORD) (MAX_POLLS * dwWaitTime))
|
|
{
|
|
printf("\n%ws failed to install. ", pszService);
|
|
printf("The service did not report an error.\n");
|
|
break;
|
|
}
|
|
/*
|
|
* Sleep() waits for the given number of milliseconds.
|
|
* It's well-behaved (allows other things to run).
|
|
*/
|
|
Sleep(dwWaitTime);
|
|
dwTimeElapsed++;
|
|
|
|
} while ((lpStatBuf->svci2_status & SERVICE_INSTALL_STATE)
|
|
== SERVICE_INSTALL_PENDING );
|
|
|
|
// Successful installation returns true from the switch statement.
|
|
(void) NetApiBufferFree( lpStatBuf );
|
|
return;
|
|
}
|
|
|
|
//====================================================================
|
|
// ShowServices
|
|
//
|
|
// This routine displays one or more service structures.
|
|
//====================================================================
|
|
|
|
void ShowServices (DWORD dwLevel, LPVOID lpArrayStart, DWORD dwCount)
|
|
{
|
|
DWORD dwEntryNum;
|
|
LPSERVICE_INFO_0 pSvc0; // Service info; level 0
|
|
LPSERVICE_INFO_1 pSvc1; // Service info; level 1
|
|
LPSERVICE_INFO_2 pSvc2; // Service info; level 2
|
|
|
|
pSvc0 = (LPSERVICE_INFO_0) lpArrayStart; // If dwLevel == 0
|
|
pSvc1 = (LPSERVICE_INFO_1) lpArrayStart; // If dwLevel == 1
|
|
pSvc2 = (LPSERVICE_INFO_2) lpArrayStart; // If dwLevel == 2
|
|
|
|
for (dwEntryNum = 0; dwEntryNum < dwCount; dwEntryNum++)
|
|
{
|
|
switch (dwLevel)
|
|
{
|
|
case 0:
|
|
printf(" %ws\n", pSvc0->svci0_name);
|
|
pSvc0++;
|
|
break;
|
|
case 1:
|
|
printf("Service: %ws\n", pSvc1->svci1_name);
|
|
printf(" Status : 0x%lX\n", pSvc1->svci1_status);
|
|
printf(" Code : 0x%lX\n", pSvc1->svci1_code);
|
|
pSvc1++;
|
|
break;
|
|
case 2:
|
|
printf("Service: %ws\n", pSvc2->svci2_name);
|
|
printf(" Status : 0x%lX\n", pSvc2->svci2_status);
|
|
printf(" Code : 0x%lX\n", pSvc2->svci2_code);
|
|
printf(" Text : %ws\n", pSvc2->svci2_text);
|
|
printf(" SpecErr: 0x%lX\n", pSvc2->svci2_specific_error);
|
|
printf(" DispNam: %ws\n", pSvc2->svci2_display_name);
|
|
pSvc2++;
|
|
break;
|
|
default:
|
|
break;
|
|
} // End switch
|
|
} // End for loop
|
|
|
|
}
|
|
|
|
//====================================================================
|
|
// NetServiceControl
|
|
//
|
|
// This API uninstalls the service.
|
|
//====================================================================
|
|
|
|
void UninstallService (LPTSTR pszServer, LPTSTR pszService)
|
|
{
|
|
DWORD dwElapsedTime = 0;
|
|
NET_API_STATUS apiRet;
|
|
DWORD dwWaitTime;
|
|
LPSERVICE_INFO_2 lpStatBuf;
|
|
|
|
apiRet = NetServiceControl (pszServer, // Servername
|
|
pszService, // Servicename
|
|
SERVICE_CTRL_UNINSTALL, // Opcode
|
|
0, // Service-specific args
|
|
(LPBYTE *) (LPVOID) &lpStatBuf); // Alloc return buffer
|
|
printf("NetServiceControl(stop) %ws returned %lu\n", pszService, apiRet);
|
|
if (apiRet == NERR_Success) {
|
|
ShowServices (2, lpStatBuf, 1);
|
|
NetApiBufferFree(lpStatBuf);
|
|
}
|
|
|
|
do // Poll every few seconds.
|
|
{
|
|
apiRet = NetServiceControl(pszServer,
|
|
pszService,
|
|
SERVICE_CTRL_INTERROGATE,
|
|
0,
|
|
(LPVOID) (LPBYTE) &lpStatBuf);
|
|
if (apiRet != NERR_Success) {
|
|
printf("NetServiceControl(query) %ws returned %lu\n",
|
|
pszService, apiRet);
|
|
return;
|
|
}
|
|
|
|
switch (lpStatBuf->svci2_status & SERVICE_INSTALL_STATE)
|
|
{
|
|
case SERVICE_UNINSTALLED:
|
|
printf ("\nService %ws successfully stopped\n", pszService);
|
|
ShowServices (2, lpStatBuf, 1);
|
|
return;
|
|
case SERVICE_UNINSTALL_PENDING: // Keep waiting
|
|
break;
|
|
default:
|
|
printf ("\nService %ws failed to stop\n", pszService);
|
|
printf ("NetServiceControl returned status %ld\n",
|
|
(DWORD) (lpStatBuf->svci2_status & SERVICE_INSTALL_STATE));
|
|
break;
|
|
}
|
|
|
|
// Get wait time from data structure.
|
|
|
|
dwWaitTime = WAIT_MULT * ( ( lpStatBuf->svci2_code
|
|
& SERVICE_IP_WAIT_TIME )
|
|
>> SERVICE_IP_WAITTIME_SHIFT);
|
|
|
|
NetApiBufferFree(lpStatBuf);
|
|
|
|
// Provide a default wait time if the service doesn't give one.
|
|
|
|
if (dwWaitTime == 0)
|
|
dwWaitTime = DEFAULT_WAITTIME;
|
|
|
|
// If service is not stopped in after 20 polls, fail.
|
|
if (dwElapsedTime >= (DWORD) (MAX_POLLS * dwWaitTime))
|
|
{
|
|
printf( "\n%ws failed to stop: ", pszService);
|
|
printf(" The service did not report an error.\n");
|
|
break;
|
|
}
|
|
|
|
printf ("."); // Display to let user know program is active.
|
|
Sleep( dwWaitTime );
|
|
dwElapsedTime++;
|
|
|
|
} while ((lpStatBuf->svci2_status & SERVICE_INSTALL_STATE)
|
|
== SERVICE_UNINSTALL_PENDING);
|
|
|
|
// Successful installation returns from the switch statement.
|
|
return;
|
|
}
|
|
//=================================================================
|
|
// Usage
|
|
//
|
|
// Display possible command-line switches for this example.
|
|
//=================================================================
|
|
|
|
void Usage(char * pszString)
|
|
{
|
|
fprintf(stderr, "NetService API sample program: 32-bit, Unicode version.\n");
|
|
fprintf(stderr, "Usage: %s [-s \\\\server] [-v servicename]", pszString);
|
|
fprintf(stderr, " [-l level]\n");
|
|
exit( EXIT_FAILURE );
|
|
}
|