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.
284 lines
9.1 KiB
284 lines
9.1 KiB
/*
|
|
* OPREQ.C
|
|
*
|
|
* RSM Service : Operator Requests
|
|
*
|
|
* Author: ErvinP
|
|
*
|
|
* (c) 2001 Microsoft Corporation
|
|
*
|
|
*/
|
|
|
|
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <wtypes.h>
|
|
#include <objbase.h>
|
|
|
|
#include <ntmsapi.h>
|
|
#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;
|
|
}
|