mirror of https://github.com/tongzx/nt5src
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.
868 lines
18 KiB
868 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
svcapis.cxx
|
|
|
|
Abstract:
|
|
|
|
Contains code that implements the service location apis.
|
|
|
|
Author:
|
|
|
|
Madan Appiah (madana) 15-May-1995
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <svcloc.hxx>
|
|
|
|
DWORD
|
|
WINAPI
|
|
INetDiscoverServers(
|
|
IN ULONGLONG ServicesMask,
|
|
IN DWORD WaitTime,
|
|
OUT LPINET_SERVERS_LIST *ServersList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API discovers all servers on the network that support and run the
|
|
internet services specified.
|
|
|
|
This API is called by the client side code, such as the internet admin
|
|
tool or wininet.dll.
|
|
|
|
Arguments:
|
|
|
|
SevicesMask : A bit mask that specifies to discover servers with the
|
|
these services running.
|
|
|
|
ex: 0x0000000E, will discovers all servers running any of the
|
|
following services :
|
|
|
|
1. FTP_SERVICE
|
|
2. GOPHER_SERVICE
|
|
3. WEB_SERVICE
|
|
|
|
DiscoverBindings : if this flag is set, this API talks to each of the
|
|
discovered server and queries the services and bindings
|
|
supported. If the flag is set to FALSE, it quickly returns with
|
|
the list of servers only.
|
|
|
|
WaitTime : Response wait time in secs. If this value is zero, it
|
|
returns what ever discovered so far by the previous invocation of
|
|
this APIs, otherwise it waits for the specified secs to collect
|
|
responses from the servers.
|
|
|
|
ServersList : Pointer to a location where the pointer to list of
|
|
servers info is returned. The API allocates dynamic memory for
|
|
this return data, the caller should free it by calling
|
|
INetFreeDiscoverServerList after it has been used.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
BOOL SvcLockLocked = FALSE;
|
|
|
|
//
|
|
// WSAStartup().
|
|
//
|
|
|
|
LOCK_SVC_GLOBAL_DATA();
|
|
SvcLockLocked = TRUE;
|
|
|
|
if ( !GlobalWinsockStarted ) {
|
|
|
|
Error = WSAStartup( WS_VERSION_REQUIRED, &GlobalWinsockStartupData );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
GlobalWinsockStarted = TRUE;
|
|
}
|
|
|
|
//
|
|
// make a discovery message, if it is not made before.
|
|
//
|
|
|
|
Error = MakeClientQueryMesage( ServicesMask );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// now check to see the discovery is in progress.
|
|
//
|
|
|
|
DWORD EventState;
|
|
EventState = WaitForSingleObject( GlobalDiscoveryInProgressEvent, 0 );
|
|
|
|
switch( EventState ) {
|
|
case WAIT_OBJECT_0:
|
|
break;
|
|
|
|
case WAIT_TIMEOUT:
|
|
|
|
//
|
|
// discovery is in progress.
|
|
//
|
|
|
|
if( WaitTime == 0 ) {
|
|
|
|
//
|
|
// the caller does not want to wait, return available data.
|
|
//
|
|
|
|
goto ProcessResponse;
|
|
|
|
}
|
|
|
|
//
|
|
// wait until the discovery is done or the specified delay is
|
|
// over. Release global lock before wait, otherwise it will
|
|
// get into a dead lock.
|
|
//
|
|
|
|
UNLOCK_SVC_GLOBAL_DATA();
|
|
SvcLockLocked = FALSE;
|
|
|
|
EventState = WaitForSingleObject( GlobalDiscoveryInProgressEvent, WaitTime * 1000 );
|
|
|
|
switch( EventState ) {
|
|
case WAIT_OBJECT_0:
|
|
case WAIT_TIMEOUT:
|
|
|
|
goto ProcessResponse;
|
|
|
|
default:
|
|
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
default:
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// now check to see we have done the discovery recently. if so, don't
|
|
// do discovery again, just return the available data.
|
|
//
|
|
|
|
time_t CurrentTime;
|
|
|
|
CurrentTime = time( NULL );
|
|
if( CurrentTime <
|
|
GlobalLastDiscoveryTime + INET_DISCOVERY_RETRY_TIMEOUT ) {
|
|
|
|
goto ProcessResponse;
|
|
}
|
|
|
|
//
|
|
// reset GlobalDiscoveryInProgressEvent to signal that discovery is in
|
|
// progress.
|
|
//
|
|
|
|
if( !ResetEvent( GlobalDiscoveryInProgressEvent ) ) {
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
UNLOCK_SVC_GLOBAL_DATA();
|
|
SvcLockLocked = FALSE;
|
|
|
|
//
|
|
// send discovery query message to all IPX servers.
|
|
//
|
|
|
|
Error = DiscoverIpxServers( NULL );
|
|
|
|
//
|
|
// now send a message to IP servers.
|
|
//
|
|
|
|
DWORD Error1;
|
|
|
|
if( GlobalPlatformType == VER_PLATFORM_WIN32_NT ) {
|
|
|
|
Error1 = DiscoverIpServers( NULL );
|
|
// discover using 1C group name.
|
|
}
|
|
else {
|
|
|
|
Error1 = DiscoverNetBiosServers( NULL );
|
|
// discover using 1C group name.
|
|
}
|
|
|
|
TcpsvcsDbgAssert( Error1 == ERROR_SUCCESS );
|
|
|
|
//
|
|
// if we have not successfully sent query message in either of the
|
|
// protocol, simply bail out.
|
|
//
|
|
|
|
if( (Error != ERROR_SUCCESS) && (Error1 != ERROR_SUCCESS) ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( GlobalPlatformType == VER_PLATFORM_WIN32s ) {
|
|
|
|
//
|
|
// for windows 3.1 we can't create thread so we discover in user
|
|
// thread.
|
|
//
|
|
|
|
WaitTime = RESPONSE_WAIT_TIMEOUT;
|
|
}
|
|
|
|
if( WaitTime == 0 ) {
|
|
|
|
//
|
|
// if the client is not willing to wait, setup a thread that
|
|
// receives query response.
|
|
//
|
|
|
|
LOCK_SVC_GLOBAL_DATA();
|
|
SvcLockLocked = TRUE;
|
|
|
|
if( GlobalCliDiscoverThreadHandle == NULL ) {
|
|
|
|
DWORD ThreadId;
|
|
|
|
GlobalCliDiscoverThreadHandle =
|
|
CreateThread(
|
|
NULL, // default security
|
|
0, // default stack size
|
|
(LPTHREAD_START_ROUTINE)ServerDiscoverThread,
|
|
NULL, // no parameter
|
|
0, // create flag, no suspend
|
|
&ThreadId );
|
|
|
|
if( GlobalCliDiscoverThreadHandle == NULL ) {
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
UNLOCK_SVC_GLOBAL_DATA();
|
|
SvcLockLocked = FALSE;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Wait for WaitTime secs for query responses
|
|
// to arrive.
|
|
//
|
|
|
|
Error = ReceiveResponses( (WORD)WaitTime, TRUE );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
ProcessResponse:
|
|
|
|
Error = ProcessDiscoveryResponses( ServicesMask, ServersList );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// done.
|
|
//
|
|
|
|
Error = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if( SvcLockLocked ) {
|
|
UNLOCK_SVC_GLOBAL_DATA();
|
|
}
|
|
|
|
return( Error );
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
INetGetServerInfo(
|
|
IN LPSTR ServerName,
|
|
IN ULONGLONG ServicesMask,
|
|
IN DWORD WaitTime,
|
|
OUT LPINET_SERVER_INFO *ServerInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API returns the server info and a list of services supported by
|
|
the server and lists of bindings supported by each of the services.
|
|
|
|
Arguments:
|
|
|
|
ServerName : name of the server whose info to be queried.
|
|
|
|
ServicesMask : services to be queried
|
|
|
|
WaitTime : Time in secs to wait.
|
|
|
|
ServerInfo : pointer to a location where the pointer to the server
|
|
info structure will be returned. The caller should call
|
|
INetFreeServerInfo to free up the list after use.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
BOOL SvcLockLocked = FALSE;
|
|
CHAR NBServerName[NETBIOS_NAME_LENGTH + 1];
|
|
|
|
//
|
|
// WSAStartup().
|
|
//
|
|
|
|
LOCK_SVC_GLOBAL_DATA();
|
|
SvcLockLocked = TRUE;
|
|
|
|
if ( !GlobalWinsockStarted ) {
|
|
|
|
Error = WSAStartup( WS_VERSION_REQUIRED, &GlobalWinsockStartupData );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
GlobalWinsockStarted = TRUE;
|
|
}
|
|
|
|
//
|
|
// make a discovery message, if it is not made before.
|
|
//
|
|
|
|
Error = MakeClientQueryMesage( ServicesMask );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// now check to see the discovery is in progress.
|
|
//
|
|
|
|
DWORD EventState;
|
|
EventState = WaitForSingleObject( GlobalDiscoveryInProgressEvent, 0 );
|
|
|
|
switch( EventState ) {
|
|
case WAIT_OBJECT_0:
|
|
break;
|
|
|
|
case WAIT_TIMEOUT:
|
|
|
|
//
|
|
// discovery is in progress.
|
|
//
|
|
|
|
if( WaitTime == 0 ) {
|
|
|
|
//
|
|
// the caller does not want to wait, return available data.
|
|
//
|
|
|
|
goto GetServerResponse;
|
|
|
|
}
|
|
|
|
//
|
|
// wait until the discovery is done or the specified delay is
|
|
// over. Release global lock before wait, otherwise it will
|
|
// get into a dead lock.
|
|
//
|
|
|
|
UNLOCK_SVC_GLOBAL_DATA();
|
|
SvcLockLocked = FALSE;
|
|
|
|
EventState = WaitForSingleObject( GlobalDiscoveryInProgressEvent, WaitTime * 1000 );
|
|
|
|
switch( EventState ) {
|
|
case WAIT_OBJECT_0:
|
|
case WAIT_TIMEOUT:
|
|
|
|
goto GetServerResponse;
|
|
|
|
default:
|
|
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
default:
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// now check to see we have done the discovery recently. if so, don't
|
|
// do discovery again, just return the available data.
|
|
//
|
|
|
|
time_t CurrentTime;
|
|
|
|
CurrentTime = time( NULL );
|
|
if( CurrentTime <
|
|
GlobalLastDiscoveryTime + INET_DISCOVERY_RETRY_TIMEOUT ) {
|
|
|
|
goto GetServerResponse;
|
|
}
|
|
|
|
//
|
|
// reset GlobalDiscoveryInProgressEvent to signal that discovery is in
|
|
// progress.
|
|
//
|
|
|
|
if( !ResetEvent( GlobalDiscoveryInProgressEvent ) ) {
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
UNLOCK_SVC_GLOBAL_DATA();
|
|
SvcLockLocked = FALSE;
|
|
|
|
//
|
|
// upper case the server name.
|
|
//
|
|
|
|
_strupr( ServerName );
|
|
|
|
//
|
|
// make unique server name.
|
|
//
|
|
|
|
MakeUniqueServerName(
|
|
(LPBYTE)NBServerName,
|
|
NETBIOS_NAME_LENGTH,
|
|
ServerName );
|
|
|
|
//
|
|
// terminate the string.
|
|
//
|
|
|
|
NBServerName[ NETBIOS_NAME_LENGTH ] = '\0';
|
|
|
|
//
|
|
// send discovery query message to all IPX servers.
|
|
//
|
|
|
|
Error = DiscoverIpxServers( ServerName );
|
|
|
|
//
|
|
// now send a message to IP servers.
|
|
//
|
|
|
|
DWORD Error1;
|
|
|
|
if( GlobalPlatformType == VER_PLATFORM_WIN32_NT ) {
|
|
|
|
Error1 = DiscoverIpServers( NBServerName );
|
|
// discover using specified server name.
|
|
}
|
|
else {
|
|
|
|
Error1 = DiscoverNetBiosServers( NBServerName );
|
|
// discover using specified server name.
|
|
}
|
|
|
|
TcpsvcsDbgAssert( Error1 == ERROR_SUCCESS );
|
|
|
|
//
|
|
// if we have successfully sent query message in either of the
|
|
// protocol, simply bail out.
|
|
//
|
|
|
|
if( (Error != ERROR_SUCCESS) && (Error1 != ERROR_SUCCESS) ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( WaitTime == 0 ) {
|
|
|
|
//
|
|
// if the client is not willing to wait, setup a thread that
|
|
// receives query response.
|
|
//
|
|
|
|
LOCK_SVC_GLOBAL_DATA();
|
|
SvcLockLocked = TRUE;
|
|
|
|
if( GlobalCliDiscoverThreadHandle == NULL ) {
|
|
|
|
DWORD ThreadId;
|
|
|
|
GlobalCliDiscoverThreadHandle =
|
|
CreateThread(
|
|
NULL, // default security
|
|
0, // default stack size
|
|
(LPTHREAD_START_ROUTINE)ServerDiscoverThread,
|
|
NULL, // no parameter
|
|
0, // create flag, no suspend
|
|
&ThreadId );
|
|
|
|
if( GlobalCliDiscoverThreadHandle == NULL ) {
|
|
Error = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
UNLOCK_SVC_GLOBAL_DATA();
|
|
SvcLockLocked = FALSE;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Wait for WaitTime secs for query responses
|
|
// to arrive.
|
|
//
|
|
|
|
Error = ReceiveResponses( (WORD)WaitTime, FALSE );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
GetServerResponse:
|
|
|
|
Error = GetDiscoveredServerInfo( ServerName, ServicesMask, ServerInfo );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// done.
|
|
//
|
|
|
|
Error = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if( SvcLockLocked ) {
|
|
UNLOCK_SVC_GLOBAL_DATA();
|
|
}
|
|
|
|
return( Error );
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
INetFreeDiscoverServersList(
|
|
IN OUT LPINET_SERVERS_LIST *ServersList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API frees the memory chunks that were allotted for the servers
|
|
list by the INetDiscoverServers call.
|
|
|
|
Arguments:
|
|
|
|
ServersList : pointer to a location where the pointer to the server
|
|
list to be freed is stored.
|
|
|
|
Return Value:
|
|
|
|
NONE.
|
|
|
|
--*/
|
|
{
|
|
FreeServersList( *ServersList );
|
|
*ServersList = NULL;
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
INetFreeServerInfo(
|
|
IN OUT LPINET_SERVER_INFO *ServerInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API frees the memory chunks that were allotted for the server
|
|
info structure by the INetGetServerInfo call.
|
|
|
|
Arguments:
|
|
|
|
ServerInfo : pointer to a location where the pointer to the server
|
|
info structure to be freed is stored.
|
|
|
|
Return Value:
|
|
|
|
NONE.
|
|
|
|
--*/
|
|
{
|
|
FreeServerInfo( *ServerInfo );
|
|
*ServerInfo = NULL;
|
|
return;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
INetRegisterService(
|
|
IN ULONGLONG ServiceMask,
|
|
IN INET_SERVICE_STATE ServiceState,
|
|
IN LPSTR ServiceComment,
|
|
IN LPINET_BINDINGS Bindings
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API registers an internet service. The service writers should
|
|
call this API just after successfully started the service and the
|
|
service is ready to accept incoming RPC calls. This API accepts an
|
|
array of RPC binding strings that the service is listening on for the
|
|
incoming RPC connections. This list will be distributed to the
|
|
clients that are discovering this service.
|
|
|
|
Arguments:
|
|
|
|
ServiceMask : service mask, such as 0x00000001 (GATEWAY_SERVICE)
|
|
|
|
ServiceState : State of the service, INetServiceRunning and
|
|
INetServicePaused are valid states to pass.
|
|
|
|
ServiceComment : Service comment specified by the admin.
|
|
|
|
Bindings : list of bindings that are supported by the service. The
|
|
bindings can be binding strings are those returned by the
|
|
RpcBindingToStringBinding call or the sockaddrs.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
INET_SERVICE_INFO ServiceInfo;
|
|
|
|
//
|
|
// if the server object is not created, do so.
|
|
//
|
|
|
|
LOCK_SVC_GLOBAL_DATA();
|
|
|
|
if( GlobalSrvInfoObj == NULL ) {
|
|
|
|
DWORD ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
|
|
|
|
//
|
|
// read computer name.
|
|
//
|
|
|
|
if( !GetComputerNameA(
|
|
GlobalComputerName,
|
|
&ComputerNameLength ) ) {
|
|
|
|
Error = GetLastError();
|
|
TcpsvcsDbgPrint(( DEBUG_ERRORS,
|
|
"GetComputerNameA failed, %ld.\n", Error ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
GlobalComputerName[ComputerNameLength] = '\0';
|
|
|
|
GlobalSrvInfoObj = new EMBED_SERVER_INFO(
|
|
INET_MAJOR_VERSION, // major version number,
|
|
INET_MINOR_VERSION, // minor version number
|
|
GlobalComputerName );
|
|
|
|
if( GlobalSrvInfoObj == NULL ) {
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
Error = GlobalSrvInfoObj->GetStatus();
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
|
|
delete GlobalSrvInfoObj;
|
|
GlobalSrvInfoObj = NULL;
|
|
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// allocate memory for the receive buffer, if it is not alotted before.
|
|
//
|
|
|
|
if( GlobalSrvRecvBuf == NULL ) {
|
|
|
|
GlobalSrvRecvBuf =
|
|
(LPBYTE)SvclocHeap->Alloc( SVCLOC_SRV_RECV_BUFFER_SIZE );
|
|
|
|
if( GlobalSrvRecvBuf == NULL ) {
|
|
Error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
GlobalSrvRecvBufLength = SVCLOC_SRV_RECV_BUFFER_SIZE;
|
|
}
|
|
|
|
//
|
|
// check to see the server registered its location and it is listening
|
|
// to the client discovery. If not do so.
|
|
//
|
|
|
|
if( !GlobalSrvRegistered ) {
|
|
Error = ServerRegisterAndListen();
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
GlobalSrvRegistered = TRUE;
|
|
}
|
|
|
|
//
|
|
// make a new service info.
|
|
//
|
|
|
|
ServiceInfo.ServiceMask = ServiceMask;
|
|
ServiceInfo.ServiceState = ServiceState;
|
|
ServiceInfo.ServiceComment = ServiceComment;
|
|
ServiceInfo.Bindings = *Bindings;
|
|
|
|
//
|
|
// add this new service to server list.
|
|
//
|
|
|
|
Error = GlobalSrvInfoObj->AddService( &ServiceInfo );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// make response buffer.
|
|
//
|
|
|
|
Error = MakeResponseBuffer();
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Error = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
UNLOCK_SVC_GLOBAL_DATA();
|
|
return( Error );
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
INetDeregisterService(
|
|
IN ULONGLONG ServiceMask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API de-registers an internet service from being announced to the
|
|
discovering clients. The service writers should call this API just
|
|
before shutting down the service.
|
|
|
|
Arguments:
|
|
|
|
ServiceMask : service mask, such as 0x00000001 (GATEWAY_SERVICE)
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
INET_SERVICE_INFO ServiceInfo;
|
|
|
|
//
|
|
// remove the service if exists.
|
|
//
|
|
|
|
Error = GlobalSrvInfoObj->RemoveService( ServiceMask );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
if( Error != ERROR_SERVICE_NOT_FOUND ) {
|
|
return( Error );
|
|
}
|
|
|
|
Error = ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// add the service back to the list with service state set to
|
|
// INetServiceStopped and no bindings.
|
|
//
|
|
|
|
ServiceInfo.ServiceMask = ServiceMask;
|
|
ServiceInfo.ServiceState = INetServiceStopped;
|
|
ServiceInfo.ServiceComment = NULL;
|
|
ServiceInfo.Bindings.NumBindings = 0;
|
|
ServiceInfo.Bindings.BindingsInfo = NULL;
|
|
|
|
//
|
|
// readd the service to server list.
|
|
//
|
|
|
|
Error = GlobalSrvInfoObj->AddService( &ServiceInfo );
|
|
|
|
if( Error != ERROR_SUCCESS ) {
|
|
|
|
DWORD LocalError;
|
|
|
|
//
|
|
// recreate response buffer.
|
|
//
|
|
|
|
LocalError = MakeResponseBuffer();
|
|
TcpsvcsDbgAssert( LocalError == ERROR_SUCCESS );
|
|
|
|
return( Error );
|
|
}
|
|
|
|
//
|
|
// recreate response buffer.
|
|
//
|
|
|
|
Error = MakeResponseBuffer();
|
|
|
|
return( Error );
|
|
}
|