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.
707 lines
19 KiB
707 lines
19 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rpcutil.c
|
|
|
|
Abstract:
|
|
|
|
This module contains high level rpc wrapper apis.
|
|
This code is here because the code in the rpcutil
|
|
project uses NT apis and the WINFAX dll but load
|
|
and run on win95.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 13-Aug-1997
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "faxapi.h"
|
|
#include "CritSec.h"
|
|
#pragma hdrstop
|
|
|
|
typedef RPC_STATUS (*PRPCSERVERUNREGISTERIFEX)(RPC_IF_HANDLE IfSpec, UUID __RPC_FAR * MgrTypeUuid, int RundownContextHandles);
|
|
|
|
#define MIN_PORT_NUMBER 1024
|
|
#define MAX_PORT_NUMBER 65534
|
|
|
|
#ifdef UNICODE
|
|
#define LPUTSTR unsigned short *
|
|
#else
|
|
#define LPUTSTR unsigned char *
|
|
#endif
|
|
|
|
CFaxCriticalSection g_CsFaxClientRpc; // This critical section provides mutual exclusion
|
|
// for all RPC server initialization operations:
|
|
// 1. Registration counter (g_dwFaxClientRpcNumInst).
|
|
// 2. Selecting free endpoint.
|
|
// 3. Register the RPC interface
|
|
// 4. Start listening for remote procedure calls.
|
|
// 5. Stop listening for remote procedure calls.
|
|
// 6. remove the interface.
|
|
//
|
|
//
|
|
// IMPORTNAT!!! g_CsFaxClientRpc should not be used in the implementation of the RPC calls because it can cause a dead lock.
|
|
// because when the RPC server is going down in StopFaxClientRpcServer(), the wait opration (for all active calls to terminate) is inside g_CsFaxClientRpc.
|
|
//
|
|
DWORD g_dwFaxClientRpcNumInst;
|
|
CFaxCriticalSection g_CsFaxAssyncInfo; // used to synchronize access to the assync info structures that are allocated on the heap (notification context).
|
|
TCHAR g_tszEndPoint[MAX_ENDPOINT_LEN]; // Buffer to hold selected port (endpoint)
|
|
// for RPC protoqol sequence
|
|
static
|
|
RPC_STATUS
|
|
SafeRpcServerUnregisterIf(
|
|
VOID
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
This function calls RpcServerUnregisterIfEx if it is exported from RPCRT4.DLL (WinXP and up).
|
|
Otherwise it calls RpcServerUnregisterIf which is subject to rundown calls even after the interface is unregistered.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
Win32 errors
|
|
*/
|
|
{
|
|
HMODULE hModule = NULL;
|
|
RPC_STATUS RpcStatus;
|
|
DEBUG_FUNCTION_NAME(TEXT("SafeRpcServerUnregisterIf"));
|
|
|
|
if (hModule = LoadLibrary(TEXT("RPCRT4.DLL")))
|
|
{
|
|
PRPCSERVERUNREGISTERIFEX pRpcServerUnregisterIfEx = NULL;
|
|
if (pRpcServerUnregisterIfEx = (PRPCSERVERUNREGISTERIFEX)GetProcAddress(hModule, "RpcServerUnregisterIfEx"))
|
|
{
|
|
RpcStatus = (*pRpcServerUnregisterIfEx)(faxclient_ServerIfHandle, 0, FALSE);
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("GetProcAddress RpcServerUnregisterIfEx failed: %ld"),
|
|
GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("LoadLibrary RPCRT4.DLL failed: %ld"),
|
|
GetLastError());
|
|
}
|
|
|
|
DebugPrintEx(
|
|
DEBUG_WRN,
|
|
TEXT("Calling RpcServerUnregisterIf !!!"));
|
|
RpcStatus = RpcServerUnregisterIf(faxclient_ServerIfHandle, 0, FALSE);
|
|
Exit:
|
|
if (hModule)
|
|
{
|
|
FreeLibrary(hModule);
|
|
}
|
|
return RpcStatus;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
FaxClientInitRpcServer(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the critical section used to protect the
|
|
global server handle, instance count and assync info structures (notification context).
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxClientInitRpcServer"));
|
|
|
|
ZeroMemory (g_tszEndPoint, sizeof(g_tszEndPoint));
|
|
g_dwFaxClientRpcNumInst = 0;
|
|
|
|
if (!g_CsFaxClientRpc.Initialize() ||
|
|
!g_CsFaxAssyncInfo.Initialize())
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("CFaxCriticalSection.Initialize (g_CsFaxClientRpc or g_CsFaxAssyncInfo) failed: %ld"),
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
FaxClientTerminateRpcServer (VOID)
|
|
/*++
|
|
Routine Description: Delete critical section when PROCESS_DETACH.
|
|
|
|
|
|
--*/
|
|
{
|
|
g_CsFaxClientRpc.SafeDelete();
|
|
g_CsFaxAssyncInfo.SafeDelete();
|
|
return;
|
|
}
|
|
|
|
DWORD
|
|
StopFaxClientRpcServer(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stops the RPC server. Deletes the interface.
|
|
Note that an endpoint is allocated to a process as long as the process lives.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
NERR_Success, or any RPC error codes that can be returned from
|
|
RpcServerUnregisterIf/Ex.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus = RPC_S_OK;
|
|
DEBUG_FUNCTION_NAME(TEXT("StopFaxClientRpcServer"));
|
|
|
|
EnterCriticalSection(&g_CsFaxClientRpc);
|
|
if (0 == g_dwFaxClientRpcNumInst)
|
|
{
|
|
//
|
|
// This can happen if the client tried to unregister from events using an invalid handle, or used the same handle twice
|
|
//
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("StopFaxClientRpcServer was called when the clients reference count was 0"));
|
|
LeaveCriticalSection(&g_CsFaxClientRpc);
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
g_dwFaxClientRpcNumInst--;
|
|
if (g_dwFaxClientRpcNumInst == 0)
|
|
{
|
|
RpcStatus = RpcMgmtStopServerListening(NULL);
|
|
if (RPC_S_OK != RpcStatus)
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("RpcMgmtStopServerListening failed. (ec: %ld)"),
|
|
RpcStatus);
|
|
}
|
|
|
|
RpcStatus = SafeRpcServerUnregisterIf();
|
|
if (RPC_S_OK != RpcStatus)
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("SafeRpcServerUnregisterIf failed. (ec: %ld)"),
|
|
RpcStatus);
|
|
}
|
|
|
|
RpcStatus = RpcMgmtWaitServerListen();
|
|
if (RPC_S_OK != RpcStatus)
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("RpcMgmtStopServerListening failed. (ec: %ld)"),
|
|
RpcStatus);
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
|
|
exit:
|
|
LeaveCriticalSection(&g_CsFaxClientRpc);
|
|
|
|
return(RpcStatus);
|
|
}
|
|
|
|
|
|
DWORD
|
|
FaxClientUnbindFromFaxServer(
|
|
IN RPC_BINDING_HANDLE BindingHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unbinds from the RPC interface.
|
|
If we decide to cache bindings, this routine will do something more
|
|
interesting.
|
|
|
|
Arguments:
|
|
|
|
BindingHandle - This points to the binding handle that is to be closed.
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
STATUS_SUCCESS - the unbinding was successful.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
|
|
if (BindingHandle != NULL) {
|
|
RpcStatus = RpcBindingFree(&BindingHandle);
|
|
}
|
|
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
#if !defined(WIN95)
|
|
|
|
RPC_STATUS RPC_ENTRY FaxClientSecurityCallBack(
|
|
IN RPC_IF_HANDLE idIF,
|
|
IN void *ctx
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Security callback function is automatically called when
|
|
any RPC server function is called. (usually, once per client - but in some cases,
|
|
the RPC run time may call the security-callback function more than
|
|
once per client-per interface - For example when talking with BOS server
|
|
with no authentication).
|
|
|
|
The call-back will deny access for:
|
|
o clients with a protocol other then ncacn_ip_tcp
|
|
|
|
Arguments:
|
|
|
|
idIF - UUID and version of the interface.
|
|
ctx - Pointer to an RPC_IF_ID server binding handle representing the client.
|
|
|
|
Return Value:
|
|
|
|
The callback function should return RPC_S_OK if the client is allowed to call methods in this interface.
|
|
Any other return code will cause the client to receive the exception RPC_S_ACCESS_DENIED.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS status = RPC_S_OK;
|
|
RPC_STATUS rpcStatRet = RPC_S_OK;
|
|
|
|
LPTSTR lptstrProtSeq = NULL;
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxClientSecurityCallBack"));
|
|
|
|
//
|
|
// Query the client's protseq
|
|
//
|
|
status = GetRpcStringBindingInfo(ctx,
|
|
NULL,
|
|
&lptstrProtSeq);
|
|
if (status != RPC_S_OK)
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("RpcBindingServerFromClient failed - (ec: %lu)"),
|
|
status);
|
|
rpcStatRet = ERROR_ACCESS_DENIED;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
if (_tcsicmp((TCHAR*)lptstrProtSeq, RPC_PROT_SEQ_TCP_IP))
|
|
{
|
|
DebugPrintEx(DEBUG_ERR,
|
|
TEXT("Client not using TCP/IP protSeq.")
|
|
);
|
|
rpcStatRet = ERROR_ACCESS_DENIED;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
if(NULL != lptstrProtSeq)
|
|
{
|
|
MemFree(lptstrProtSeq);
|
|
}
|
|
|
|
return rpcStatRet;
|
|
} // FaxClientSecurityCallBack
|
|
|
|
#endif
|
|
|
|
DWORD
|
|
StartFaxClientRpcServer(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Starts an RPC Server, and adds the interface (dispatch table).
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Standard Win32 or RPC error code.
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD ec = RPC_S_OK;
|
|
DEBUG_FUNCTION_NAME(TEXT("StartFaxClientRpcServer"));
|
|
|
|
EnterCriticalSection(&g_CsFaxClientRpc);
|
|
|
|
if (0 == _tcslen(g_tszEndPoint))
|
|
{
|
|
//
|
|
// Endpoint not yet allocated for this Fax handle. Find a free endpoint.
|
|
// Note that an endpoint is allocated to a process as long as the process lives.
|
|
TCHAR tszFreeEndPoint[MAX_ENDPOINT_LEN] = {0};
|
|
DWORD i;
|
|
DWORD PortNumber;
|
|
|
|
for (i = MIN_PORT_NUMBER; i < MIN_PORT_NUMBER + 10 ; i++ )
|
|
{
|
|
//
|
|
// Search for a free end point.
|
|
// If we fail for an error other than a duplicate endpoint, we loop for nothing.
|
|
// We do so since diffrent platformns (W2K, NT4, Win9X) return diffrent error codes for duplicate enpoint.
|
|
//
|
|
for (PortNumber = i; PortNumber < MAX_PORT_NUMBER; PortNumber += 10)
|
|
{
|
|
_stprintf (tszFreeEndPoint, TEXT("%d"), PortNumber);
|
|
ec = RpcServerUseProtseqEp ( (LPUTSTR)RPC_PROT_SEQ_TCP_IP,
|
|
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
|
|
(LPUTSTR)tszFreeEndPoint,
|
|
NULL);
|
|
if (RPC_S_OK == ec)
|
|
{
|
|
_tcscpy (g_tszEndPoint, tszFreeEndPoint);
|
|
DebugPrintEx(
|
|
DEBUG_MSG,
|
|
TEXT("Found free endpoint - %s"),
|
|
tszFreeEndPoint);
|
|
break;
|
|
}
|
|
}
|
|
if (RPC_S_OK == ec)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 == g_dwFaxClientRpcNumInst)
|
|
{
|
|
//
|
|
// First rpc server instance - register interface, start listening for remote procedure calls
|
|
//
|
|
|
|
//
|
|
// Register interface
|
|
//
|
|
|
|
//
|
|
// The logic for registering the interface written below is done to preserve
|
|
// BOS capability of sending notifications.
|
|
// BOS Fax server does not "talk" with it's clients in a secure channel.
|
|
//
|
|
// Only on .NET OS we can call RpcServerRegisterIfEx for registering callback function even
|
|
// when the RPC client is anonymous (using the RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH flag that
|
|
// were introduce only on .NET).
|
|
//
|
|
// On all other OS we use RpcServerRegisterIf and have no callback.
|
|
//
|
|
// The callback will only check for proper ProtSeq.
|
|
// We will check for proper authentication level (RPC_C_AUTHN_LEVEL_PKT_PRIVACY from .NET fax server
|
|
// and no authentication for BOS fax server)
|
|
//
|
|
|
|
|
|
#if defined(WIN95)
|
|
//
|
|
// Win9x OS
|
|
//
|
|
ec = RpcServerRegisterIf (faxclient_ServerIfHandle,
|
|
0,
|
|
0);
|
|
if (RPC_S_OK != ec)
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("RpcServerRegisterIf failed (ec = %lu)"),
|
|
ec);
|
|
goto exit;
|
|
}
|
|
#else
|
|
//
|
|
// NT4 and later OS
|
|
//
|
|
|
|
|
|
if (IsWinXPOS())
|
|
{
|
|
//
|
|
// Running on .NET OS (XP client does not run this code)
|
|
//
|
|
ec = RpcServerRegisterIfEx (faxclient_ServerIfHandle,
|
|
0,
|
|
0,
|
|
RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH,
|
|
RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Relieves the RPC run-time environment from enforcing an unnecessary restriction
|
|
FaxClientSecurityCallBack // CallBack function address
|
|
);
|
|
if (RPC_S_OK != ec)
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("RpcServerRegisterIfEx failed (ec = %lu)"),
|
|
ec);
|
|
goto exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Running on NT4 or Win2K OS
|
|
//
|
|
ec = RpcServerRegisterIf (faxclient_ServerIfHandle,
|
|
0,
|
|
0);
|
|
if (RPC_S_OK != ec)
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("RpcServerRegisterIf failed (ec = %lu)"),
|
|
ec);
|
|
goto exit;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// We use NTLM authentication RPC calls
|
|
//
|
|
ec = RpcServerRegisterAuthInfo (
|
|
(LPUTSTR)TEXT(""), // Igonred by RPC_C_AUTHN_WINNT
|
|
RPC_C_AUTHN_WINNT, // NTLM SPP authenticator
|
|
NULL, // Ignored when using RPC_C_AUTHN_WINNT
|
|
NULL); // Ignored when using RPC_C_AUTHN_WINNT
|
|
if (ec != RPC_S_OK)
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("RpcServerRegisterAuthInfo() failed (ec: %ld)"),
|
|
ec);
|
|
//
|
|
// Unregister the interface if it is the first instance
|
|
//
|
|
RpcStatus = SafeRpcServerUnregisterIf();
|
|
if (RPC_S_OK != RpcStatus)
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("SafeRpcServerUnregisterIf failed. (ec: %ld)"),
|
|
RpcStatus);
|
|
}
|
|
|
|
goto exit;
|
|
}
|
|
|
|
|
|
// The first argument specifies the minimum number of threads to
|
|
// be created to handle calls; the second argument specifies the
|
|
// maximum number of concurrent calls allowed. The last argument
|
|
// indicates not to wait.
|
|
ec = RpcServerListen (1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, 1);
|
|
if (ec != RPC_S_OK)
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("RpcServerListen failed (ec = %ld"),
|
|
ec);
|
|
|
|
//
|
|
// Unregister the interface if it is the first instance
|
|
//
|
|
RpcStatus = SafeRpcServerUnregisterIf();
|
|
if (RPC_S_OK != RpcStatus)
|
|
{
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("SafeRpcServerUnregisterIf failed. (ec: %ld)"),
|
|
RpcStatus);
|
|
}
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
g_dwFaxClientRpcNumInst++;
|
|
|
|
exit:
|
|
LeaveCriticalSection(&g_CsFaxClientRpc);
|
|
return ec;
|
|
}
|
|
|
|
DWORD
|
|
FaxClientBindToFaxServer(
|
|
IN LPCTSTR lpctstrServerName,
|
|
IN LPCTSTR lpctstrServiceName,
|
|
IN LPCTSTR lpctstrNetworkOptions,
|
|
OUT RPC_BINDING_HANDLE * pBindingHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Binds to the RPC server if possible.
|
|
|
|
Arguments:
|
|
|
|
ServerName - Name of server to bind with.
|
|
|
|
ServiceName - Name of service to bind with.
|
|
|
|
pBindingHandle - Location where binding handle is to be placed
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The binding has been successfully completed.
|
|
|
|
STATUS_INVALID_COMPUTER_NAME - The ServerName syntax is invalid.
|
|
|
|
STATUS_NO_MEMORY - There is not sufficient memory available to the
|
|
caller to perform the binding.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
LPTSTR StringBinding;
|
|
LPTSTR Endpoint;
|
|
LPTSTR NewServerName = NULL;
|
|
DWORD dwResult;
|
|
DEBUG_FUNCTION_NAME(TEXT("FaxClientBindToFaxServer"));
|
|
|
|
*pBindingHandle = NULL;
|
|
|
|
if (IsLocalMachineName (lpctstrServerName))
|
|
{
|
|
NewServerName = NULL;
|
|
}
|
|
else
|
|
{
|
|
NewServerName = (LPTSTR)lpctstrServerName;
|
|
}
|
|
//
|
|
// We need to concatenate \pipe\ to the front of the service
|
|
// name.
|
|
//
|
|
Endpoint = (LPTSTR)LocalAlloc(
|
|
0,
|
|
sizeof(NT_PIPE_PREFIX) + TCSSIZE(lpctstrServiceName));
|
|
if (Endpoint == 0)
|
|
{
|
|
dwResult = STATUS_NO_MEMORY;
|
|
goto exit;
|
|
}
|
|
_tcscpy(Endpoint,NT_PIPE_PREFIX);
|
|
_tcscat(Endpoint,lpctstrServiceName);
|
|
|
|
if (!NewServerName)
|
|
{
|
|
//
|
|
// Local connection only - Make sure the service is up
|
|
//
|
|
if (!EnsureFaxServiceIsStarted (NULL))
|
|
{
|
|
dwResult = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("EnsureFaxServiceIsStarted failed (ec = %ld"),
|
|
dwResult);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Wait till the RPC service is up an running
|
|
//
|
|
if (!WaitForServiceRPCServer (60 * 1000))
|
|
{
|
|
dwResult = GetLastError ();
|
|
DebugPrintEx(
|
|
DEBUG_ERR,
|
|
TEXT("WaitForServiceRPCServer failed (ec = %ld"),
|
|
dwResult);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Start RPC connection binding
|
|
//
|
|
RpcStatus = RpcStringBindingCompose(
|
|
0,
|
|
(LPUTSTR)RPC_PROT_SEQ_NP,
|
|
(LPUTSTR)NewServerName,
|
|
(LPUTSTR)Endpoint,
|
|
(LPUTSTR)lpctstrNetworkOptions,
|
|
(LPUTSTR *)&StringBinding);
|
|
LocalFree(Endpoint);
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
dwResult = STATUS_NO_MEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
RpcStatus = RpcBindingFromStringBinding((LPUTSTR)StringBinding, pBindingHandle);
|
|
RpcStringFree((LPUTSTR *)&StringBinding);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
*pBindingHandle = NULL;
|
|
if ( (RpcStatus == RPC_S_INVALID_ENDPOINT_FORMAT)
|
|
|| (RpcStatus == RPC_S_INVALID_NET_ADDR) )
|
|
{
|
|
dwResult = ERROR_INVALID_COMPUTERNAME ;
|
|
goto exit;
|
|
}
|
|
dwResult = STATUS_NO_MEMORY;
|
|
goto exit;
|
|
}
|
|
dwResult = ERROR_SUCCESS;
|
|
|
|
exit:
|
|
return dwResult;
|
|
} // FaxClientBindToFaxServer
|
|
|
|
|
|
|
|
|