📄 event.cpp
字号:
// send a message to the user thread to trigger
// event firing...
// UNDONE: need to register unique Windows message.
// Need to use PostMessage instead of
// SendMessage otherwise get RPC_E_CANCALLOUT_ININPUTSYNCCALL
// when attempting to call to exe (only?) server like
// Excel in user-defined event handler.
// However, we would like event firing to be synchronous
// for ease of understanding and control so we
// simulate SendMessage by waiting for the event
// handler to signal it has completed handling.
//
#if 0 // Undone for now
DWORD dwWait;
ASSERT(g_hEvent != INVALID_HANDLE_VALUE,
L"should have valid event handle.");
pwinmsg->m_hEvent = g_hEvent;
lr = PostMessage(hwnd,
WM_MQRECEIVE,
(WPARAM)hReceiveQueue,
(LPARAM)pwinmsg);
dwWait = WaitForSingleObject(g_hEvent, INFINITE);
ASSERT(dwWait != WAIT_FAILED, L"wait failed.");
#endif // 0
lr = SendMessage(hwnd,WM_MQRECEIVE,
(WPARAM)hReceiveQueue,
(LPARAM)pwinmsg);
}
else {
pwinmsg->m_hrStatus = hrStatus;
#if 0
lr = PostMessage(hwnd,
WM_MQTHROWERROR,
(WPARAM)hReceiveQueue,
(LPARAM)pwinmsg);
#else // 0
lr = SendMessage(hwnd,
WM_MQTHROWERROR,
(WPARAM)hReceiveQueue,
(LPARAM)pwinmsg);
#endif // 1
}
} // if IsWindow
} // if pqevent
} // if isOpen
} // pq
cleanup:
// still in critsect?
if (fInCritSect) {
LeaveCriticalSection(&g_csCallback);
}
// Free params whose ownership we've acquired...
CMSMQMessage::FreeMessageProps(pmsgprops);
RELEASE(pprivateevent);
// translation to local ptr
delete pmsgprops;
return;
}
//=--------------------------------------------------------------------------=
// ReceiveCallback, ReceiveCallbackCurrent, ReceiveCallbackNext
//=--------------------------------------------------------------------------=
// Async callback handler. Runs in Falcon created thread.
// We send message to user thread so that event is fired
// in correct execution context.
// NOTE: no cursor
//
// Parameters:
// hrStatus,
// hReceiveQueue,
// dwTimeout,
// dwAction,
// pMessageProps,
// lpOverlapped,
// hCursor
//
// Output:
// HRESULT - S_OK, E_NOINTERFACE
//
// Notes:
//
void APIENTRY ReceiveCallback(
HRESULT hrStatus,
QUEUEHANDLE hReceiveQueue,
DWORD dwTimeout,
DWORD dwAction,
MQMSGPROPS* pmsgprops,
LPOVERLAPPED lpOverlapped,
HANDLE hCursor)
{
InternalReceiveCallback(
hrStatus,
hReceiveQueue,
dwTimeout,
dwAction,
pmsgprops,
lpOverlapped,
0, // no cursor
MQMSG_FIRST
);
}
void APIENTRY ReceiveCallbackCurrent(
HRESULT hrStatus,
QUEUEHANDLE hReceiveQueue,
DWORD dwTimeout,
DWORD dwAction,
MQMSGPROPS* pmsgprops,
LPOVERLAPPED lpOverlapped,
HANDLE hCursor)
{
InternalReceiveCallback(
hrStatus,
hReceiveQueue,
dwTimeout,
dwAction,
pmsgprops,
lpOverlapped,
hCursor,
MQMSG_CURRENT
);
}
void APIENTRY ReceiveCallbackNext(
HRESULT hrStatus,
QUEUEHANDLE hReceiveQueue,
DWORD dwTimeout,
DWORD dwAction,
MQMSGPROPS* pmsgprops,
LPOVERLAPPED lpOverlapped,
HANDLE hCursor)
{
InternalReceiveCallback(
hrStatus,
hReceiveQueue,
dwTimeout,
dwAction,
pmsgprops,
lpOverlapped,
hCursor,
MQMSG_NEXT
);
}
//=--------------------------------------------------------------------------=
// global CMSMQEvent_WindowProc
//=--------------------------------------------------------------------------=
// "derived" windowproc so that we can process our async event
// msg. This is a nop if notification has been disabled.
//
// Parameters:
// hwnd
// msg we can handle WM_MQRECEIVE/WM_MQTHROWERROR
// wParam QUEUEHANDLE: hReceiveQueue
// lParam [lErrorCode]:
// lErrorCode: if WM_MQTHROWERROR
//
// Output:
// LRESULT
//
// Notes:
//
LRESULT APIENTRY CMSMQEvent_WindowProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
CMSMQQueue *pq = NULL;
VARIANT_BOOL isOpen;
// CMSMQEvent *pqevent = NULL;
IMSMQEvent *pqevent = NULL;
IMSMQPrivateEvent *pprivateevent = NULL;
WindowsMessage *pwinmsg = (WindowsMessage *)lParam;
HRESULT hresult;
switch (msg) {
case WM_MQRECEIVE:
case WM_MQTHROWERROR:
//
// Need to revalidate incoming hReceiveQueue by
// lookup up (again) in queue list -- it might
// have been deleted already since we previously
// looked it up in another thread (falcon-created
// callback thread).
// Since we are now in the user-thread we don't
// need to critsect this lookup unlike the
// lookup in the callback thread.
//
pq = CMSMQQueue::PqOfHandle((QUEUEHANDLE)wParam);
if (pq) {
hresult = pq->get_IsOpen(&isOpen);
ASSERT(hresult == NOERROR, L"IsOpen shouldn't fail.");
if (isOpen) {
// does queue have an event handler?
// note: cast is safe because we populated
// queue object with our implementation of IMSMQEvent.
//
// pqevent = (CMSMQEvent *)pq->Pqevent();
pqevent = pq->Pqevent();
if (pqevent) {
MQMSGCURSOR msgcursor;
msgcursor = pwinmsg->m_msgcursor;
//
// 1884: allow event handler to reenable notifications
//
pq->SetHasActiveEventHandler(FALSE);
//
// QI to the private interface
//
hresult = pqevent->QueryInterface(
IID_IMSMQPrivateEvent,
(LPVOID *)&pprivateevent);
ASSERT(hresult == NOERROR, L"QI to IMSMQPrivateEvent shouldn't fail!");
if (msg == WM_MQRECEIVE) {
#if 1
pprivateevent->FireArrivedEvent(
pq,
(long)msgcursor);
#else
pqevent->FireEvent(&g_rgMSMQEventEvents[MSMQEventEvent_Arrived],
(long)pq,
(long)msgcursor);
#endif // 0
}
else {
// WM_MQTHROWERROR
HRESULT hrStatus;
hrStatus = pwinmsg->m_hrStatus;
#if 1
pprivateevent->FireArrivedErrorEvent(
pq,
(long)hrStatus,
(long)msgcursor);
#else
pqevent->FireEvent(
&g_rgMSMQEventEvents[MSMQEventEvent_ArrivedError],
(long)pq,
(long)hrStatus,
(long)msgcursor);
#endif // 0
}
RELEASE(pprivateevent);
} // pqevent
} // isOpen
} // pq
if (msg == WM_MQRECEIVE) {
//
// signal completion event if the event is still valid
//
if (g_hEvent != INVALID_HANDLE_VALUE) {
BOOL fSucceeded;
fSucceeded = SetEvent((HANDLE)g_hEvent);
ASSERT(fSucceeded, L"SetEvent failed!");
}
}
delete pwinmsg;
break;
default:
#ifdef CREATEWINDOW
return DefWindowProc(hwnd, msg, wParam, lParam);
#else
return CallWindowProc(
CMSMQEvent::LpPrevWndFunc(),
NULL, // hwnd,
msg,
wParam,
lParam);
#endif // CREATEWINDOW
} // switch
return 0;
}
//=--------------------------------------------------------------------------=
// CMSMQEvent::CreateHiddenWindow
//=--------------------------------------------------------------------------=
// creates a per-class hidden window that is used for inter-thread
// messaging from the Falcon async thread and the user thread.
//
// Parameters:
//
// Output:
//
// Notes:
//
HWND CMSMQEvent::CreateHiddenWindow()
{
HWND hwnd;
ATOM atomWndClass;
LPCTSTR lpClassName;
ASSERT(m_hwnd == 0, L"shouldn't be inited yet.");
memset(&m_wndclass, 0, sizeof(WNDCLASSA));
m_wndclass.lpfnWndProc = CMSMQEvent_WindowProc;
m_wndclass.lpszClassName = L"MSMQEvent";
// can use ANSI version
m_wndclass.hInstance = GetModuleHandle(NULL);
m_wndclass.style = WS_DISABLED;
atomWndClass = RegisterClass(&m_wndclass); // use ANSI version
ASSERT(atomWndClass != 0, L"RegisterClass shouldn't fail.");
lpClassName = (LPCTSTR)atomWndClass;
// can use ANSI version
hwnd = CreateWindow(
// (LPCSTR)m_wndclass.lpszClassName,
lpClassName,
L"EventWindow",
m_wndclass.style,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, // handle to parent or owner window
NULL, // handle to menu or child-window identifier
m_wndclass.hInstance,
NULL // pointer to window-creation data
);
#if DEBUG
DWORD dwErr;
if (hwnd == 0) {
dwErr = GetLastError();
ASSERT(dwErr == 0, L"CreateWindow returned an error.");
}
#endif // DEBUG
return hwnd;
}
//=--------------------------------------------------------------------------=
// CMSMQEvent::DestroyHiddenWindow
//=--------------------------------------------------------------------------=
// destroys per-class hidden window that is used for inter-thread
// messaging from the Falcon async thread and the user thread.
//
// Parameters:
//
// Output:
//
// Notes:
//
void CMSMQEvent::DestroyHiddenWindow()
{
ASSERT(m_hwnd != 0, L"should have a window handle.");
if (IsWindow(m_hwnd)) {
BOOL fDestroyed, fUnregistered;
fDestroyed = DestroyWindow(m_hwnd);
#if DEBUG
DWORD dwErr;
if (fDestroyed == FALSE) {
dwErr = GetLastError();
ASSERT(dwErr == 0, L"hmm... couldn't destroy window.");
}
#endif // DEBUG
// unregister our window class now that we've destroyed
// the window
//
fUnregistered = UnregisterClass(
m_wndclass.lpszClassName,
m_wndclass.hInstance);
#if DEBUG
if (fUnregistered == FALSE) {
dwErr = GetLastError();
ASSERT(dwErr == 0, L"hmm... couldn't unregister window class.");
}
#endif // DEBUG
}
m_hwnd = NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -