667 lines
15 KiB
C
667 lines
15 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Shutdown.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the client side wrappers for the Win32 remote
|
|||
|
shutdown APIs, that is:
|
|||
|
|
|||
|
- InitiateSystemShutdownA
|
|||
|
- InitiateSystemShutdownW
|
|||
|
- AbortSystemShutdownA
|
|||
|
- AbortSystemShutdownW
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Dave Chalmers (davidc) 29-Apr-1992
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Dragos C. Sambotin (dragoss) 21-May-1999
|
|||
|
Added support for the new winlogon's Shutdown interface
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#define UNICODE
|
|||
|
|
|||
|
#include <rpc.h>
|
|||
|
#include "regrpc.h"
|
|||
|
#include "client.h"
|
|||
|
#include "shutinit.h"
|
|||
|
#include "..\regconn\regconn.h"
|
|||
|
|
|||
|
LONG
|
|||
|
BaseBindToMachine(
|
|||
|
IN LPCWSTR lpMachineName,
|
|||
|
IN PBIND_CALLBACK BindCallback,
|
|||
|
IN PVOID Context1,
|
|||
|
IN PVOID Context2
|
|||
|
);
|
|||
|
|
|||
|
LONG
|
|||
|
ShutdownCallback(
|
|||
|
IN RPC_BINDING_HANDLE *pbinding,
|
|||
|
IN PUNICODE_STRING Message,
|
|||
|
IN PVOID Context2
|
|||
|
);
|
|||
|
|
|||
|
LONG
|
|||
|
ShutdownCallbackEx(
|
|||
|
IN RPC_BINDING_HANDLE *pbinding,
|
|||
|
IN PUNICODE_STRING Message,
|
|||
|
IN PVOID Context2
|
|||
|
);
|
|||
|
|
|||
|
LONG
|
|||
|
AbortShutdownCallback(
|
|||
|
IN RPC_BINDING_HANDLE *pbinding,
|
|||
|
IN PVOID Context1,
|
|||
|
IN PVOID Context2
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
APIENTRY
|
|||
|
InitiateSystemShutdownW(
|
|||
|
IN LPWSTR lpMachineName OPTIONAL,
|
|||
|
IN LPWSTR lpMessage OPTIONAL,
|
|||
|
IN DWORD dwTimeout,
|
|||
|
IN BOOL bForceAppsClosed,
|
|||
|
IN BOOL bRebootAfterShutdown
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Win32 Unicode API for initiating the shutdown of a (possibly remote) machine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpMachineName - Name of machine to shutdown.
|
|||
|
|
|||
|
lpMessage - Message to display during shutdown timeout period.
|
|||
|
|
|||
|
dwTimeout - Number of seconds to delay before shutting down
|
|||
|
|
|||
|
bForceAppsClosed - Normally applications may prevent system shutdown.
|
|||
|
If this flag is set, all applications are terminated
|
|||
|
unconditionally.
|
|||
|
|
|||
|
bRebootAfterShutdown - TRUE if the system should reboot.
|
|||
|
FALSE if it should be left in a shutdown state.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns TRUE on success, FALSE on failure (GetLastError() returns error code)
|
|||
|
|
|||
|
Possible errors :
|
|||
|
|
|||
|
ERROR_SHUTDOWN_IN_PROGRESS - a shutdown has already been started on
|
|||
|
the specified machine.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Result;
|
|||
|
UNICODE_STRING Message;
|
|||
|
SHUTDOWN_CONTEXT ShutdownContext;
|
|||
|
BOOL TryOld = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Explicitly bind to the given server.
|
|||
|
//
|
|||
|
if (!ARGUMENT_PRESENT(lpMachineName)) {
|
|||
|
lpMachineName = L"";
|
|||
|
TryOld = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
ShutdownContext.dwTimeout = dwTimeout;
|
|||
|
ShutdownContext.bForceAppsClosed = (bForceAppsClosed != 0);
|
|||
|
ShutdownContext.bRebootAfterShutdown = (bRebootAfterShutdown != 0);
|
|||
|
RtlInitUnicodeString(&Message, lpMessage);
|
|||
|
|
|||
|
//
|
|||
|
// Call the server
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// First try to connect to the new InitShutdown interface
|
|||
|
//
|
|||
|
Result = BaseBindToMachineShutdownInterface(lpMachineName,
|
|||
|
NewShutdownCallback,
|
|||
|
&Message,
|
|||
|
&ShutdownContext);
|
|||
|
|
|||
|
if( (Result != ERROR_SUCCESS) && (TryOld == TRUE) ) {
|
|||
|
//
|
|||
|
// try the old one, maybe we are calling into a NT4 machine
|
|||
|
// which doesn't know about the new interface
|
|||
|
//
|
|||
|
Result = BaseBindToMachine(lpMachineName,
|
|||
|
ShutdownCallback,
|
|||
|
&Message,
|
|||
|
&ShutdownContext);
|
|||
|
}
|
|||
|
|
|||
|
if (Result != ERROR_SUCCESS) {
|
|||
|
SetLastError(Result);
|
|||
|
}
|
|||
|
|
|||
|
return(Result == ERROR_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
APIENTRY
|
|||
|
InitiateSystemShutdownExW(
|
|||
|
IN LPWSTR lpMachineName OPTIONAL,
|
|||
|
IN LPWSTR lpMessage OPTIONAL,
|
|||
|
IN DWORD dwTimeout,
|
|||
|
IN BOOL bForceAppsClosed,
|
|||
|
IN BOOL bRebootAfterShutdown,
|
|||
|
IN DWORD dwReason
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Win32 Unicode API for initiating the shutdown of a (possibly remote) machine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpMachineName - Name of machine to shutdown.
|
|||
|
|
|||
|
lpMessage - Message to display during shutdown timeout period.
|
|||
|
|
|||
|
dwTimeout - Number of seconds to delay before shutting down
|
|||
|
|
|||
|
bForceAppsClosed - Normally applications may prevent system shutdown.
|
|||
|
If this flag is set, all applications are terminated
|
|||
|
unconditionally.
|
|||
|
|
|||
|
bRebootAfterShutdown - TRUE if the system should reboot.
|
|||
|
FALSE if it should be left in a shutdown state.
|
|||
|
|
|||
|
dwReason - Reason for initiating the shutdown. This reason is logged
|
|||
|
in the eventlog #6006 event.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns TRUE on success, FALSE on failure (GetLastError() returns error code)
|
|||
|
|
|||
|
Possible errors :
|
|||
|
|
|||
|
ERROR_SHUTDOWN_IN_PROGRESS - a shutdown has already been started on
|
|||
|
the specified machine.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Result;
|
|||
|
UNICODE_STRING Message;
|
|||
|
SHUTDOWN_CONTEXTEX ShutdownContext;
|
|||
|
BOOL TryOld = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Explicitly bind to the given server.
|
|||
|
//
|
|||
|
if (!ARGUMENT_PRESENT(lpMachineName)) {
|
|||
|
lpMachineName = L"";
|
|||
|
TryOld = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
ShutdownContext.dwTimeout = dwTimeout;
|
|||
|
ShutdownContext.bForceAppsClosed = (bForceAppsClosed != 0);
|
|||
|
ShutdownContext.bRebootAfterShutdown = (bRebootAfterShutdown != 0);
|
|||
|
ShutdownContext.dwReason = dwReason;
|
|||
|
RtlInitUnicodeString(&Message, lpMessage);
|
|||
|
|
|||
|
//
|
|||
|
// Call the server
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// First try to connect to the new InitShutdown interface
|
|||
|
//
|
|||
|
Result = BaseBindToMachineShutdownInterface(lpMachineName,
|
|||
|
NewShutdownCallbackEx,
|
|||
|
&Message,
|
|||
|
&ShutdownContext);
|
|||
|
|
|||
|
if( (Result != ERROR_SUCCESS) && (TryOld == TRUE) ) {
|
|||
|
//
|
|||
|
// try the old one, maybe we are calling into a NT4 machine
|
|||
|
// which doesn't know about the new interface
|
|||
|
//
|
|||
|
Result = BaseBindToMachine(lpMachineName,
|
|||
|
ShutdownCallbackEx,
|
|||
|
&Message,
|
|||
|
&ShutdownContext);
|
|||
|
}
|
|||
|
|
|||
|
if (Result != ERROR_SUCCESS) {
|
|||
|
SetLastError(Result);
|
|||
|
}
|
|||
|
|
|||
|
return(Result == ERROR_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
APIENTRY
|
|||
|
InitiateSystemShutdownA(
|
|||
|
IN LPSTR lpMachineName OPTIONAL,
|
|||
|
IN LPSTR lpMessage OPTIONAL,
|
|||
|
IN DWORD dwTimeout,
|
|||
|
IN BOOL bForceAppsClosed,
|
|||
|
IN BOOL bRebootAfterShutdown
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
See InitiateSystemShutdownW
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UNICODE_STRING MachineName;
|
|||
|
UNICODE_STRING Message;
|
|||
|
ANSI_STRING AnsiString;
|
|||
|
NTSTATUS Status;
|
|||
|
BOOL Result;
|
|||
|
|
|||
|
//
|
|||
|
// Convert the ansi machinename to wide-character
|
|||
|
//
|
|||
|
|
|||
|
RtlInitAnsiString( &AnsiString, lpMachineName );
|
|||
|
Status = RtlAnsiStringToUnicodeString(
|
|||
|
&MachineName,
|
|||
|
&AnsiString,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
if( NT_SUCCESS( Status )) {
|
|||
|
|
|||
|
//
|
|||
|
// Convert the ansi message to wide-character
|
|||
|
//
|
|||
|
|
|||
|
RtlInitAnsiString( &AnsiString, lpMessage );
|
|||
|
Status = RtlAnsiStringToUnicodeString(
|
|||
|
&Message,
|
|||
|
&AnsiString,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Call the wide-character api
|
|||
|
//
|
|||
|
|
|||
|
Result = InitiateSystemShutdownW(
|
|||
|
MachineName.Buffer,
|
|||
|
Message.Buffer,
|
|||
|
dwTimeout,
|
|||
|
bForceAppsClosed,
|
|||
|
bRebootAfterShutdown
|
|||
|
);
|
|||
|
|
|||
|
RtlFreeUnicodeString(&Message);
|
|||
|
}
|
|||
|
|
|||
|
RtlFreeUnicodeString(&MachineName);
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
SetLastError(RtlNtStatusToDosError(Status));
|
|||
|
Result = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return(Result);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
APIENTRY
|
|||
|
InitiateSystemShutdownExA(
|
|||
|
IN LPSTR lpMachineName OPTIONAL,
|
|||
|
IN LPSTR lpMessage OPTIONAL,
|
|||
|
IN DWORD dwTimeout,
|
|||
|
IN BOOL bForceAppsClosed,
|
|||
|
IN BOOL bRebootAfterShutdown,
|
|||
|
IN DWORD dwReason
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
See InitiateSystemShutdownW
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UNICODE_STRING MachineName;
|
|||
|
UNICODE_STRING Message;
|
|||
|
ANSI_STRING AnsiString;
|
|||
|
NTSTATUS Status;
|
|||
|
BOOL Result;
|
|||
|
|
|||
|
//
|
|||
|
// Convert the ansi machinename to wide-character
|
|||
|
//
|
|||
|
|
|||
|
RtlInitAnsiString( &AnsiString, lpMachineName );
|
|||
|
Status = RtlAnsiStringToUnicodeString(
|
|||
|
&MachineName,
|
|||
|
&AnsiString,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
if( NT_SUCCESS( Status )) {
|
|||
|
|
|||
|
//
|
|||
|
// Convert the ansi message to wide-character
|
|||
|
//
|
|||
|
|
|||
|
RtlInitAnsiString( &AnsiString, lpMessage );
|
|||
|
Status = RtlAnsiStringToUnicodeString(
|
|||
|
&Message,
|
|||
|
&AnsiString,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Call the wide-character api
|
|||
|
//
|
|||
|
|
|||
|
Result = InitiateSystemShutdownExW(
|
|||
|
MachineName.Buffer,
|
|||
|
Message.Buffer,
|
|||
|
dwTimeout,
|
|||
|
bForceAppsClosed,
|
|||
|
bRebootAfterShutdown,
|
|||
|
dwReason
|
|||
|
);
|
|||
|
|
|||
|
RtlFreeUnicodeString(&Message);
|
|||
|
}
|
|||
|
|
|||
|
RtlFreeUnicodeString(&MachineName);
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
SetLastError(RtlNtStatusToDosError(Status));
|
|||
|
Result = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return(Result);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
APIENTRY
|
|||
|
AbortSystemShutdownW(
|
|||
|
IN LPWSTR lpMachineName OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Win32 Unicode API for aborting the shutdown of a (possibly remote) machine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpMachineName - Name of target machine.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns TRUE on success, FALSE on failure (GetLastError() returns error code)
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Result;
|
|||
|
RPC_BINDING_HANDLE binding;
|
|||
|
BOOL TryOld = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Explicitly bind to the given server.
|
|||
|
//
|
|||
|
if (!ARGUMENT_PRESENT(lpMachineName)) {
|
|||
|
lpMachineName = L"";
|
|||
|
TryOld = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Call the server
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// First try to connect to the new InitShutdown interface
|
|||
|
//
|
|||
|
Result = BaseBindToMachineShutdownInterface(lpMachineName,
|
|||
|
NewAbortShutdownCallback,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
if( (Result != ERROR_SUCCESS) && (TryOld == TRUE) ) {
|
|||
|
//
|
|||
|
// try the old one, maybe we are calling into a NT4 machine
|
|||
|
// which doesn't know about the new interface
|
|||
|
Result = BaseBindToMachine(lpMachineName,
|
|||
|
AbortShutdownCallback,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
if (Result != ERROR_SUCCESS) {
|
|||
|
SetLastError(Result);
|
|||
|
}
|
|||
|
|
|||
|
return(Result == ERROR_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
APIENTRY
|
|||
|
AbortSystemShutdownA(
|
|||
|
IN LPSTR lpMachineName OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
See AbortSystemShutdownW
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UNICODE_STRING MachineName;
|
|||
|
ANSI_STRING AnsiString;
|
|||
|
NTSTATUS Status;
|
|||
|
BOOL Result;
|
|||
|
|
|||
|
//
|
|||
|
// Convert the ansi machinename to wide-character
|
|||
|
//
|
|||
|
|
|||
|
RtlInitAnsiString( &AnsiString, lpMachineName );
|
|||
|
Status = RtlAnsiStringToUnicodeString(
|
|||
|
&MachineName,
|
|||
|
&AnsiString,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
if( NT_SUCCESS( Status )) {
|
|||
|
|
|||
|
//
|
|||
|
// Call the wide-character api
|
|||
|
//
|
|||
|
|
|||
|
Result = AbortSystemShutdownW(
|
|||
|
MachineName.Buffer
|
|||
|
);
|
|||
|
|
|||
|
RtlFreeUnicodeString(&MachineName);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
SetLastError(RtlNtStatusToDosError(Status));
|
|||
|
Result = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return(Result);
|
|||
|
}
|
|||
|
|
|||
|
LONG
|
|||
|
ShutdownCallback(
|
|||
|
IN RPC_BINDING_HANDLE *pbinding,
|
|||
|
IN PUNICODE_STRING Message,
|
|||
|
IN PSHUTDOWN_CONTEXT ShutdownContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Callback for binding to a machine to initiate a shutdown.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pbinding - Supplies a pointer to the RPC binding context
|
|||
|
|
|||
|
Message - Supplies message to display during shutdown timeout period.
|
|||
|
|
|||
|
ShutdownContext - Supplies remaining parameters for BaseInitiateSystemShutdown
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS if no error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Result;
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
Result = BaseInitiateSystemShutdown((PREGISTRY_SERVER_NAME)pbinding,
|
|||
|
Message,
|
|||
|
ShutdownContext->dwTimeout,
|
|||
|
ShutdownContext->bForceAppsClosed,
|
|||
|
ShutdownContext->bRebootAfterShutdown);
|
|||
|
} RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
Result = RpcExceptionCode();
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
if (Result != ERROR_SUCCESS) {
|
|||
|
RpcBindingFree(pbinding);
|
|||
|
}
|
|||
|
return(Result);
|
|||
|
}
|
|||
|
|
|||
|
LONG
|
|||
|
ShutdownCallbackEx(
|
|||
|
IN RPC_BINDING_HANDLE *pbinding,
|
|||
|
IN PUNICODE_STRING Message,
|
|||
|
IN PSHUTDOWN_CONTEXTEX ShutdownContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Callback for binding to a machine to initiate a shutdown.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pbinding - Supplies a pointer to the RPC binding context
|
|||
|
|
|||
|
Message - Supplies message to display during shutdown timeout period.
|
|||
|
|
|||
|
ShutdownContext - Supplies remaining parameters for BaseInitiateSystemShutdown
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS if no error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Result;
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
Result = BaseInitiateSystemShutdownEx((PREGISTRY_SERVER_NAME)pbinding,
|
|||
|
Message,
|
|||
|
ShutdownContext->dwTimeout,
|
|||
|
ShutdownContext->bForceAppsClosed,
|
|||
|
ShutdownContext->bRebootAfterShutdown,
|
|||
|
ShutdownContext->dwReason);
|
|||
|
} RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
Result = RpcExceptionCode();
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
if (Result != ERROR_SUCCESS) {
|
|||
|
RpcBindingFree(pbinding);
|
|||
|
}
|
|||
|
return(Result);
|
|||
|
}
|
|||
|
|
|||
|
LONG
|
|||
|
AbortShutdownCallback(
|
|||
|
IN RPC_BINDING_HANDLE *pbinding,
|
|||
|
IN PVOID Unused1,
|
|||
|
IN PVOID Unused2
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Callback for binding to a machine to abort a shutdown.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pbinding - Supplies a pointer to the RPC binding context
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS if no error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Result;
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
Result = BaseAbortSystemShutdown((PREGISTRY_SERVER_NAME)pbinding);
|
|||
|
} RpcExcept(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
Result = RpcExceptionCode();
|
|||
|
} RpcEndExcept;
|
|||
|
|
|||
|
if (Result != ERROR_SUCCESS) {
|
|||
|
RpcBindingFree(pbinding);
|
|||
|
}
|
|||
|
return(Result);
|
|||
|
}
|
|||
|
|
|||
|
|