📄 event.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
//=--------------------------------------------------------------------------=
// event.Cpp
//=--------------------------------------------------------------------------=
//
// the MSMQEvent object
//
//
#include "IPServer.H"
#include "LocalObj.H"
#include "dispids.h"
#include "globals.h" // for framework globals
#include "oautil.h"
#include "event.h"
#include "msg.h"
#include "q.h"
// for ASSERT and FAIL
//
SZTHISFILE
// debug...
#define new DEBUG_NEW
#if DEBUG
#define SysAllocString DebSysAllocString
#define SysReAllocString DebSysReAllocString
#define SysFreeString DebSysFreeString
#endif // DEBUG
#define CREATEWINDOW
// Used to coordinate user-thread queue ops and
// queue lookup in falcon-thread callback
//
CRITICAL_SECTION g_csCallback;
// per-class hwnd
HWND CMSMQEvent::m_hwnd = NULL;
WNDPROC CMSMQEvent::m_lpPrevWndFunc = NULL;
UINT CMSMQEvent::m_cInstance = 0;
WNDCLASS CMSMQEvent::m_wndclass;
HANDLE g_hEvent = INVALID_HANDLE_VALUE;
// MSMQEvent event stuff...
typedef enum {
MSMQEventEvent_Arrived = 0,
MSMQEventEvent_ArrivedError = 1,
} MSMQEventEVENTS;
VARTYPE rgI4[] = {VT_I4};
VARTYPE rgI4I4[] = {VT_I4, VT_I4};
VARTYPE rgDISPATCHI4[] = {VT_DISPATCH, VT_I4};
VARTYPE rgDISPATCHI4I4[] = {VT_DISPATCH, VT_I4, VT_I4};
EVENTINFO g_rgMSMQEventEvents[] = {
{DISPID_MQEVENTEVENTS_ARRIVED, 2, rgDISPATCHI4},
{DISPID_MQEVENTEVENTS_ARRIVEDERROR, 3, rgDISPATCHI4I4}
};
//=--------------------------------------------------------------------------=
// CMSMQEvent::Create
//=--------------------------------------------------------------------------=
// creates a new MSMQMessage object.
//
// Parameters:
// IUnknown * - [in] controlling unkonwn
//
// Output:
// IUnknown * - new object.
//
// Notes:
//
IUnknown *CMSMQEvent::Create
(
IUnknown *pUnkOuter
)
{
// make sure we return the private unknown so that we support aggegation
// correctly!
//
CMSMQEvent *pNew = new CMSMQEvent(pUnkOuter);
return pNew ? pNew->PrivateUnknown() : NULL;
}
//=--------------------------------------------------------------------------=
// CMSMQEvent::CMSMQEvent
//=--------------------------------------------------------------------------=
// create the object and initialize the refcount
//
// Parameters:
// IUnknown * - [in] controlling unknown
//
// Notes:
//
#pragma warning(disable:4355) // using 'this' in constructor
CMSMQEvent::CMSMQEvent
(
IUnknown *pUnkOuter
)
: CAutomationObjectWEvents(pUnkOuter, OBJECT_TYPE_OBJMQEVENT, (void *)this)
{
// TODO: initialize anything here
HWND hwnd;
// Register our "sub-classed" windowproc so that we can
// send a message from the Falcon thread to the user's VB
// thread in order to fire async events in the correct
// context.
//
if (m_cInstance++ == 0) {
#ifdef CREATEWINDOW
hwnd = CreateHiddenWindow();
#else
hwnd = GetActiveWindow();
#endif // CREATEWINDOW
ASSERT(IsWindow(hwnd), L"should have a valid window.");
#ifndef CREATEWINDOW
m_lpPrevWndFunc = (WNDPROC)SetWindowLong(
NULL, // hwnd,
GWL_WNDPROC,
(LONG)CMSMQEvent_WindowProc
);
#endif // CREATEWINDOW
m_hwnd = hwnd;
//
// Event for inter-thread synchronization
//
g_hEvent = CreateEvent(NULL,
FALSE, // manual reset
FALSE, // not signalled
NULL);
ASSERT(g_hEvent != NULL, L"CreateEvent failed!");
} // if m_hwnd == NULL
}
#pragma warning(default:4355) // using 'this' in constructor
//=--------------------------------------------------------------------------=
// CMSMQEvent::CMSMQEvent
//=--------------------------------------------------------------------------=
// "We all labour against our own cure, for death is the cure of all diseases"
// - Sir Thomas Browne (1605 - 82)
//
// Notes:
//
CMSMQEvent::~CMSMQEvent ()
{
// TODO: clean up anything here.
#ifndef CREATEWINDOW
// Un-subclass if the sub-classed window is still valid.
if (m_hwnd && m_lpPrevWndFunc) {
if (IsWindow(m_hwnd)) {
SetWindowLong(NULL, // m_hwnd,
GWL_WNDPROC,
(LONG)m_lpPrevWndFunc);
}
}
m_hwnd = NULL;
m_lpPrevWndFunc = NULL;
#else
if (--m_cInstance == 0) {
DestroyHiddenWindow();
if (g_hEvent != INVALID_HANDLE_VALUE) {
SetEvent(g_hEvent);
CloseHandle(g_hEvent);
g_hEvent = INVALID_HANDLE_VALUE;
}
}
#endif // CREATEWINDOW
}
//=--------------------------------------------------------------------------=
// CMSMQEvent::InternalQueryInterface
//=--------------------------------------------------------------------------=
// the controlling unknown will call this for us in the case where they're
// looking for a specific interface.
//
// Parameters:
// REFIID - [in] interface they want
// void ** - [out] where they want to put the resulting object ptr.
//
// Output:
// HRESULT - S_OK, E_NOINTERFACE
//
// Notes:
//
HRESULT CMSMQEvent::InternalQueryInterface
(
REFIID riid,
void **ppvObjOut
)
{
CHECK_POINTER(ppvObjOut);
// we support IMSMQEvent and ISupportErrorInfo and now IMSMQPrivateEvent
//
if (DO_GUIDS_MATCH(riid, IID_IMSMQEvent)) {
*ppvObjOut = (void *)(IMSMQEvent *)this;
AddRef();
return S_OK;
} else if (DO_GUIDS_MATCH(riid, IID_ISupportErrorInfo)) {
*ppvObjOut = (void *)(ISupportErrorInfo *)this;
AddRef();
return S_OK;
} else if (DO_GUIDS_MATCH(riid, IID_IMSMQPrivateEvent)) {
*ppvObjOut = (void *)(IMSMQPrivateEvent *)this;
AddRef();
return S_OK;
}
// call the super-class version and see if it can oblige.
//
return CAutomationObjectWEvents::InternalQueryInterface(riid, ppvObjOut);
}
//
// IMSMQPrivateEvent methods
//
//=--------------------------------------------------------------------------=
// CMSMQEvent::FireArrivedEvent
//=--------------------------------------------------------------------------=
//
// Parameters:
//
// Output:
//
// Notes:
HRESULT CMSMQEvent::FireArrivedEvent(
IMSMQQueue __RPC_FAR *pq,
long msgcursor)
{
FireEvent(
&g_rgMSMQEventEvents[MSMQEventEvent_Arrived],
(long)pq,
msgcursor);
return NOERROR;
}
//=--------------------------------------------------------------------------=
// CMSMQEvent::FireArrivedErrorEvent
//=--------------------------------------------------------------------------=
//
// Parameters:
//
// Output:
//
// Notes:
HRESULT CMSMQEvent::FireArrivedErrorEvent(
IMSMQQueue __RPC_FAR *pq,
HRESULT hrStatus,
long msgcursor)
{
FireEvent(
&g_rgMSMQEventEvents[MSMQEventEvent_ArrivedError],
(long)pq,
(long)hrStatus,
(long)msgcursor);
return NOERROR;
}
extern WNDPROC g_lpPrevWndFunc;
//=--------------------------------------------------------------------------=
// InternalReceiveCallback
//=--------------------------------------------------------------------------=
// Async callback handler. Runs in Falcon created thread.
// We send message to user thread so that event is fired
// in correct execution context.
//
// Parameters:
// hrStatus,
// hReceiveQueue,
// dwTimeout,
// dwAction,
// pMessageProps,
// lpOverlapped,
// hCursor
// MQMSG_CURSOR
//
// Output:
// HRESULT - S_OK, E_NOINTERFACE
//
// Notes:
//
void APIENTRY InternalReceiveCallback(
HRESULT hrStatus,
QUEUEHANDLE hReceiveQueue,
DWORD dwTimeout,
DWORD dwAction,
MQMSGPROPS* pmsgprops,
LPOVERLAPPED lpOverlapped,
HANDLE hCursor,
MQMSGCURSOR msgcursor)
{
// FireEvent...
// Map handle to associated queue object
//
CMSMQQueue *pq;
HWND hwnd;
VARIANT_BOOL isOpen;
LRESULT lr;
BOOL fInCritSect = FALSE;
IMSMQEvent *pqevent;
IMSMQPrivateEvent *pprivateevent = NULL;
HRESULT hresult;
//
// UNDONE: 905: decrement dll refcount that we incremented
// when we registered the callback.
//
EnterCriticalSection(&g_csCallback); // syncs other queue ops
fInCritSect = TRUE;
pq = CMSMQQueue::PqOfHandle(hReceiveQueue);
// if no queue, then ignore the callback otherwise
// if the queue is open and it has a window
// then send message to user-thread that will
// trigger event firing.
//
if (pq) {
hresult = pq->get_IsOpen(&isOpen);
ASSERT(hresult == NOERROR, L"IsOpen should never fail.");
if (isOpen) {
pqevent = pq->Pqevent();
if (pqevent) {
//
// don't get the private interface here since MTS might cache it
// and then we'll have ITC problems
//
hwnd = CMSMQEvent::Hwnd();
if (IsWindow(hwnd)) {
//
// Need to exit critsect now so that
// we don't deadlock with user closing queue
// in user thread.
//
LeaveCriticalSection(&g_csCallback);
fInCritSect = FALSE;
//
// 1212: In principle, need to special case BUFFER_OVERFLOW
// by growing buffer and synchronously peeking...
// but since it's the user's responsibility to
// receive the actual message, we'll just let our
// usual InternalReceive handling deal with the
// overflow...
//
//
// 1900: pass msgcursor to event handler
//
WindowsMessage *pwinmsg = new WindowsMessage;
if (! pwinmsg) {
RETAILMSG(1, (L"MQOA: OUT OF MEMORY - DATA WILL BE LOST!\r\n"));
goto cleanup;
}
pwinmsg->m_msgcursor = msgcursor;
if ((hrStatus == MQ_ERROR_BUFFER_OVERFLOW) ||
SUCCEEDED(hrStatus)) {
//
// Since we are in a Falcon created callback thread,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -