/*++ 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 #include #include // // 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; }