390 likes | 610 Views
™. Programming A Distributed Message Queue Application Raphi Renous Software Development Engineer Desktop And Business Systems Division Microsoft Corporation. Agenda. “Falcon” (MSMQ) features Distributed whiteboard demo C/C++ API ActiveX ™ Components Summary Questions?.
E N D
™ Programming A Distributed Message Queue ApplicationRaphi RenousSoftware Development EngineerDesktop And Business Systems DivisionMicrosoft Corporation
Agenda • “Falcon” (MSMQ) features • Distributed whiteboard demo • C/C++ API • ActiveX™ Components • Summary • Questions?
“Falcon” (MSMQ) Features • Sessionless with asynchronous send and receive • Protocol and platform-independent API • Scalable to large number of nodes • Robust: reliable, guaranteed, transactional • Integrated security • System-wide priority policy • Advanced logging and tracking • Multireader, multisender, multithreaded • Support for legacy systems • SDK: C/C++ API, ActiveX Components
C/C++ API • Function sets • Queue manipulation • Queue location • Message manipulation • Utilities • Message and queue objects represented using properties • Use MQ.H, MQRT.LIB
Properties • Properties associated with queuesand messages • Each property consists of ID, type, value • Property set • Count • Array of IDs • Array of variants (tagged union) containing type and value • Array of status codes (optional) • ID names: PROPID_Q_* or PROPID_M_*
Usage Overview • Queue creation • Form queue property set • Call MQCreateQueue()with property set • Queue opening • Obtain queue format name • By creating the queue • From the queue location function • Set by the application • Call MQOpenQueue()with format name
Usage Overview • Message reception • Open queue for receive access • Determine message property set to be received • Call MQReceiveMessage() with open queue handle and property set • If asynchronous, write code to handle message arrival • Message sending • Open queue for send access • Form message property set • Call MQSendMessage() with open queue handle and property set
Queue Manipulation • Default security: get properties/permissions and send • Queue properties • PATHNAME, LABEL, SERVICETYPE, INSTANCE, TRANSACTIONAL, BASEPRIORITY, AUTHENTICATE, JOURNAL, PRIV_LEVEL, QUOTA • PATHNAME property specifies public/private queue • Public • Stored in MSMQ Information Service database • “MachineName\QueueName” • Private • Stored on disk of local machine • “MachineName\Private$\QueueName” HRESULT MQCreateQueue(IN PSECURITY_DESCRIPTOR pSecurityDesc, IN OUT MQQUEUEPROPS *pQueueProps, OUT LPWSTR lpwcsFormatName, IN OUT LPDWORD lpdwFormatNameLength) HRESULT MQDeleteQueue(IN LPWSTR lpwcsFormatName)
Queue Manipulation • Format name • Specifies how to get to a queue • “Public=QueueInstance” • “Private=MachineGUID\QueueInstance” • “Direct=Protocol:MachineAddress\QueueName”“Direct=OS:MachineAddress\QueueName” • Not a property • Returned by MQCreateQueue() • Obtained from the properties returnedby the queue location functions • Formed by the application
Queue Manipulation • Subject to queue security • One type of access per queue handle • MQ_SEND_ACCESS, MQ_RECEIVE_ACCESS, MQ_PEEK_ACCESS • Share mode • 0 - available to everyone (must be used for peek and send) • MQ_DENY_RECEIVE_SHARE - only this process can receive HRESULT MQOpenQueue(IN LPWSTR lpwcsFormatName, IN DWORD dwAccess, IN DWORD dwShareMode, OUT LPQUEUEHANDLE phQueue) HRESULT MQCloseQueue(IN QUEUEHANDLE hQueue)
Queue Manipulation QUEUEPROPID aPropId[1]; MQPROPVARIANT aPropVar[1]; DWORD cProps= 0; aPropId[cProps] = PROPID_Q_PATHNAME; aPropVar[cProps].vt = VT_LPWSTR; aPropVar[cProps].pwszVal= L“machine\\queue”; cProps++; MQQUEUEPROPS propsQueue; propsQueue.cProps = cProps; propsQueue.aPropId = aPropId; propsQueue.aPropVar = aPropVar; propsQueue.aStatus = NULL; WCHAR szFormat[MAX_FORMAT_NAME_LEN]; DWORD dwSize = MAX_FORMAT_NAME_LEN; HRESULThr = MQCreateQueue(NULL, &propsQueue, szFormat, &dwSize); QUEUEHANDLE hQueue; if (!FAILED(hr)) hr = MQOpenQueue(szFormat, MQ_RECEIVE_ACCESS, 0, &hQueue);
Queue Location • Powerful - do not need to know exact location of queue • Context - starting point in name space (currently NULL) • Restriction set • Property information (ID, type, value) • Comparison operation for each property • Column set - queue properties to be returned by query • Sort set - sort order for results (optional) • Property IDs from column set • Order for each property ID • Returns enumeration handle (does not retrieve results) HRESULT MQLocateBegin(IN LPCWSTR lpwcsContext, IN MQRESTRICTION *pRestriction, IN MQCOLUMNSET *pColumns, IN MQSORTSET *pSort, OUT PHANDLE phEnum)
Queue Location • Call MQLocateNext() until (*pcProps) on output < (*pcProps) on input • Returns as many “complete” results as possible • Must free memory allocated by “Falcon” (if any) using MQFreeMemory() HRESULT MQLocateNext(IN HANDLE hEnum, IN OUT DWORD *pcProps, OUT PROPVARIANT aPropVar[]) HRESULT MQLocateEnd(IN HANDLE hEnum)
Queue Location MQPROPERTYRESTRICTION aPropRestriction[1]; DWORD cProps= 0; aPropRestriction[cProps].rel=PREQ; aPropRestriction[cProps].prop=PROPID_Q_LABEL; aPropRestriction[cProps].prval.vt=VT_LPWSTR; aPropRestriction[cProps].prval.pwszVal=L“label”; cProps++; MQRESTRICTION Restriction; Restriction.cRes = cProps; Restriction.paPropRes = aPropRestriction; QUEUEPROPID aPropId[1]; cProps= 0; aPropId[cProps] = PROPID_Q_INSTANCE; cProps++; MQCOLUMNSET Column; Column.cCol = cProps; Column.aCol = aPropId;
Queue Location DWORD hEnum; HRESULThr = MQLocateBegin(NULL, &Restriction, &Column, NULL, &hEnum); if (!FAILED(hr)) { MQPROPVARIANT aPropVar[1]; DWORD cQueue= 1; hr = MQLocateNext(hEnum, &cQueue, &Column, aPropVar); if (!FAILED(hr) && cQueue> 0) { WCHAR szFormat[MAX_FORMAT_NAME_LEN]; DWORD dwSize = MAX_FORMAT_NAME_LEN; hr = MQGuidToFormatName(aPropVar[0].puuid, szFormat, &dwSize); if (!FAILED(hr)) ... /* Open queue */ MQFreeMemory(apropVar[0].puuid); } MQLocateEnd(hEnum); }
Message Manipulation HRESULT MQSendMessage(IN QUEUEHANDLE hDestinationQueue, IN MQMSGPROPS *pMessageProps, IN ITransaction *pTransaction) • Message properties • BODY, LABEL, DELIVERY, PRIORITY, TIME_TO_BE_RECEIVED, TIME_TO_REACH_QUEUE, JOURNAL, ACKNOWLEDGE, CORRELATIONID, APPSPECIFIC, ADMIN_QUEUE, RESPONSE_QUEUE, PRIVACYLEVEL, SECURITY_CONTEXT • Always asynchronous • Use TIME_TO_BE_RECEIVED or TIME_TO_REACH_QUEUE property to specify time limit for message to reach destination • Transaction interface • Get from MS® DTC
Message Manipulation HRESULT MQReceiveMessage(IN QUEUEHANDLE hSourceQueue, IN DWORD dwTimeOut, IN DWORD dwAction, IN OUT MQMSGPROPS *pMessageProps, IN OUT LPOVERLAPPED lpOverlapped, IN PMQRECEIVECALLBACK fnReceiveCallback, IN HANDLE hCursor, IN ITransaction *pTransaction) • Action • MQ_ACTION_RECEIVE, MQ_ACTION_PEEK_CURRENT, MQ_ACTION_PEEK_NEXT • Additional message properties • CLASS, MSGID, SENDERID, SRC_MACHINE, SENDER_CERTIFICATE • Allows asynchronous receive • Callback function, Win32® event, Windows NT® completion port • Cursor used to traverse messages in queue • Transaction interface • Get from MS DTC
Message Manipulation MSGPROPID aPropId[1]; MQPROPVARIANT aPropVar[1]; DWORD cProps= 0; WCHAR szBody[MAX_MSG_BODY_LEN]; aPropId[cProps] = PROPID_M_BODY; aPropVar[cProps].vt = VT_UI1 | VT_VECTOR; aPropVar[cProps].cab.cElems= sizeof(szBody); aPropVar[cProps].cab.pElems= (UCHAR *)szBody; cProps++; MQMSGPROPS propsMsg; propsMsg.cProps = cProps; propsMsg.aPropId = aPropId; propsMsg.aPropVar = aPropVar; propsMsg.aStatus = NULL; HRESULThr = MQReceiveMessage(hQueue,INFINITE, MQ_ACTION_RECEIVE,&propsMsg, NULL, NULL, NULL, NULL);
Other Functions • Queue manipulation • MQGetQueueProperties(), MQSetQueueProperties() • MQGetQueueSecurity(), MQSetQueueSecurity() • Message manipulation • MQCreateCursor(), MQCloseCursor() • Utilities • MQFreeMemory() • MQGetMachineProperties() • MQGuidToFormatName(), MQHandleToFormatName(), MQPathNameToFormatName()
ActiveX Components • Provide simple end-user programming modelwithout compromising performance • Support early (vtable) and late (IDispatch) binding • Direct support for most “Falcon” functionalitywithin the object model • No UI required • Usable by any ActiveX Server controller, for example, • Visual Basic® 3.0, Visual Basic 4.0, Visual Basic 5.0 • “Denali” • Microsoft® Access • Office 97 • Delphi, PowerBuilder
Component Model • MSMQQueueInfo: queue object • MSMQQueue: instance of open queue • MSMQMessage: message object • MSMQQuery: supports queue location • MSMQQueueInfos: collection of queues • MSMQEvent:asynchronous message arrival notification • Deliverable: mqoa.dll • Contains both implementation and type library
Usage Overview • Queue creation • Set properties in MSMQQueueInfo • Call MSMQQueueInfo.Create • Queue opening • Obtain MSMQQueueInfo • By creating the queue • From MSMQQueueInfos returned by MSMQQuery • Set q = queueinfo.Open
Usage Overview • Message reception • mqQueue = queue opened with receive access • If asynchronous • Create MSMQEvent object:set qevent = new MSMQEvent • Call mqQueue.EnableNotification(qevent) • Write qevent_Arrived event handler • Set mqMessage = mqQueue.Receive • Message sending • mqQueue = queue opened with send access • Set properties in mqMessage instance • Call mqMessage.Send(mqQueue)
MSMQQueueInfo • Describes a queue object • Methods • Create, Delete • Open(access, sharemode) as MSMQQueue • access: MQMSG_RECEIVE_ACCESS, MQMSG_SEND_ACCESS, MQMSG_PEEK_ACCESS • sharemode: MQ_DENY_NONE, MQ_DENY_RECEIVE_SHARE • Properties • strLabel, strPathname, guidServiceType, guidQueue, strFormatName • Example‘ Create queue for my instanceDim qrec As New MSMQQueueInfoqinfo.strPathName = "machine\queue"qinfo.strLabel = "My Draw Queue"qinfo.Create
MSMQQueue • Describes an open queue instance • A queue can be concurrently open multiple times • One-to-many mapping from MSMQQueueInfo to MSMQQueue • Analogy: MSMQQueueInfo is to MSMQQueue as File is to FileHandle • Provides asynchronous message handling • Manages collection of messages
MSMQQueue • Methods • IsOpen() as Boolean • Close • Receive() as MSMQMessage • Synchronous message reception • Peek() as MSMQMessage • Synchronous message peeking • EnableNotification(qevent as MSMQEvent) • Turns on asynchronous message notification • Message arrival to queue will now fire qevent_Arrived event • DisableNotification • Reset • Resets message collection to start • ReceiveNext() / PeekNext() as MSMQMessage • Cursor based synchronous reception/peek
MSMQQueue • Properties • lReceiveTimeout, lAccess, lShareMode, queueinfo, lHandle • Error event fired if timeout expires while synchronously waiting to receive message • Example‘ Create and open a queue for synchronous receptionDim qinfo As New MSMQQueueInfoDim myQ As MSMQQueue qinfo.strPathName = "machine\queue" qinfo.CreateSet myQ = qinfo.Open(MQMSG_RECEIVE_ACCESS, MQ_DENY_NONE)
MSMQEvent • Allows user to write single generic event handler to manage message arrival notification of multiple queues • Events • Arrived(byval pdispQueue as Object) • Fired when a new message arrives at queue • ArrivedError(byval pdispQueue as Object, byval error as Long) • Fired to indicate message error in reception
MSMQQuery • Provides filtered queue location • Returns collection of queue objects • Method • LookupQueue(<selection criteria>) as MSMQQueueInfos • Example‘ Locate the friend queueDim queryFriend As New MqQueryDim qinfosResult As MSMQQueueInfosSet qinfosResult = queryFriend.LookupQueue( strLabel := FriendName, strGuidServiceType := DrawType)
MSMQQueueInfos • Manages collection of MSMQQueueInfo objects produced by MSMQQuery • Methods • Reset • Next() as MSMQQueueInfo • Example‘ Display the queue label for all the queuesDim queryAll As New MSMQQueryDim qinfos As MSMQQueueInfosDim qinfoCurrent As MSMQQueueInfoSet qinfos = queryAll.LookupQueueqinfos.ResetSet qinfoCurrent = qinfos.NextWhile Not qinfoCurrent Is Nothing MsgBox qinfoCurrent.strLabel Set qinfoCurrent = qinfos.NextWend
MSMQMessage • Describes a message • Method • Send(q as MSMQQueue) • Properties • body, strLabel, delivery, lPriority, lTimeToBeReceived, lTimeToReachQueue, class, id, idCorrelation, lJournal, acknowledge, queueinfoResponse, queueinfoAdmin, queueinfoDest, lAppSpecific • Example‘ Send the keystroke to the friendDim OutMsg as New MSMQMessageOutMsg.lPriority = 4OutMsg.strBody = Chr(KeyAscii)OutMsg.strLabel = "Key: " + OutMsg.strBodyOutMsg.Send FriendQ
MSMQMessage.body • The body property allows you to send/receive typed messages • Messages can be: • Strings • Arrays of bytes • Persistent ActiveX objects • Support IDispatch and IPersistStream or IPersistStorage • E.g., Office documents, bitmaps
Example ‘ send/receive an XL sheetDim mSend as New MSMQMessageDim mReceive as MSMQMessageDim qSend as MSMQQueueDim qReceive as MSMQQueue mSend.body = GetObject(“sheet.xls”)mSend.Send qSend set mReceive = qReceive.Receive if TypeOf mReceive.body Is Excel.Workbook Then ‘ do XL stuff to message body set xl = mReceive.bodyend if
Limitations • Only Visual Basic 5.0 supports user-defined event handlers to ActiveX Servers • Use WithEvents keyword in declaration • Visual Basic 4.0 can use every other feature • Visual Basic 5.0 example:‘ Open an existing queue for asynchronous receptionDim WithEvents qevent As MSMQEventSub OpenExistingQueue() Dim qinfo As New MSMQQueueInfo qinfo.strPathName = "machine\queue" Set qPeek = qrec.Open(MQMSG_PEEK_ACCESS, 0) Set qevent = New MSMQEvent qPeek.EnableNotification qeventEnd SubPrivate Sub qevent_Arrived(byval q as Object) Dim m As MSMQMessage Set m = q.PeekNext MsgBox "Arrived: " + m.strBody q.EnableNotification qeventEnd Sub
Summary • Your mission • Today: try Beta2 • Run the samples (c_draw and oa_draw) • Write applications using the C/C++ API and ActiveX Components • Soon: deploy “Falcon”-based message queuing applications
Summary • Your benefit • Easy and flexible distributed programming • Asynchronous, sessionless messaging • Not concerned with underlying networkand protocols • Not concerned with computer and network reliability • Integrated with state-of-the-art technologies and interfaces • ActiveX Components usable fromVisual Basic Scripting Edition (e.g., “Denali”)
Questions? • For more information • See slides from “Microsoft Message Queue Server Overview (ENT208)” talk • Check out our Web site: http://www.microsoft.com/msmq • Contact msmq@microsoft.com