454 lines
11 KiB
C++
454 lines
11 KiB
C++
/*==========================================================================
|
|
*
|
|
* Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: DPLMsgQ.h
|
|
* Content: DirectPlay Lobby Message Queues Header File
|
|
*@@BEGIN_MSINTERNAL
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 02/21/00 mjn Created
|
|
* 04/26/00 mjn Fixed AddData() to return HRESULT
|
|
* 07/07/2000 rmt
|
|
*@@END_MSINTERNAL
|
|
*
|
|
***************************************************************************/
|
|
|
|
|
|
#ifndef __DPLMSGQ_H__
|
|
#define __DPLMSGQ_H__
|
|
|
|
//**********************************************************************
|
|
// Constant definitions
|
|
//**********************************************************************
|
|
|
|
//
|
|
// Message Queue Object IDs
|
|
//
|
|
#define DPL_MSGQ_OBJECT_IDCHAR_FILEMAP 'F'
|
|
#define DPL_MSGQ_OBJECT_IDCHAR_MUTEX 'M'
|
|
#define DPL_MSGQ_OBJECT_IDCHAR_EVENT 'E'
|
|
#define DPL_MSGQ_OBJECT_IDCHAR_EVENT2 'V'
|
|
#define DPL_MSGQ_OBJECT_IDCHAR_SEMAPHORE 'S'
|
|
|
|
//
|
|
// Message Queue Object Suffixes
|
|
//
|
|
#define DPL_MSGQ_OBJECT_SUFFIX_CLIENT 'C'
|
|
#define DPL_MSGQ_OBJECT_SUFFIX_APPLICATION 'A'
|
|
|
|
//
|
|
// Message Queue Flags
|
|
//
|
|
#define DPL_MSGQ_FLAG_AVAILABLE 0x00001
|
|
#define DPL_MSGQ_FLAG_RECEIVING 0x00010
|
|
|
|
#define DPL_MSGQ_OPEN_FLAG_NO_CREATE 0x10000
|
|
|
|
//
|
|
// Message Queue File Size
|
|
//
|
|
// Increased so user can send a 64K message
|
|
#define DPL_MSGQ_SIZE 0x010030
|
|
|
|
//
|
|
// Internal Message IDs
|
|
//
|
|
#define DPL_MSGQ_MSGID_SEND 0x0001
|
|
#define DPL_MSGQ_MSGID_TERMINATE 0x0003
|
|
#define DPL_MSGQ_MSGID_IDLE 0x0004
|
|
|
|
#define DPL_MSGQ_MSGFLAGS_QUEUESYSTEM 0x0001
|
|
#define DPL_MSGQ_MSGFLAGS_USER1 0x0002
|
|
#define DPL_MSGQ_MSGFLAGS_USER2 0x0004
|
|
|
|
#define DPL_MSGQ_SIGNATURE 'QMLD'
|
|
|
|
#undef DPF_SUBCOMP
|
|
#define DPF_SUBCOMP DN_SUBCOMP_LOBBY
|
|
|
|
//**********************************************************************
|
|
// Macro definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Structure definitions
|
|
//**********************************************************************
|
|
|
|
#pragma pack(push,4)
|
|
//
|
|
// Message Queue File Map Info
|
|
//
|
|
typedef struct _DPL_MSGQ_INFO
|
|
{
|
|
DWORD dwFlags; // Queue usage flags
|
|
DWORD dwStartOffset;
|
|
DWORD dwEndOffset;
|
|
DWORD dwFreeBytes;
|
|
DWORD dwQueueSize;
|
|
LONG lRefCount; // Number of connections
|
|
} DPL_MSGQ_INFO, *PDPL_MSGQ_INFO;
|
|
|
|
|
|
//
|
|
// Message Queue Send Message
|
|
//
|
|
typedef struct _DPL_MSGQ_SEND
|
|
{
|
|
DWORD dwCurrentSize; // Size of this frame (in BYTES)
|
|
DWORD dwTotalSize; // Total size of message
|
|
DWORD dwMsgId; // Message ID
|
|
DPNHANDLE hSender;
|
|
DWORD dwFlags;
|
|
DWORD dwCurrentOffset; // Offset of this frame in message
|
|
} DPL_MSGQ_HEADER, *PDPL_MSGQ_HEADER;
|
|
|
|
//
|
|
// Message Queue Terminate Message
|
|
//
|
|
typedef struct _DPL_MSGQ_TERMINATE
|
|
{
|
|
DWORD dwMsgId;
|
|
} DPL_MSGQ_TERMINATE, *PDPL_MSGQ_TERMINATE;
|
|
|
|
#pragma pack(pop)
|
|
|
|
//
|
|
// Message Handler Callback
|
|
//
|
|
typedef HRESULT (*PFNDPLMSGQMESSAGEHANDLER)(PVOID,const DPNHANDLE,DWORD, BYTE *const,const DWORD);
|
|
|
|
//**********************************************************************
|
|
// Variable definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Function prototypes
|
|
//**********************************************************************
|
|
|
|
BOOL DPLIsApplicationAvailable(const DWORD dwPid);
|
|
HRESULT DPLMakeApplicationUnavailable(const DWORD dwPid);
|
|
DWORD WINAPI DPLProcessMessageQueue(PVOID pvReceiveQueue);
|
|
|
|
//**********************************************************************
|
|
// Class prototypes
|
|
//**********************************************************************
|
|
|
|
class CMessageQueue
|
|
{
|
|
public:
|
|
CMessageQueue()
|
|
{
|
|
m_dwPID = 0;
|
|
m_hFileMap = NULL;
|
|
m_hEvent = NULL;
|
|
m_hMutex = NULL;
|
|
m_hSemaphore = NULL;
|
|
m_pFileMapAddress = NULL;
|
|
m_pInfo = NULL;
|
|
m_pvContext = NULL;
|
|
m_pfnMessageHandler = NULL;
|
|
m_hSender = 0xFFFFFFFF;
|
|
m_hReceiveThreadRunningEvent = NULL;
|
|
m_dwIdleTimeout = INFINITE;
|
|
};
|
|
|
|
~CMessageQueue() { };
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::SetMessageHandler"
|
|
void CMessageQueue::SetMessageHandler(PVOID pvContext,PFNDPLMSGQMESSAGEHANDLER pfn )
|
|
{
|
|
DNASSERT(pfn != NULL);
|
|
|
|
m_pvContext = pvContext;
|
|
m_pfnMessageHandler = pfn;
|
|
};
|
|
|
|
void CMessageQueue::SetSenderHandle(DPNHANDLE hSender)
|
|
{
|
|
m_hSender = hSender;
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::CallMessageHandler"
|
|
HRESULT CMessageQueue::CallMessageHandler(const DPNHANDLE hSender,
|
|
DWORD dwMessageFlags,
|
|
BYTE *const pBuffer,
|
|
const DWORD dwBufferSize)
|
|
{
|
|
DNASSERT(m_pfnMessageHandler != NULL);
|
|
|
|
return((m_pfnMessageHandler)(m_pvContext,hSender,dwMessageFlags,pBuffer,dwBufferSize));
|
|
};
|
|
|
|
HRESULT CMessageQueue::Open(const DWORD dwPID,
|
|
const CHAR cSuffix,
|
|
const DWORD dwQueueSize,
|
|
const DWORD dwIdleTimeout,
|
|
const DWORD dwFlags
|
|
);
|
|
|
|
void CMessageQueue::Close(void);
|
|
|
|
LONG CMessageQueue::GetRefCount(void)
|
|
{
|
|
DWORD lRefCount;
|
|
|
|
if (m_pInfo == NULL)
|
|
return(0);
|
|
|
|
Lock();
|
|
lRefCount = m_pInfo->lRefCount;
|
|
Unlock();
|
|
|
|
return(lRefCount);
|
|
};
|
|
|
|
HRESULT CMessageQueue::AddData(BYTE *const pBuffer,
|
|
const DWORD dwSize);
|
|
|
|
|
|
HRESULT CMessageQueue::Send(BYTE *const pBuffer,
|
|
const DWORD dwSize,
|
|
const DWORD dwTimeOut,
|
|
const DWORD dwMessageFlags,
|
|
const DWORD dwFlags);
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::Lock"
|
|
void CMessageQueue::Lock(void)
|
|
{
|
|
DNASSERT(m_hMutex != NULL);
|
|
WaitForSingleObject(m_hMutex,INFINITE);
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::Unlock"
|
|
void CMessageQueue::Unlock(void)
|
|
{
|
|
DNASSERT(m_hMutex != NULL);
|
|
ReleaseMutex(m_hMutex);
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::WaitForMessages"
|
|
DWORD CMessageQueue::WaitForMessages(void)
|
|
{
|
|
DNASSERT(m_hSemaphore != NULL);
|
|
return WaitForSingleObject(m_hSemaphore,m_dwIdleTimeout);
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::IndicateMessage"
|
|
void CMessageQueue::IndicateMessage(void)
|
|
{
|
|
DNASSERT(m_hSemaphore != NULL);
|
|
ReleaseSemaphore(m_hSemaphore,1,NULL);
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::WaitForConsumption"
|
|
BOOL CMessageQueue::WaitForConsumption(const DWORD dwTimeOut)
|
|
{
|
|
DWORD dwError;
|
|
|
|
DNASSERT(m_hEvent != NULL);
|
|
dwError = WaitForSingleObject(m_hEvent,dwTimeOut);
|
|
if (dwError==WAIT_OBJECT_0)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::IndicateConsumption"
|
|
void CMessageQueue::IndicateConsumption(void)
|
|
{
|
|
DNASSERT(m_hEvent != NULL);
|
|
//SetEvent(m_hEvent); // Will auto-reset (i.e. pulse)
|
|
|
|
ReleaseSemaphore( m_hEvent, 1, NULL );
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::MakeAvailable"
|
|
void CMessageQueue::MakeAvailable(void)
|
|
{
|
|
DNASSERT(m_pInfo != NULL);
|
|
|
|
Lock();
|
|
|
|
m_pInfo->dwFlags |= DPL_MSGQ_FLAG_AVAILABLE;
|
|
|
|
Unlock();
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::MakeUnavailable"
|
|
HRESULT CMessageQueue::MakeUnavailable(void)
|
|
{
|
|
|
|
HRESULT hResultCode;
|
|
|
|
DNASSERT(m_pInfo != NULL);
|
|
|
|
Lock();
|
|
|
|
if (m_pInfo->dwFlags & DPL_MSGQ_FLAG_AVAILABLE)
|
|
{
|
|
m_pInfo->dwFlags &= (~DPL_MSGQ_FLAG_AVAILABLE);
|
|
hResultCode = DPN_OK;
|
|
}
|
|
else
|
|
{
|
|
hResultCode = DPNERR_ALREADYCONNECTED;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return(hResultCode);
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::MakeReceiving"
|
|
void CMessageQueue::MakeReceiving(void)
|
|
{
|
|
DNASSERT(m_pInfo != NULL);
|
|
|
|
Lock();
|
|
m_pInfo->dwFlags |= DPL_MSGQ_FLAG_RECEIVING;
|
|
Unlock();
|
|
SetEvent(m_hReceiveThreadRunningEvent);
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::MakeNotReceiving"
|
|
void CMessageQueue::MakeNotReceiving(void)
|
|
{
|
|
DNASSERT(m_pInfo != NULL);
|
|
|
|
ResetEvent(m_hReceiveThreadRunningEvent);
|
|
Lock();
|
|
m_pInfo->dwFlags &= (~DPL_MSGQ_FLAG_RECEIVING);
|
|
Unlock();
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::WaitForReceiveThread"
|
|
BOOL CMessageQueue::WaitForReceiveThread(const DWORD dwTimeOut)
|
|
{
|
|
DWORD dwError;
|
|
|
|
DNASSERT(m_hEvent != NULL);
|
|
dwError = WaitForSingleObject(m_hReceiveThreadRunningEvent,dwTimeOut);
|
|
if (dwError==WAIT_OBJECT_0)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::IsOpen"
|
|
BOOL CMessageQueue::IsOpen(void)
|
|
{
|
|
if (m_hFileMap!= NULL) return(TRUE);
|
|
else return(FALSE);
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::IsAvailable"
|
|
BOOL CMessageQueue::IsAvailable(void)
|
|
{
|
|
DNASSERT(m_pInfo != NULL);
|
|
|
|
if (m_pInfo->dwFlags & DPL_MSGQ_FLAG_AVAILABLE)
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::IsReceiving"
|
|
BOOL CMessageQueue::IsReceiving(void)
|
|
{
|
|
DNASSERT(m_pInfo != NULL);
|
|
|
|
if (m_pInfo->dwFlags & DPL_MSGQ_FLAG_RECEIVING)
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
};
|
|
|
|
HRESULT GetNextMessage( PDPL_MSGQ_HEADER pMsgHeader, PBYTE pbPayload, DWORD *pdwBufferSize );
|
|
|
|
/*
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CMessageQueue::Realign"
|
|
void CMessageQueue::Realign(void)
|
|
{
|
|
DNASSERT(m_pInfo != NULL);
|
|
|
|
m_pInfo->dwFirstMsgOffset = 0;
|
|
m_pInfo->dwFreeSpaceAtEnd = m_pInfo->dwTotalUsableSpace
|
|
- (m_pInfo->dwNextFreeOffset - m_pInfo->dwFirstMsgOffset);
|
|
m_pInfo->dwTotalFreeSpace = m_pInfo->dwFreeSpaceAtEnd;
|
|
|
|
};*/
|
|
|
|
void CMessageQueue::Terminate(void);
|
|
|
|
|
|
private:
|
|
|
|
// GetData
|
|
//
|
|
// Get dwSize bytes from the queue. If the queue is empty this function will return
|
|
// DPNERR_DOESNOTEXIST. Once this function returns the dwSize bytes will be consumed
|
|
//
|
|
// Needs LOCK()
|
|
//
|
|
HRESULT GetData( BYTE *pbData, DWORD dwSize );
|
|
|
|
// Consume
|
|
//
|
|
// Marks dwSize bytes as consumed
|
|
//
|
|
// Needs LOCK()
|
|
void Consume( const DWORD dwSize );
|
|
|
|
DWORD m_dwSig; // Signature (ensure initialized)
|
|
DWORD m_dwPID; // Queue PID
|
|
PBYTE m_pFileMapAddress; // File Mapping address
|
|
DPL_MSGQ_INFO *m_pInfo; // Message queue file mapping info
|
|
PBYTE m_pData; // Message data starts here
|
|
|
|
HANDLE m_hReceiveThreadRunningEvent;
|
|
|
|
// Notes:
|
|
// Each message queue has four shared memory items: file map, mutex, event, semaphore.
|
|
// The file map is a circular queue of messages.
|
|
// The mutex controls access to the file map.
|
|
// The event signals when an item has been taken off the queue by the consumer.
|
|
// The semaphore indicates to the consumer that there are messages in the queue
|
|
|
|
HANDLE m_hFileMap; // File Mapping handle
|
|
HANDLE m_hMutex; // Mutex handle
|
|
HANDLE m_hEvent; // Event handle
|
|
HANDLE m_hSemaphore; // Semaphore handle
|
|
|
|
PFNDPLMSGQMESSAGEHANDLER m_pfnMessageHandler;
|
|
PVOID m_pvContext;
|
|
|
|
DPNHANDLE m_hSender; // For all SEND messages
|
|
|
|
DWORD m_dwIdleTimeout; // Amount of time between idle messages
|
|
};
|
|
|
|
#undef DPF_MODNAME
|
|
|
|
#endif // __DPLMSGQ_H__
|