📄 scexpapi.cxx
字号:
//
// 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.
//
/*++
Module Name:
scapi.h
Abstract:
Small client - Windows CE nonport part/export library
--*/
#include <windows.h>
#include <objbase.h>
#include <objidl.h>
#include <wtypes.h>
#include <mq.h>
#include <mqmgmt.h>
#include "..\server\expapis.hxx"
#include <svsutil.hxx>
#include <psl_marshaler.hxx>
ce::psl_proxy<>* pProxy;
//
// Callback information.
//
// Information blob for each perform callback call.
typedef struct _MSMQ_CALLBACK_INFO {
PMQRECEIVECALLBACK pfnMQReceiveCallback; // function to call
HANDLE hEvent; // Handle that MSMQ Core wakes us up on.
// Paramaters passed to pfnMQReceiveCallback. None of these paramaters should be
// freed -- according to the spec, the calling application continues to own this memory.
QUEUEHANDLE hSource;
DWORD dwTimeout;
DWORD dwAction;
MQMSGPROPS* pMessageProps;
LPOVERLAPPED lpOverlapped; // NOTE: This is not passed to MSMQ core, but just to application callback.
HANDLE hCursor;
ITransaction *pTransaction;
} MSMQ_CALLBACK_INFO, *PMSMQ_CALLBACK_INFO;
DWORD WINAPI PerformCallbackWorker(LPVOID lpv);
// List of MSMQ_CALLBACK_INFO structures
SVSLinkManager *g_pCallbackList;
// Thread pool of PerformCallbackWorker()'s.
SVSThreadPool *g_pThreadPool;
// Lock class.
SVSSynch *g_pSync;
// Are we running or no? Used for shutdown processing.
BOOL g_fRunning;
//
// Global private data
//
static HANDLE hDevice = INVALID_HANDLE_VALUE;
extern "C" int QueryAPISetID(char*);
HRESULT APIENTRY MQCreateQueue(
PSECURITY_DESCRIPTOR pSecurityDescriptor,
MQQUEUEPROPS *pQueueProps,
LPWSTR lpszFormatName,
LPDWORD pdwNameLen
)
{
if (pSecurityDescriptor)
return MQ_ERROR_ILLEGAL_SECURITY_DESCRIPTOR;
if (pdwNameLen == NULL)
MQ_ERROR_INVALID_PARAMETER;
return pProxy->call(MQAPI_CODE_MQCreateQueue,pQueueProps,
ce::psl_buffer(lpszFormatName,*pdwNameLen),pdwNameLen);
}
HRESULT APIENTRY MQDeleteQueue (LPCWSTR lpszFormatName) {
return pProxy->call(MQAPI_CODE_MQDeleteQueue,lpszFormatName);
}
HRESULT APIENTRY MQGetMachineProperties (LPCWSTR lpszMachineName, const GUID *pGuid, MQQMPROPS *pMachineProps) {
return pProxy->call(MQAPI_CODE_MQGetMachineProperties,lpszMachineName,pGuid,pMachineProps);
}
HRESULT APIENTRY MQGetQueueProperties (LPCWSTR lpszFormatName, MQQUEUEPROPS *pQueueProps) {
return pProxy->call(MQAPI_CODE_MQGetQueueProperties,lpszFormatName,pQueueProps);
}
HRESULT APIENTRY MQSetQueueProperties (LPCWSTR lpszFormatName, MQQUEUEPROPS *pQueueProps) {
return pProxy->call(MQAPI_CODE_MQSetQueueProperties,lpszFormatName,pQueueProps);
}
HRESULT APIENTRY MQOpenQueue (LPCWSTR lpszFormatName, DWORD dwAccess, DWORD dwShareMode, QUEUEHANDLE *phQueue) {
return pProxy->call(MQAPI_CODE_MQOpenQueue,lpszFormatName,dwAccess,dwShareMode,phQueue);
}
HRESULT APIENTRY MQCloseQueue (QUEUEHANDLE hQueue) {
return pProxy->call(MQAPI_CODE_MQCloseQueue,hQueue);
}
HRESULT APIENTRY MQCreateCursor (QUEUEHANDLE hQueue, HANDLE *phCursor) {
return pProxy->call(MQAPI_CODE_MQCreateCursor,hQueue,phCursor);
}
HRESULT APIENTRY MQCloseCursor (HANDLE hCursor) {
return pProxy->call(MQAPI_CODE_MQCloseCursor,hCursor);
}
HRESULT APIENTRY MQHandleToFormatName (QUEUEHANDLE hQueue, WCHAR *lpszFormatName, DWORD *pdwNameLen) {
if (pdwNameLen == NULL)
return MQ_ERROR_INVALID_PARAMETER;
return pProxy->call(MQAPI_CODE_MQHandleToFormatName,hQueue,
ce::psl_buffer(lpszFormatName,*pdwNameLen),pdwNameLen);
}
HRESULT APIENTRY MQPathNameToFormatName (LPCWSTR lpszPathName, WCHAR *lpszFormatName, DWORD *pdwCount) {
if (pdwCount == NULL)
return MQ_ERROR_INVALID_PARAMETER;
return pProxy->call(MQAPI_CODE_MQPathNameToFormatName,lpszPathName,
ce::psl_buffer(lpszFormatName,*pdwCount),pdwCount);
}
void APIENTRY MQFreeMemory (void *pvPtr) {
pProxy->call(MQAPI_CODE_MQFreeMemory,pvPtr);
}
HRESULT APIENTRY MQSendMessage (QUEUEHANDLE hQueue, MQMSGPROPS *pMsgProps, void *pvTransact) {
return pProxy->call(MQAPI_CODE_MQSendMessage,hQueue,pMsgProps,(int)pvTransact);
}
HRESULT APIENTRY MQReceiveMessage(
QUEUEHANDLE hQueue,
DWORD dwTimeout,
DWORD dwAction,
MQMSGPROPS *pMsgProps,
LPOVERLAPPED lpOverlapped,
PMQRECEIVECALLBACK fnReceiveCallback,
HANDLE hCursor,
ITransaction *pTransaction
) {
if (fnReceiveCallback) {
// If app passes in a callback function, in the past we used to call
// PerformCallback() from MSMQ core in services.exe. However PerformCallback()
// is an unsafe function. The calling app, possibly untrusted, could muck with
// services.exe call stack.
// To get the same behavior for application in safe manner, we spin up
// a thread in application space, have that thread call into MQReceiveMessage
// with an event that will be signaled once MSMQ has something to report,
// then finally call into the app's callback once this has occurred.
HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
if (NULL==hEvent)
return MQ_ERROR_INSUFFICIENT_RESOURCES;
g_pSync->Lock();
PMSMQ_CALLBACK_INFO pCallback = (PMSMQ_CALLBACK_INFO) g_pCallbackList->AllocEntry();
if (!pCallback) {
g_pSync->Unlock();
CloseHandle(hEvent);
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
pCallback->hEvent = hEvent;
pCallback->pfnMQReceiveCallback = fnReceiveCallback;
pCallback->hSource = hQueue;
pCallback->dwTimeout = dwTimeout;
pCallback->dwAction = dwAction;
pCallback->pMessageProps = pMsgProps;
pCallback->lpOverlapped = lpOverlapped;
pCallback->hCursor = hCursor;
pCallback->pTransaction = pTransaction;
if (! g_pThreadPool->ScheduleEvent(PerformCallbackWorker,pCallback)) {
g_pCallbackList->RemoveEntry(pCallback); // This automatically closes hEvent via DeleteCallbackInfo().
g_pSync->Unlock();
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
g_pSync->Unlock();
return MQ_INFORMATION_OPERATION_PENDING;
}
return pProxy->call(MQAPI_CODE_MQReceiveMessage,hQueue,dwTimeout,dwAction,pMsgProps,
lpOverlapped,hCursor,(int)pTransaction);
}
HRESULT APIENTRY MQBeginTransaction (ITransaction **pTransact) {
// Not implemented - don't bother calling into services.exe
return MQ_ERROR_SERVICE_NOT_AVAILABLE;
}
HRESULT
APIENTRY
MQGetQueueSecurity(
LPCWSTR lpwcsFormatName,
SECURITY_INFORMATION RequestedInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD nLength,
LPDWORD lpnLengthNeeded
) {
// Not implemented - don't bother calling into servicesd.exe
return MQ_ERROR_SERVICE_NOT_AVAILABLE;
}
HRESULT
APIENTRY
MQSetQueueSecurity(
LPCWSTR lpwcsFormatName,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor
) {
// Not implemented - don't bother calling into servicesd.exe
return MQ_ERROR_SERVICE_NOT_AVAILABLE;
}
HRESULT APIENTRY MQGetSecurityContext
(
VOID *lpCertBuffer,
DWORD dwCertBufferLength,
HANDLE *hSecurityContext
) {
// Not implemented - don't bother calling into servicesd.exe
return MQ_ERROR_SERVICE_NOT_AVAILABLE;
}
void APIENTRY MQFreeSecurityContext (HANDLE h) {
// Not implemented - don't bother calling into servicesd.exe
return;
}
HRESULT APIENTRY MQInstanceToFormatName
(
GUID *pGUID,
WCHAR *lpszFormatName,
DWORD *lpdwCount
) {
// Not implemented - don't bother calling into servicesd.exe
return MQ_ERROR_SERVICE_NOT_AVAILABLE;
}
HRESULT APIENTRY MQLocateBegin(LPCWSTR lpwcsContext, MQRESTRICTION* pRestriction,
MQCOLUMNSET* pColumns, MQSORTSET* pSort, PHANDLE phEnum) {
// Not implemented - don't bother calling into servicesd.exe
return MQ_ERROR_SERVICE_NOT_AVAILABLE;
}
HRESULT APIENTRY MQLocateNext(HANDLE hEnum, DWORD* pcProps, MQPROPVARIANT aPropVar[]) {
// Not implemented - don't bother calling into servicesd.exe
return MQ_ERROR_SERVICE_NOT_AVAILABLE;
}
HRESULT APIENTRY MQLocateEnd (HANDLE hEnum) {
// Not implemented - don't bother calling into servicesd.exe
return MQ_ERROR_SERVICE_NOT_AVAILABLE;
}
HRESULT APIENTRY MQMgmtGetInfo(LPCWSTR pMachineName, LPCWSTR pObjectName, MQMGMTPROPS *pMgmtProps) {
memset (pMgmtProps->aPropVar, 0, sizeof(pMgmtProps->aPropVar[0]) * pMgmtProps->cProp);
for (int i = 0 ; i < (int)pMgmtProps->cProp ; ++i)
pMgmtProps->aPropVar[i].vt = VT_NULL;
return pProxy->call(MQAPI_CODE_MQMgmtGetInfo2,pMachineName,pObjectName,pMgmtProps);
}
HRESULT APIENTRY MQMgmtAction(LPCWSTR pMachineName, LPCWSTR pObjectName, LPCWSTR pAction) {
return pProxy->call(MQAPI_CODE_MQMgmtAction,pMachineName,pObjectName,pAction);
}
//
// Code related to making callbacks work on MQReceiveMessage()
//
void PerformCallbackMSMQ(MSMQ_CALLBACK_INFO *pCallback, HRESULT hr) {
__try {
pCallback->pfnMQReceiveCallback(hr, pCallback->hSource, pCallback->dwTimeout,
pCallback->dwAction,pCallback->pMessageProps,
pCallback->lpOverlapped,pCallback->hCursor);
}
__except (1) {
;
}
}
// Worker thread for actually doing the callback itself.
DWORD WINAPI PerformCallbackWorker(LPVOID lpv) {
PMSMQ_CALLBACK_INFO pCallback;
g_pSync->Lock();
// Got removed from list before we could get started
pCallback = (PMSMQ_CALLBACK_INFO)g_pCallbackList->FindEntry(lpv);
if (NULL == pCallback) {
SVSUTIL_ASSERT(0); // shouldn't be able to happen
return 0;
}
g_pSync->Unlock();
OVERLAPPED ov;
memset(&ov,0,sizeof(ov));
ov.hEvent = pCallback->hEvent;
ov.Internal = MQ_ERROR;
HRESULT hr = MQReceiveMessage(pCallback->hSource,pCallback->dwTimeout,pCallback->dwAction,
pCallback->pMessageProps,&ov,NULL,pCallback->hCursor,
pCallback->pTransaction);
if (hr != MQ_INFORMATION_OPERATION_PENDING) {
// There is already a message waiting to be received or there was an error.
PerformCallbackMSMQ(pCallback,hr);
goto done;
}
hr = WaitForSingleObject(pCallback->hEvent,INFINITE);
if (hr == WAIT_OBJECT_0) {
if (! g_fRunning) {
// The application is dying (g_fRunning is only set = FALSE in
// DllMain DLL_PROCESS_DETACH processing). In this case,
// we want to exit thread ASAP so do not call into callback.
goto done;
}
// MSMQ puts status in Internal param
PerformCallbackMSMQ(pCallback,ov.Internal);
}
// If there was some other error, do not perform callback...
done:
CloseHandle(pCallback->hEvent);
g_pSync->Lock();
// Remove ourselves from the list.
g_pCallbackList->RemoveEntry(pCallback);
g_pSync->Unlock();
return 0;
}
void WINAPI DeleteCallbackInfo(void *pvData) {
PMSMQ_CALLBACK_INFO pCallback = (PMSMQ_CALLBACK_INFO) pvData;
if (pCallback->hEvent)
CloseHandle(pCallback->hEvent);
}
extern "C" BOOL WINAPI DllMain(HANDLE hInstDll, DWORD fdwReason, LPVOID lpvReserved) {
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
svsutil_Initialize();
DisableThreadLibraryCalls((HMODULE)hInstDll);
g_pSync = new SVSSynch();
if (NULL == g_pSync)
return FALSE;
g_pCallbackList = new SVSLinkManager(sizeof(MSMQ_CALLBACK_INFO),DeleteCallbackInfo);
if (NULL == g_pCallbackList)
return FALSE;
g_pThreadPool = new SVSThreadPool();
if (NULL == g_pThreadPool)
return FALSE;
pProxy = new ce::psl_proxy<>(L"MMQ1:", IOCTL_MSMQ_INVOKE, NULL);
if (NULL == pProxy)
return FALSE;
g_fRunning = TRUE;
break;
case DLL_PROCESS_DETACH:
g_fRunning = FALSE;
if (pProxy)
delete pProxy;
if (g_pThreadPool)
delete g_pThreadPool;
if (g_pCallbackList)
delete g_pCallbackList;
if (g_pSync)
delete g_pSync;
svsutil_DeInitialize();
break;
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -