/* * OPREQ.C * * RSM Service : Operator Requests * * Author: ErvinP * * (c) 2001 Microsoft Corporation * */ #include #include #include #include #include #include "internal.h" #include "resource.h" #include "debug.h" OPERATOR_REQUEST *NewOperatorRequest( DWORD dwRequest, LPCWSTR lpMessage, LPNTMS_GUID lpArg1Id, LPNTMS_GUID lpArg2Id) { OPERATOR_REQUEST *newOpReq; newOpReq = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, sizeof(OPERATOR_REQUEST)); if (newOpReq){ newOpReq->completedEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (newOpReq->completedEvent){ InitializeListHead(&newOpReq->sessionOpReqsListEntry); newOpReq->opRequestCommand = dwRequest; newOpReq->state = NTMS_OPSTATE_UNKNOWN; WStrNCpy((WCHAR *)newOpReq->appMessage, (WCHAR *)lpMessage, sizeof(newOpReq->appMessage)/sizeof(WCHAR)); memcpy(&newOpReq->arg1Guid, lpArg1Id, sizeof(NTMS_GUID)); memcpy(&newOpReq->arg2Guid, lpArg2Id, sizeof(NTMS_GUID)); #if 0 // BUGBUG - do this in RSM Monitor app ? /* * Initialize the NOTIFYICONDATA structure * for the message display (used in the Shell_NotifyIcon call). * Make it hidden initially. * BUGBUG - make this work with RSM monitor (need hWnd and callback msg id) */ newOpReq->notifyData.cbSize = sizeof(NOTIFYICONDATA); newOpReq->notifyData.hWnd = NULL; newOpReq->notifyData.uID = (ULONG_PTR)newOpReq; newOpReq->notifyData.uFlags = NIF_ICON | NIF_TIP | NIF_STATE; newOpReq->notifyData.uCallbackMessage = 0; newOpReq->notifyData.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_OPREQ_ICON)); LoadString(g_hInstanceMonitor, IDS_OPTIP, newOpReq->notifyData.szTip, sizeof(newOpReq->notifyData.szTip)/sizeof(TCHAR)); newOpReq->notifyData.dwState = NIS_HIDDEN; newOpReq->notifyData.dwStateMask = NIS_HIDDEN; LoadString(g_hInstanceMonitor, IDS_OPINFO, newOpReq->notifyData.szInfo, sizeof(newOpReq->notifyData.szInfo)/sizeof(TCHAR)); newOpReq->notifyData.uTimeout = 60000; // 1 minute LoadString(g_hInstanceMonitor, IDS_OPTIP, newOpReq->notifyData.szInfoTitle, sizeof(newOpReq->notifyData.szInfoTitle)/sizeof(TCHAR)); newOpReq->notifyData.dwInfoFlags = NIIF_INFO; Shell_NotifyIcon(NIM_ADD, &newOpReq->notifyData); #endif /* * Create a unique identifier for this op request */ CoCreateGuid(&newOpReq->opReqGuid); } else { FreeOperatorRequest(newOpReq); newOpReq = NULL; } } ASSERT(newOpReq); return newOpReq; } VOID FreeOperatorRequest(OPERATOR_REQUEST *opReq) { ASSERT(IsListEmpty(&opReq->sessionOpReqsListEntry)); if (opReq->completedEvent) CloseHandle(opReq->completedEvent); // BUGBUG ? if (opReq->notifyData.hIcon) DestroyIcon(opReq->notifyData.hIcon); GlobalFree(opReq); } BOOL EnqueueOperatorRequest(SESSION *thisSession, OPERATOR_REQUEST *opReq) { DWORD threadId; BOOL ok = FALSE; #if 0 // BUGBUG - do this in RSM Monitor app ? /* * Make the notification display visible on the tray */ newOpReq->notifyData.uFlags = NIF_MESSAGE | NIF_INFO | NIF_STATE; newOpReq->notifyData.dwState = 0; newOpReq->notifyData.uTimeout = 60000; // 1 minute Shell_NotifyIcon(NIM_MODIFY, &newOpReq->notifyData); #endif // BUGBUG FINISH - make rsm monitor put up dialog UI for op req msg opReq->invokingSession = thisSession; GetSystemTime(&opReq->timeSubmitted); EnterCriticalSection(&thisSession->lock); // BUGBUG - I don't think we need an op request thread opReq->hThread = CreateThread(NULL, 0, OperatorRequestThread, opReq, 0, &threadId); if (opReq->hThread){ InsertTailList(&thisSession->operatorRequestList, &opReq->sessionOpReqsListEntry); opReq->state = NTMS_OPSTATE_SUBMITTED; ok = TRUE; } else { ASSERT(opReq->hThread); } LeaveCriticalSection(&thisSession->lock); return ok; } /* * DequeueOperatorRequest * * Callable 3 ways: * dequeue given op request (specificOpReq non-null) * dequeue op request with given GUID (specificOpReqGuid non-null) * dequeue first op request (both NULL) */ OPERATOR_REQUEST *DequeueOperatorRequest( SESSION *thisSession, OPERATOR_REQUEST *specificOpReq, LPNTMS_GUID specificOpReqGuid) { OPERATOR_REQUEST *opReq; LIST_ENTRY *listEntry; /* * If an op request is passed in, dequeue that one. * Else, dequeue the first. */ EnterCriticalSection(&thisSession->lock); if (specificOpReq){ ASSERT(!IsListEmpty(&specificOpReq->sessionOpReqsListEntry)); ASSERT(!IsListEmpty(&thisSession->operatorRequestList)); RemoveEntryList(&specificOpReq->sessionOpReqsListEntry); InitializeListHead(&specificOpReq->sessionOpReqsListEntry); opReq = specificOpReq; } else if (specificOpReqGuid){ opReq = FindOperatorRequest(thisSession, specificOpReqGuid); if (opReq){ RemoveEntryList(&opReq->sessionOpReqsListEntry); } } else { if (IsListEmpty(&thisSession->operatorRequestList)){ opReq = NULL; } else { listEntry = RemoveHeadList(&thisSession->operatorRequestList); opReq = CONTAINING_RECORD(listEntry, OPERATOR_REQUEST, sessionOpReqsListEntry); } } LeaveCriticalSection(&thisSession->lock); return opReq; } /* * FindOperatorRequest * * ** Must be called with session lock held */ OPERATOR_REQUEST *FindOperatorRequest(SESSION *thisSession, LPNTMS_GUID opReqGuid) { OPERATOR_REQUEST *opReq = NULL; LIST_ENTRY *listEntry; listEntry = &thisSession->operatorRequestList; while ((listEntry = listEntry->Flink) != &thisSession->operatorRequestList){ OPERATOR_REQUEST *thisOpReq = CONTAINING_RECORD(listEntry, OPERATOR_REQUEST, sessionOpReqsListEntry); if (RtlEqualMemory(&thisOpReq->opReqGuid, opReqGuid, sizeof(NTMS_GUID))){ opReq = thisOpReq; break; } } return opReq; } /* * CompleteOperatorRequest * * Complete and free the op request, synchronizing with any threads * waiting on its completion. */ HRESULT CompleteOperatorRequest( SESSION *thisSession, LPNTMS_GUID lpRequestId, enum NtmsOpreqState completeState) { HRESULT result; if (lpRequestId){ OPERATOR_REQUEST *opReq; opReq = DequeueOperatorRequest(thisSession, NULL, lpRequestId); if (opReq){ /* * Remove the notification display from the tray */ // BUGBUG - do this in RSM Monitor app ? // Shell_NotifyIcon(NIM_DELETE, &opReq->notifyData); /* * Make sure there are no threads waiting on the * operator request before freeing it. */ EnterCriticalSection(&thisSession->lock); /* * Kill the op request thread */ TerminateThread(opReq->hThread, ERROR_SUCCESS); CloseHandle(opReq->hThread); /* * There may be some threads waiting in WaitForNtmsOperatorRequest * for this op request to complete. Need to flush them * before freeing the op request. */ opReq->state = completeState; SetEvent(opReq->completedEvent); /* * Drop the lock and wait for the waiting threads to exit. */ while (opReq->numWaitingThreads > 0){ LeaveCriticalSection(&thisSession->lock); Sleep(1); EnterCriticalSection(&thisSession->lock); } LeaveCriticalSection(&thisSession->lock); FreeOperatorRequest(opReq); result = ERROR_SUCCESS; } else { result = ERROR_OBJECT_NOT_FOUND; } } else { ASSERT(lpRequestId); result = ERROR_INVALID_PARAMETER; } return result; } // BUGBUG - I don't think we need an op request thread DWORD __stdcall OperatorRequestThread(void *context) { OPERATOR_REQUEST *opReq = (OPERATOR_REQUEST *)context; return NO_ERROR; }