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.
764 lines
18 KiB
764 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rpcsvr.c
|
|
|
|
Abstract:
|
|
|
|
RPC server routines
|
|
|
|
Author:
|
|
|
|
Vlad Sadovsky (vlads) 10-Jan-1997
|
|
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
26-Jan-1997 VladS created
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "stiexe.h"
|
|
|
|
#include "device.h"
|
|
#include "conn.h"
|
|
#include "wiapriv.h"
|
|
#include "lockmgr.h"
|
|
|
|
#include <apiutil.h>
|
|
#include <stiapi.h>
|
|
#include <stirpc.h>
|
|
|
|
//
|
|
// Context number used for WIA runtime event clients
|
|
//
|
|
LONG_PTR g_lContextNum = 0;
|
|
|
|
//
|
|
// External prototypes
|
|
//
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
StiApiAccessCheck(
|
|
IN ACCESS_MASK DesiredAccess
|
|
);
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
R_StiApiGetVersion(
|
|
LPCWSTR pszServer,
|
|
DWORD dwReserved,
|
|
DWORD *pdwVersion
|
|
)
|
|
{
|
|
|
|
DWORD dwErr;
|
|
|
|
dwErr = StiApiAccessCheck(STI_GENERIC_READ);
|
|
if (NOERROR != dwErr ) {
|
|
return dwErr;
|
|
}
|
|
|
|
if (!pdwVersion) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
STIMONWPRINTF(TEXT("RPC SUPP: ApiGetVersion called"));
|
|
|
|
*pdwVersion = STI_VERSION;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
R_StiApiOpenDevice(
|
|
LPCWSTR pszServer,
|
|
LPCWSTR pszDeviceName,
|
|
DWORD dwMode,
|
|
DWORD dwAccessRequired,
|
|
DWORD dwProcessId,
|
|
STI_DEVICE_HANDLE *pHandle
|
|
)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
BOOL fRet;
|
|
DWORD dwErr;
|
|
|
|
dwErr = StiApiAccessCheck(STI_GENERIC_READ);
|
|
if (NOERROR != dwErr ) {
|
|
return dwErr;
|
|
}
|
|
|
|
if (!pHandle || !pszDeviceName) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// STIMONWPRINTF(TEXT("RPC SUPP: Open device called"));
|
|
|
|
//
|
|
// Create connection object and get it's handle
|
|
//
|
|
fRet = CreateDeviceConnection(W2CT(pszDeviceName),
|
|
dwMode,
|
|
dwProcessId,
|
|
pHandle
|
|
);
|
|
if (fRet && *pHandle) {
|
|
return NOERROR;
|
|
}
|
|
|
|
*pHandle = INVALID_HANDLE_VALUE;
|
|
|
|
return ::GetLastError();
|
|
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
R_StiApiCloseDevice(
|
|
LPCWSTR pszServer,
|
|
STI_DEVICE_HANDLE hDevice
|
|
)
|
|
{
|
|
|
|
STIMONWPRINTF(TEXT("RPC SUPP: Close device called"));
|
|
|
|
DWORD dwErr;
|
|
|
|
dwErr = StiApiAccessCheck(STI_GENERIC_READ);
|
|
if (NOERROR != dwErr ) {
|
|
return dwErr;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
DebugDumpScheduleList(TEXT("RPC CLose enter"));
|
|
#endif
|
|
|
|
if (DestroyDeviceConnection(hDevice,FALSE) ) {
|
|
#ifdef DEBUG
|
|
DebugDumpScheduleList(TEXT("RPC CLose exit"));
|
|
#endif
|
|
return NOERROR;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
DebugDumpScheduleList(TEXT("RPC CLose exit"));
|
|
#endif
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
VOID
|
|
STI_DEVICE_HANDLE_rundown(
|
|
STI_DEVICE_HANDLE hDevice
|
|
)
|
|
{
|
|
STIMONWPRINTF(TEXT("RPC SUPP: rundown device called"));
|
|
|
|
if (DestroyDeviceConnection(hDevice,TRUE) ) {
|
|
return;
|
|
}
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
R_StiApiSubscribe(
|
|
STI_DEVICE_HANDLE Handle,
|
|
LOCAL_SUBSCRIBE_CONTAINER *lpSubscribe
|
|
)
|
|
{
|
|
|
|
STI_CONN *pConnectionObject;
|
|
BOOL fRet;
|
|
|
|
|
|
DWORD dwErr;
|
|
|
|
dwErr = StiApiAccessCheck(STI_GENERIC_READ);
|
|
if (NOERROR != dwErr ) {
|
|
return dwErr;
|
|
}
|
|
|
|
//
|
|
// Validate contents of subscribe request
|
|
//
|
|
// For this call we need to impersonate , because we will need
|
|
// access to client process handle
|
|
//
|
|
|
|
dwErr = ::RpcImpersonateClient( NULL ) ;
|
|
|
|
if( dwErr == NOERROR ) {
|
|
|
|
//
|
|
// Invoke add subscription method on connection object
|
|
//
|
|
if (!LookupConnectionByHandle(Handle,&pConnectionObject)) {
|
|
dwErr = ERROR_INVALID_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
fRet = pConnectionObject->SetSubscribeInfo(lpSubscribe);
|
|
if (fRet)
|
|
{
|
|
dwErr = NOERROR;
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
pConnectionObject->Release();
|
|
}
|
|
|
|
// Go back. RpcRevertToSelf will always succeed in this case (including low mem conditions etc.)
|
|
// because it is called on the same thread that RpcImpersonateClient was called on. Therefore, the
|
|
// return code is never looked at.
|
|
RPC_STATUS rpcStatus = ::RpcRevertToSelf();
|
|
}
|
|
else {
|
|
// Failed to impersonate
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
R_StiApiGetLastNotificationData(
|
|
STI_DEVICE_HANDLE Handle,
|
|
LPBYTE pData,
|
|
DWORD nSize,
|
|
LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
//
|
|
// Find connection object and if we are subscribed , retreive
|
|
// first waiting message
|
|
//
|
|
STI_CONN *pConnectionObject;
|
|
|
|
DWORD cbNeeded = nSize;
|
|
DWORD dwErr;
|
|
|
|
dwErr = StiApiAccessCheck(STI_GENERIC_READ);
|
|
if (NOERROR != dwErr ) {
|
|
return dwErr;
|
|
}
|
|
|
|
//
|
|
// Validate contents of subscribe request
|
|
//
|
|
|
|
if (!LookupConnectionByHandle(Handle,&pConnectionObject)) {
|
|
return ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
dwErr = pConnectionObject->GetNotification(pData,&cbNeeded);
|
|
|
|
pConnectionObject->Release();
|
|
|
|
if (pcbNeeded) {
|
|
*pcbNeeded = cbNeeded;
|
|
}
|
|
|
|
return dwErr;
|
|
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
R_StiApiUnSubscribe(
|
|
STI_DEVICE_HANDLE Handle
|
|
)
|
|
{
|
|
STI_CONN *pConnectionObject;
|
|
BOOL fRet;
|
|
|
|
DWORD dwErr;
|
|
|
|
dwErr = StiApiAccessCheck(STI_GENERIC_READ);
|
|
if (NOERROR != dwErr ) {
|
|
return( dwErr );
|
|
}
|
|
|
|
|
|
//
|
|
// Validate contents of subscribe request
|
|
//
|
|
// For this call we need to impersonate , because we will need
|
|
// access to client process handle
|
|
//
|
|
|
|
dwErr = ::RpcImpersonateClient( NULL ) ;
|
|
|
|
if( dwErr == NOERROR ) {
|
|
|
|
//
|
|
// Invoke add subscription method on connection object
|
|
//
|
|
if (!LookupConnectionByHandle(Handle,&pConnectionObject)) {
|
|
dwErr = ERROR_INVALID_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
fRet = pConnectionObject->SetSubscribeInfo(NULL);
|
|
if (fRet)
|
|
{
|
|
dwErr = NOERROR;
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
pConnectionObject->Release();
|
|
}
|
|
|
|
// Go back. RpcRevertToSelf will always succeed in this case (including low mem conditions etc.)
|
|
// because it is called on the same thread that RpcImpersonateClient was called on. Therefore, the
|
|
// return code is never looked at.
|
|
RPC_STATUS rpcStatus = ::RpcRevertToSelf();
|
|
}
|
|
else {
|
|
// Failed to impersonate
|
|
}
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
R_StiApiEnableHwNotifications(
|
|
LPCWSTR pszServer,
|
|
LPCWSTR pszDeviceName,
|
|
BOOL bNewState
|
|
)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
ACTIVE_DEVICE *pOpenedDevice;
|
|
BOOL fRet;
|
|
|
|
|
|
DWORD dwErr;
|
|
|
|
dwErr = StiApiAccessCheck(STI_GENERIC_READ);
|
|
if (NOERROR != dwErr ) {
|
|
return dwErr;
|
|
}
|
|
|
|
//
|
|
// Locate device incrementing it's ref count
|
|
//
|
|
pOpenedDevice = g_pDevMan->IsInList(DEV_MAN_IN_LIST_DEV_ID, pszDeviceName);
|
|
if(!pOpenedDevice) {
|
|
// Failed to connect to the device
|
|
return ERROR_DEV_NOT_EXIST ;
|
|
}
|
|
|
|
{
|
|
TAKE_ACTIVE_DEVICE t(pOpenedDevice);
|
|
|
|
if (bNewState) {
|
|
pOpenedDevice->EnableDeviceNotifications();
|
|
}
|
|
else {
|
|
pOpenedDevice->DisableDeviceNotifications();
|
|
}
|
|
}
|
|
|
|
pOpenedDevice->Release();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
DWORD
|
|
R_StiApiGetHwNotificationState(
|
|
LPCWSTR pszServer,
|
|
LPCWSTR pszDeviceName,
|
|
LPDWORD pState
|
|
)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
ACTIVE_DEVICE *pOpenedDevice;
|
|
BOOL fRet;
|
|
|
|
DWORD dwErr;
|
|
|
|
dwErr = StiApiAccessCheck(STI_GENERIC_READ);
|
|
if (NOERROR != dwErr ) {
|
|
return dwErr;
|
|
}
|
|
|
|
//
|
|
// Locate device incrementing it's ref count
|
|
//
|
|
pOpenedDevice = g_pDevMan->IsInList(DEV_MAN_IN_LIST_DEV_ID, pszDeviceName);
|
|
if(!pOpenedDevice) {
|
|
// Failed to connect to the device
|
|
return ERROR_DEV_NOT_EXIST ;
|
|
}
|
|
|
|
if (pOpenedDevice->QueryFlags() & STIMON_AD_FLAG_NOTIFY_ENABLED) {
|
|
*pState = TRUE;
|
|
}
|
|
else {
|
|
*pState = FALSE;
|
|
}
|
|
|
|
pOpenedDevice->Release();
|
|
|
|
return NOERROR;
|
|
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
R_StiApiLaunchApplication(
|
|
LPCWSTR pszServer,
|
|
LPCWSTR pszDeviceName,
|
|
LPCWSTR pAppName,
|
|
LPSTINOTIFY pStiNotify
|
|
)
|
|
{
|
|
|
|
USES_CONVERSION;
|
|
|
|
ACTIVE_DEVICE *pOpenedDevice;
|
|
BOOL fRet;
|
|
DWORD dwError;
|
|
|
|
|
|
DWORD dwErr;
|
|
|
|
dwErr = StiApiAccessCheck(STI_GENERIC_READ | STI_GENERIC_EXECUTE);
|
|
if (NOERROR != dwErr ) {
|
|
return dwErr;
|
|
}
|
|
|
|
//
|
|
// Locate device incrementing it's ref count
|
|
//
|
|
pOpenedDevice = g_pDevMan->IsInList(DEV_MAN_IN_LIST_DEV_ID, pszDeviceName);
|
|
if(!pOpenedDevice) {
|
|
// Failed to connect to the device
|
|
return ERROR_DEV_NOT_EXIST ;
|
|
}
|
|
|
|
//
|
|
// Attempt to launch registered application
|
|
//
|
|
{
|
|
TAKE_ACTIVE_DEVICE t(pOpenedDevice);
|
|
|
|
fRet = pOpenedDevice->ProcessEvent(pStiNotify,TRUE,W2CT(pAppName));
|
|
|
|
dwError = fRet ? NOERROR : pOpenedDevice->QueryError();
|
|
}
|
|
|
|
pOpenedDevice->Release();
|
|
|
|
return dwError;
|
|
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
R_StiApiLockDevice(
|
|
LPCWSTR pszServer,
|
|
LPCWSTR pszDeviceName,
|
|
DWORD dwWait,
|
|
BOOL bInServerProcess,
|
|
DWORD dwClientThreadId
|
|
)
|
|
{
|
|
BSTR bstrDevName = SysAllocString(pszDeviceName);
|
|
DWORD dwError = 0;
|
|
|
|
|
|
if (bstrDevName) {
|
|
|
|
dwError = (DWORD) g_pStiLockMgr->RequestLock(bstrDevName,
|
|
(ULONG) dwWait,
|
|
bInServerProcess,
|
|
dwClientThreadId);
|
|
|
|
SysFreeString(bstrDevName);
|
|
} else {
|
|
dwError = (DWORD) E_OUTOFMEMORY;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
R_StiApiUnlockDevice(
|
|
LPCWSTR pszServer,
|
|
LPCWSTR pszDeviceName,
|
|
BOOL bInServerProcess,
|
|
DWORD dwClientThreadId
|
|
|
|
)
|
|
{
|
|
BSTR bstrDevName = SysAllocString(pszDeviceName);
|
|
DWORD dwError = 0;
|
|
|
|
|
|
if (bstrDevName) {
|
|
dwError = (DWORD) g_pStiLockMgr->RequestUnlock(bstrDevName,
|
|
bInServerProcess,
|
|
dwClientThreadId);
|
|
SysFreeString(bstrDevName);
|
|
} else {
|
|
dwError = (DWORD) E_OUTOFMEMORY;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
void
|
|
R_WiaGetEventDataAsync(IN PRPC_ASYNC_STATE pAsync,
|
|
RPC_BINDING_HANDLE hBinding,
|
|
WIA_ASYNC_EVENT_NOTIFY_DATA *pEvent
|
|
)
|
|
{
|
|
RPC_STATUS status;
|
|
|
|
EnterCriticalSection(&g_RpcEvent.cs);
|
|
|
|
if(g_RpcEvent.pAsync) {
|
|
status = RpcAsyncAbortCall(g_RpcEvent.pAsync, RPC_S_CALL_CANCELLED);
|
|
}
|
|
|
|
g_RpcEvent.pAsync = pAsync;
|
|
g_RpcEvent.pEvent = pEvent;
|
|
|
|
LeaveCriticalSection(&g_RpcEvent.cs);
|
|
}
|
|
|
|
void WiaGetRuntimetEventDataAsync(
|
|
IN PRPC_ASYNC_STATE pAsync,
|
|
RPC_BINDING_HANDLE hBinding,
|
|
STI_CLIENT_CONTEXT ClientContext,
|
|
WIA_ASYNC_EVENT_NOTIFY_DATA *pWIA_ASYNC_EVENT_NOTIFY_DATA)
|
|
{
|
|
DWORD dwStatus = RPC_S_OK;
|
|
|
|
//
|
|
// Do Validation.
|
|
//
|
|
if (!pAsync)
|
|
{
|
|
DBG_ERR(("StiRpc Error: Client specified NULL Async State structure!!"));
|
|
dwStatus = RPC_S_INVALID_ARG;
|
|
}
|
|
if (!pWIA_ASYNC_EVENT_NOTIFY_DATA)
|
|
{
|
|
DBG_ERR(("StiRpc Error: Client specified NULL WIA_ASYNC_EVENT_NOTIFY_DATA structure!!"));
|
|
dwStatus = RPC_S_INVALID_ARG;
|
|
}
|
|
|
|
if (dwStatus == RPC_S_OK)
|
|
{
|
|
if (g_pWiaEventNotifier)
|
|
{
|
|
//
|
|
// Find the client
|
|
//
|
|
AsyncRPCEventClient *pWiaEventClient = (AsyncRPCEventClient*)g_pWiaEventNotifier->GetClientFromContext(ClientContext);
|
|
if (pWiaEventClient)
|
|
{
|
|
HRESULT hr = pWiaEventClient->saveAsyncParams(pAsync, pWIA_ASYNC_EVENT_NOTIFY_DATA);
|
|
//
|
|
// Release pWiaEventClient now that we're done
|
|
//
|
|
pWiaEventClient->Release();
|
|
dwStatus = RPC_S_OK;
|
|
}
|
|
else
|
|
{
|
|
DBG_ERR(("StiRpc Error: Client %p was not found, cannot update reg info", ClientContext));
|
|
dwStatus = RPC_S_INVALID_ARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBG_ERR(("StiRpc Error: The WiaEventNotifier is NULL"));
|
|
dwStatus = RPC_S_INVALID_ARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwStatus = RPC_S_INVALID_ARG;
|
|
}
|
|
|
|
//
|
|
// Abort the call if we could not save the async parameters
|
|
//
|
|
if (dwStatus != RPC_S_OK)
|
|
{
|
|
RPC_STATUS rpcStatus = RpcAsyncAbortCall(pAsync, dwStatus);
|
|
}
|
|
}
|
|
|
|
|
|
DWORD OpenClientConnection(
|
|
handle_t hBinding,
|
|
STI_CLIENT_CONTEXT *pSyncClientContext,
|
|
STI_CLIENT_CONTEXT *pAsyncClientContext)
|
|
{
|
|
DWORD dwStatus = RPC_S_OK;
|
|
|
|
if (pSyncClientContext && pAsyncClientContext)
|
|
{
|
|
*pSyncClientContext = (STI_CLIENT_CONTEXT)NativeInterlockedIncrement(&g_lContextNum);
|
|
*pAsyncClientContext = *pSyncClientContext;
|
|
DBG_TRC(("Opened client connection for %p", *pAsyncClientContext));
|
|
if (g_pWiaEventNotifier)
|
|
{
|
|
WiaEventClient *pWiaEventClient = new AsyncRPCEventClient(*pSyncClientContext);
|
|
if (pWiaEventClient)
|
|
{
|
|
//
|
|
// Add the client
|
|
//
|
|
dwStatus = g_pWiaEventNotifier->AddClient(pWiaEventClient);
|
|
if (SUCCEEDED(dwStatus))
|
|
{
|
|
dwStatus = RPC_S_OK;
|
|
}
|
|
//
|
|
// We can release the client object here. If the WiaEventNotifier successfully
|
|
// added it to its list of clients, it would have AddRef'd it. If it wasn't successful,
|
|
// we want to destory it here anyway.
|
|
//
|
|
pWiaEventClient->Release();
|
|
}
|
|
else
|
|
{
|
|
dwStatus = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwStatus = RPC_S_INVALID_ARG;
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
VOID STI_CLIENT_CONTEXT_rundown(
|
|
STI_CLIENT_CONTEXT ClientContext)
|
|
{
|
|
DBG_TRC(("Rundown called for %p", ClientContext));
|
|
|
|
//
|
|
// TBD: Check if client exists, then remove it if the connection hasn't been
|
|
// closed correctly.
|
|
//
|
|
|
|
if (g_pWiaEventNotifier)
|
|
{
|
|
g_pWiaEventNotifier->MarkClientForRemoval(ClientContext);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
DWORD CloseClientConnection(
|
|
handle_t hBinding,
|
|
STI_CLIENT_CONTEXT ClientContext)
|
|
{
|
|
//
|
|
// TBD: Remove objects used to keep track of client
|
|
//
|
|
|
|
DBG_TRC(("Closed connection for %p", ClientContext));
|
|
|
|
STI_CLIENT_CONTEXT_rundown(ClientContext);
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
DWORD RegisterUnregisterForEventNotification(
|
|
handle_t hBinding,
|
|
STI_CLIENT_CONTEXT ClientContext,
|
|
WIA_ASYNC_EVENT_REG_DATA *pWIA_ASYNC_EVENT_REG_DATA)
|
|
{
|
|
DWORD dwStatus = RPC_S_OK;
|
|
if (g_pWiaEventNotifier)
|
|
{
|
|
if (pWIA_ASYNC_EVENT_REG_DATA)
|
|
{
|
|
//
|
|
// Find the client
|
|
//
|
|
WiaEventClient *pWiaEventClient = g_pWiaEventNotifier->GetClientFromContext(ClientContext);
|
|
|
|
if (pWiaEventClient)
|
|
{
|
|
EventRegistrationInfo *pEventRegistrationInfo = new EventRegistrationInfo(pWIA_ASYNC_EVENT_REG_DATA->dwFlags,
|
|
pWIA_ASYNC_EVENT_REG_DATA->guidEvent,
|
|
pWIA_ASYNC_EVENT_REG_DATA->bstrDeviceID,
|
|
pWIA_ASYNC_EVENT_REG_DATA->ulCallback);
|
|
if (pEventRegistrationInfo)
|
|
{
|
|
//
|
|
// Update its event registration info
|
|
//
|
|
dwStatus = pWiaEventClient->RegisterUnregisterForEventNotification(pEventRegistrationInfo);
|
|
|
|
pEventRegistrationInfo->Release();
|
|
}
|
|
else
|
|
{
|
|
DBG_ERR(("StiRpc Error: Cannot update reg info - we appear to be out of memory"));
|
|
dwStatus = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
//
|
|
// Release pWiaEventClient now that we're done
|
|
//
|
|
pWiaEventClient->Release();
|
|
}
|
|
else
|
|
{
|
|
DBG_ERR(("StiRpc Error: Client %p was not found, cannot update reg info", ClientContext));
|
|
dwStatus = RPC_S_INVALID_ARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBG_ERR(("StiRpc Error: Received NULL event reg data from RPC"));
|
|
dwStatus = RPC_S_INVALID_ARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBG_ERR(("StiRpc Error: WiaEventNotifier is NULL"));
|
|
dwStatus = RPC_S_INVALID_ARG;
|
|
}
|
|
return dwStatus;
|
|
}
|
|
|