home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Visual Database / Visual BASIC 5.0 (Ent. Edition) / Vb5ent Extractor.EXE / VB / SAMPLES / ENTRPRIS / APE / AEWORKER / MODWORKR.BAS < prev    next >
Encoding:
BASIC Source File  |  1996-11-27  |  28.9 KB  |  613 lines

  1. Attribute VB_Name = "modWorker"
  2. Option Explicit
  3. '-------------------------------------------------------------------------
  4. 'The project is the Worker component of the Application Performance Explorer
  5. 'The Worker is designed to function as a thread per object or
  6. 'single-use OLE Server to be created by the QueueMgr
  7. 'component.  The Worker loads Service provider objects to accomplish
  8. 'tasks.  The Worker gets task requests from the Queue Manager and returns
  9. 'results to the back to the Queue Manager.
  10. '
  11. 'Key Files:
  12. '   Worker.cls      public class used as controling OLE interface
  13. '-------------------------------------------------------------------------
  14. 'Declares
  15. Private Declare Function GetTickCount Lib "kernel32" () As Long
  16. Private Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
  17. Private Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long
  18.  
  19. 'Public Constants
  20. Public Const giERROR_THRESHOLD As Integer = 32000
  21. Public Const giTIMER_INTERVAL As Integer = 500
  22. Public Const giMAX_ALLOWED_RETRIES  As Integer = 500
  23. Public Const giRETRY_WAIT_MIN  As Integer = 500      'Retry Wait is measure in DoEvent cyles
  24. Public Const giRETRY_WAIT_MAX  As Integer = 2500
  25.  
  26. 'Property defaults
  27. Public Const gbLOG_DEFAULT As Boolean = False
  28. Public Const gbPERSISTENCE_DEFAULT As Boolean = True
  29. Public Const gbEARLY_BIND_DEFAULT As Boolean = True
  30. Public Const gsCOMMAND_DELIMITER As String * 1 = "."
  31.  
  32. 'Message Constants, resourse string
  33. Public Const giEXECUTE_BEGIN As Integer = 3
  34. Public Const giEXECUTE_END As Integer = 4
  35. Public Const giGET_REQUEST_BEGIN As Integer = 6
  36. Public Const giWORKER_NAME As Integer = 7
  37. Public Const giGET_REQUEST_END_NEW_SERVICE As Integer = 8
  38. Public Const giGET_REQUEST_END_NO_SERVICE As Integer = 9
  39. Public Const giDO_SERVICE_RECEIVED As Integer = 10
  40. Public Const giCALL_REJECTED_RETRY As Integer = 11
  41. Public Const giERROR_PREFIX As Integer = 12
  42.  
  43. 'User Defined Error Codes which serve as resource string Indexes
  44. Public Const giINVALID_COMMAND_PARAMETER As Integer = 32767
  45.  
  46. 'Default Timer interval
  47. Private Const mlDEFAULT_INTERVAL As Long = 1
  48.  
  49. 'User Defined Type
  50. Public Type Service
  51.     ID As Long                  'The ID of the Service Request, known by QueueMgr, and Expediter
  52.     Command As String           'Format is "Library.Class.Method"
  53.     Data As Variant             'Variant received by Queue Mgr pass from a client
  54.     Return As Variant           'Variant returned by Service object
  55.     DataPresent As Boolean      'Flag received by QueueMgr, if true pass data to Service object
  56. End Type
  57.  
  58. Public glWorkerID As Long       'This is given by the queue manager
  59. Public gbLog As Boolean         'If true log Service
  60. Public gbPersistent As Boolean  'If true, the worker keeps reference to
  61.                                 'every Service object it has used, else
  62.                                 'worker releases Service object after
  63.                                 'each use.
  64. Public gbEarlyBind As Boolean   'If true, the worker uses code that utilizes
  65.                                 'early binding.  This option is only
  66.                                 'available for Service objects classes that
  67.                                 'were developed with the worker class,
  68.                                 'because early binding is only available
  69.                                 'if class names are hard coded.
  70. Public goLogger As AELogger.Logger     'Logger object
  71. Public goQueueDelegator As APEInterfaces.QueueDelegator  'QueueManager class object
  72. Public gcServices As Collection        'Collection of Service objects, using
  73.                                         '"Library.Class" as the key
  74.                                         'Object and its name
  75. Public gudtService As Service          'Stores the Service Request that needs processed
  76. Public gbNewService As Boolean         'If true a new Service is being processed.
  77.                                         'Do not retrieve another
  78. Public gbShutDown As Boolean
  79.  
  80. 'The following object variable is only used if gbEarlyBind is true
  81. Public goEarlyBoundService As APEInterfaces.Service
  82. 'The following variables are used to speed up successive
  83. 'Service request that have the same Command value (Lib.Class.Method)
  84. Public goLastServiceUsed As Object
  85. Public gsLastCommandUsed As String
  86. Public gsLastMethodUsed As String
  87. Public gsLastLibClassUsed As String
  88.  
  89.  
  90.  
  91. 'Timer related variables
  92. Private mlTimerID As Long               'The ID of the system timer created by this object
  93. Private mlInterval As Long              'The interval of this timer
  94. Private mbTimerStarted As Boolean       'If true, a system timer is set for this object
  95. Private mbTimerEnabled As Boolean       'Equals the enabled property of this object
  96.  
  97. '***********************
  98. 'Public Procedures
  99. '***********************
  100.  
  101. Public Sub GetLibClassMethod(sLibClass As String, sMethod As String, sReceived As String)
  102.     '-------------------------------------------------------------------------
  103.     'Purpose:   Called by the DoService and CheckService procedure.  Get the
  104.     '           library.class  and the method from sReceived.  sReceived is in
  105.     '           the format "library.class.method".
  106.     'In:        [sReceive]
  107.     '               Is the Command received by a client or the QueueMgr, in the
  108.     '               format "library.class.method"
  109.     'Out:       [sLibClass]
  110.     '               Returns the "library.class" of sReceive
  111.     '           [sMethod]
  112.     '               Returns the "method" of sReceive
  113.     '-------------------------------------------------------------------------
  114.     Dim iPos As Integer
  115.     
  116.     iPos = InStr(sReceived, gsCOMMAND_DELIMITER)
  117.     If iPos = 0 Then Err.Raise giINVALID_COMMAND_PARAMETER, , LoadResString(giINVALID_COMMAND_PARAMETER)
  118.     iPos = InStr((iPos + 1), sReceived, gsCOMMAND_DELIMITER)
  119.     If iPos = 0 Then Err.Raise giINVALID_COMMAND_PARAMETER, , LoadResString(giINVALID_COMMAND_PARAMETER)
  120.     sLibClass = Left$(sReceived, (iPos - 1))
  121.     sMethod = Right$(sReceived, (Len(sReceived) - iPos))
  122. End Sub
  123.  
  124. Public Function GetServiceObject(sLibClass As String) As Object
  125.     '-------------------------------------------------------------------------
  126.     'Purpose:   Called by CheckService and LoadServiceObject.  Loads the Server
  127.     '           object specified by sLibClass.  If mbPerssistent is true, see
  128.     '           if the object is already loaded and in gcServices collection.
  129.     '           If it isn't in collection, load it and add it to the collection
  130.     'In:        [sLibClass]
  131.     '               ProgID of needed server object
  132.     'Return:    Object specified by passed ProgID
  133.     'Assumption:
  134.     '           gcServices is a valid collection object if gbPersistent is true
  135.     '-------------------------------------------------------------------------
  136.     Dim oService As Object      'Object that will be return after being
  137.                                 'created a retrieved according to ProgID
  138.     If gbPersistent Then
  139.         'Turn off error handling in case
  140.         'the key sLibClass does not exist in the collection
  141.         Err.Clear
  142.         On Error Resume Next
  143.         Set oService = gcServices.Item(sLibClass)
  144.         'If Error, Object variable or With block variable not set occured
  145.         'Create object and add it to gcServices
  146.         If Err.Number = ERR_INVALID_PROCEDURE_CALL Then
  147.             'Use user defined function that handles
  148.             'Late binding versus early binding options
  149.             On Error GoTo 0
  150.             Set oService = CreateObject(sLibClass)
  151.             gcServices.Add oService, sLibClass
  152.         Else
  153.             On Error GoTo 0
  154.         End If
  155.         
  156.     Else
  157.         Set oService = CreateObject(sLibClass)
  158.     End If
  159.     Set GetServiceObject = oService
  160. End Function
  161.  
  162. Public Sub LogEvent(intMessage As Integer, lServiceID As Long)
  163.     '-------------------------------------------------------------------------
  164.     'Purpose:   To add a record to the AELogger.Logger object, if logging is on.
  165.     'In:        [intMessage]
  166.     '               Resource string key of the string that should put in the log
  167.     '               record
  168.     '           [lServiceID]
  169.     '               The ID of the Service or Task request that will form part of
  170.     '               the log record
  171.     'Assumption:
  172.     '           goLogger is a valid AELogger.Logger object if gbLog is true
  173.     '-------------------------------------------------------------------------
  174.     On Error GoTo LogEventError
  175.     If gbLog Then
  176.         goLogger.Record LoadResString(giWORKER_NAME) & Str$(glWorkerID), lServiceID, LoadResString(intMessage), GetTickCount()
  177.     End If
  178.     Exit Sub
  179. LogEventError:
  180.     Select Case Err.Number
  181.         Case RPC_E_CALL_REJECTED
  182.                'Collision error, the OLE server is busy
  183.                Dim iRetry As Integer
  184.                Dim il As Integer
  185.                Dim ir As Integer
  186.                If iRetry < giMAX_ALLOWED_RETRIES Then
  187.                    iRetry = iRetry + 1
  188.                    ir = Int((giRETRY_WAIT_MAX - giRETRY_WAIT_MIN + 1) * Rnd + giRETRY_WAIT_MIN)
  189.                    For il = 0 To ir
  190.                        DoEvents
  191.                    Next il
  192.                    Resume
  193.                Else
  194.                    'We reached our max retries
  195.                    'This would occur when clients are sending
  196.                    'there logs
  197.                    LogError Err, gudtService.ID
  198.                    Exit Sub
  199.                End If
  200.         Case Else
  201.             LogError Err, gudtService.ID
  202.             Exit Sub
  203.     End Select
  204.     Exit Sub
  205. End Sub
  206.  
  207. Public Sub LogError(ByVal oErr As ErrObject, lServiceID As Long)
  208.     '-------------------------------------------------------------------------
  209.     'Purpose:   To add an error record to the AELogger.Logger object,
  210.     '           if logging is on.
  211.     'In:        [oErr]
  212.     '               Error object which hold the error information that will
  213.     '               form the log record
  214.     '           [lServiceID]
  215.     '               The ID of the Service or Task request that will form part of
  216.     '               the log record
  217.     'Assumption:
  218.     '           goLogger is a valid AELogger.Logger object if gbLog is true
  219.     '-------------------------------------------------------------------------
  220.     'Log error if logging is on
  221.     'Check that the logger isn't nothing to avoid an error
  222.     'occurring here, because this is often called by error handling
  223.     If Not (goLogger Is Nothing) And gbLog Then goLogger.Record LoadResString(giWORKER_NAME) & Str$(glWorkerID), lServiceID, LoadResString(giERROR_PREFIX) & Str$(oErr.Number) & gsSEPERATOR & oErr.Source & gsSEPERATOR & oErr.Description, GetTickCount()
  224. End Sub
  225.  
  226. Public Sub SetInterval(lInterval As Long)
  227.     '-------------------------------------------------------------------------
  228.     'Purpose:   Changes the interval of the Timer
  229.     'In:        [lInterval]
  230.     '               The new interval to set the timer to.
  231.     'Effects:   [mlInterval]
  232.     '               Becomes equal to lInterval
  233.     '           Calls SetInterval only if there is a system timer corresponding
  234.     '           to this object
  235.     '-------------------------------------------------------------------------
  236.     If mlInterval <> lInterval Then
  237.         mlInterval = lInterval
  238.         If mbTimerStarted Then
  239.             ChangeInterval lInterval, mlTimerID
  240.         End If
  241.     End If
  242. End Sub
  243.  
  244. Public Sub SetEnabled(bEnabled As Boolean)
  245.     '-------------------------------------------------------------------------
  246.     'Purpose:   Starts a system timer if bEnabled is true
  247.     '           Stops the timer if bEnabled is false
  248.     'Effects:   [mbTimerEnabled] is set equal to bEnabled
  249.     '           [mbTimerStarted] is set to true if StartTimer succeeds
  250.     '                            is set to false if StopTimer succeeds
  251.     '           If true a new system timer is started and the TimerID
  252.     '           is stored in a class level variable so that this object
  253.     '           can effect the specific system timer.
  254.     '-------------------------------------------------------------------------
  255.     Dim lReturn As Long
  256.     'If shut down flag is true always disable timer
  257.     If gbShutDown Then bEnabled = False
  258.     
  259.     mbTimerEnabled = bEnabled       'Even if calling KillTimer fails
  260.                                     'This flag will stop processing of TimerProc events
  261.     If bEnabled <> mbTimerStarted Then
  262.         If bEnabled Then
  263.             mlTimerID = StartTimer(mlInterval)
  264.             If mlTimerID <> 0 Then
  265.                 mbTimerStarted = True
  266.             End If
  267.         Else
  268.             lReturn = StopTimer(mlTimerID)
  269.             If lReturn = 1 Then
  270.                 mbTimerStarted = False
  271.             End If
  272.         End If
  273.     End If
  274. End Sub
  275.  
  276. '********************
  277. 'Private Procedures
  278. '********************
  279. Private Sub CheckService()
  280.     '-------------------------------------------------------------------------
  281.     'Purpose:   Called by the PollQueue procedure.  Checks to see of service
  282.     '           task request data was returned by call to QueueMgr.  If it
  283.     '           was, CheckService loads the needed Service provider object
  284.     '           and calls it to accomplish the task. The this procedure poles
  285.     '           the QueueMgr again to get a new task request.  In the same call
  286.     '           the finished service request results are returned as parameters.
  287.     '           The new service request is received as the result.
  288.     '           If no task, request is returned
  289.     '           the timer is started which will continue poling the queue.
  290.     '           Otherwise, CheckService will continue a cycle as long as the
  291.     '           the QueueMgr returns a task request when poled.
  292.     'Assumptions:
  293.     '           If [gbNewService] is true, there is valid task request data
  294.     '           in the [gudtService] type.
  295.     '           [goQueueDelegator] is a valid reference to AEQueueMgr.clsQueueDelegator
  296.     '           if the goQueueDelegator.GetServiceRequest returns an integer value of giCLOSE_WORKER_NOW
  297.     '           then the Worker object has been released from the QueueMgr.
  298.     'Effects:
  299.     '           If the goQueueDelegator.GetServiceRequest returns a value of giCLOSE_WORKER_NOW
  300.     '           this procedure will close this Worker application
  301.     '           [gudtService]
  302.     '               After using the data in this type, this procedure will call
  303.     '               the QueueMgr again, and fill this type with new data if a
  304.     '               task request was returned.
  305.     '           [goEarlyBoundService]
  306.     '               Set equal to AEService.Service class object if passed ProgID
  307.     '               equals "AEService.Service"
  308.     '           [gsLastCommandUsed]
  309.     '               Will get updated with the current value of gudtService.Command
  310.     '           [gsLastLibClassUsed]
  311.     '               Will get updated with the current Lib.Class portion of
  312.     '               of gudtService.Command
  313.     '           [gsLastMethodUsed]
  314.     '               Will get updated with the current .Method portion of
  315.     '               gudtService.Command
  316.     '           [goLastServiceUsed]
  317.     '               Set equal to the object created using the passed ProgID
  318.     '           Timer is disabled on entrance and enabled if
  319.     '               loop is exited becaue QueueMgr did not return a task request
  320.     '-------------------------------------------------------------------------
  321.     Dim sError As String        'Error handling places error information into
  322.                                 'this string in the format of "number; source; description"
  323.                                 'passed to QueueMgr with return data.  Client
  324.                                 'receives this.  Elements of error collection
  325.                                 'are delimited by a semicolon and a space.
  326.     Dim iRetry As Integer       'Counter for how many attempts are made to call
  327.                                 'an OLE server.
  328.     Dim vServiceData As Variant 'value returned by QueueMgr as a variant array
  329.                                 'Elements of it are placed into gudtService type
  330.     Dim bCallingQueue As Boolean
  331.     
  332.     On Error GoTo CheckServiceError
  333.     'Disable timer because it only needs enabled
  334.     'When there is a new Service
  335.     SetEnabled False
  336.     'If there is a new Service process it
  337.     If gbNewService Then
  338.         Do
  339.             iRetry = 0
  340.             
  341.             If Not gsLastCommandUsed = gudtService.Command Or goLastServiceUsed Is Nothing Then
  342.                 'Get the library.class from gudtService.Command
  343.                 'gudtService.Command is in the format "library.class.method"
  344.                 gsLastCommandUsed = gudtService.Command
  345.                 GetLibClassMethod gsLastLibClassUsed, gsLastMethodUsed, gudtService.Command
  346.                 'Get the Service object
  347.                 Set goLastServiceUsed = GetServiceObject(gsLastLibClassUsed)
  348.                 If gbEarlyBind Then
  349.                     Set goEarlyBoundService = goLastServiceUsed
  350.                 End If
  351.             End If
  352.             'Call the execute method of the class object
  353.             'passing the method string and the send data as variant,
  354.             'and the return data as variant by reference
  355.             LogEvent giEXECUTE_BEGIN, gudtService.ID
  356.             If gbEarlyBind Then
  357.             'Use the Earlybound object reference
  358.                 If gudtService.DataPresent Then
  359.                     goEarlyBoundService.Execute gsLastMethodUsed, gudtService.Data, gudtService.Return
  360.                 Else
  361.                     goEarlyBoundService.Execute gsLastMethodUsed
  362.                 End If
  363.             Else
  364.                 If gudtService.DataPresent Then
  365.                     goLastServiceUsed.Execute gsLastMethodUsed, gudtService.Data, gudtService.Return
  366.                 Else
  367.                     goLastServiceUsed.Execute gsLastMethodUsed
  368.                 End If
  369.             End If
  370.             LogEvent giEXECUTE_END, gudtService.ID
  371.             
  372. SendServiceResult:
  373.  
  374.             'Notify QueueManager that Service is completed
  375.             'And worker is ready for a new Service
  376.             'QueueMgr can return another Service
  377.             'In the same call pass the Service Request results
  378.             'to the QueueMgr as parameters.  The Expediter will
  379.             'get the Service results from the Queue manager
  380.             LogEvent giGET_REQUEST_BEGIN, gudtService.ID
  381.             iRetry = 0
  382.             
  383.             'Call the QueueMgr to get a new Service Request
  384.             bCallingQueue = True
  385.             vServiceData = goQueueDelegator.GetServiceRequest(glWorkerID, CVar(gudtService.ID), gudtService.Return, CVar(sError))
  386.             bCallingQueue = False
  387.             
  388.             'Check if results were returned
  389.             'The QueueMgr will not return results if it has no Service Requests
  390.             'The QueueMgr may return an integer value of giCLOSE_WORKER_NOW
  391.             'If it does close this worker
  392.             If VarType(vServiceData) = (vbArray + vbVariant) Then
  393.                 'Results were returned
  394.                 With gudtService
  395.                     .ID = vServiceData(giSERVICE_ID_ELEMENT)
  396.                     .Command = vServiceData(giCOMMAND_ELEMENT)
  397.                     .DataPresent = vServiceData(giDATA_PRESENT_ELEMENT)
  398.                     Select Case VarType(vServiceData(giSERVICE_DATA_ELEMENT))
  399.                         Case vbNull, vbEmpty
  400.                             .Data = Null
  401.                         Case vbObject, vbError, vbDataObject
  402.                             Set .Data = vServiceData(giSERVICE_DATA_ELEMENT)
  403.                         Case Else
  404.                             .Data = vServiceData(giSERVICE_DATA_ELEMENT)
  405.                     End Select
  406.                 End With
  407.                 'If an Service was passed back call CheckService again
  408.                 'Log whether or not a new Service was received
  409.                 LogEvent giGET_REQUEST_END_NEW_SERVICE, gudtService.ID
  410.                 gbNewService = True
  411.             Else
  412.                 'Check to see if the Worker should shut down!!!!
  413.                 If VarType(vServiceData) = vbInteger Then
  414.                     If vServiceData = giCLOSE_WORKER_NOW Then
  415.                         'Close the Worker
  416.                         Exit Sub        'The Worker Terminate event will do the rest
  417.                     End If
  418.                 End If
  419.                 
  420.                 'Results were not returned. See if Worker needs kept alive by Setting
  421.                 'a timer or if it needs shutdown because ShutDown was called.
  422.                 LogEvent giGET_REQUEST_END_NO_SERVICE, gudtService.ID
  423.                 gbNewService = False
  424.                 If Not gbShutDown Then
  425.                     SetEnabled True
  426.                 End If
  427.             End If
  428.         Loop Until (VarType(vServiceData) <> vbArray + vbVariant) Or gbShutDown
  429.     End If
  430.     Exit Sub
  431. CheckServiceError:
  432.     Dim il As Integer
  433.     Dim ir As Integer
  434.     Select Case Err.Number
  435.         Case RPC_E_CALL_REJECTED
  436.                'Collision error, the OLE server is busy
  437.                If iRetry < giMAX_ALLOWED_RETRIES Then
  438.                    iRetry = iRetry + 1
  439.                    ir = Int((giRETRY_WAIT_MAX - giRETRY_WAIT_MIN + 1) * Rnd + giRETRY_WAIT_MIN)
  440.                    For il = 0 To ir
  441.                        DoEvents
  442.                    Next il
  443.                    'Shutdown may be called during DoEvents loop
  444.                    If gbShutDown Then
  445.                         Exit Sub
  446.                    Else
  447.                         LogEvent giCALL_REJECTED_RETRY, gudtService.ID
  448.                         Resume
  449.                    End If
  450.                Else
  451.                    'We reached our max retries
  452.                     LogError Err, gudtService.ID
  453.                End If
  454.         Case Is > giERROR_THRESHOLD
  455.             'Create error string and pass it back to the client
  456.             'Through the QueueMgr and Expediter
  457.             sError = Err.Source & "; " & CStr(Err.Number + vbObjectError) & "; " & Err.Source & gsSEPERATOR & Err.Description
  458.             LogError Err, gudtService.ID
  459.             Resume SendServiceResult
  460.         Case ERR_OBJECT_VARIABLE_NOT_SET
  461.             LogError Err, gudtService.ID
  462.             If Not bCallingQueue Then
  463.                 sError = Err.Source & "; " & CStr(Err.Number) & "; " & Err.Description
  464.                 Resume SendServiceResult
  465.             End If
  466.         Case Else
  467.             LogError Err, gudtService.ID
  468.             sError = Err.Source & "; " & CStr(Err.Number) & "; " & Err.Description
  469.             Resume SendServiceResult
  470.     End Select
  471.     'Reset timer and flag so that Worker will continue
  472.     'processing other Services even though this one may have failed.
  473.     SetEnabled True
  474.     gbNewService = False
  475.     Exit Sub
  476. End Sub
  477.  
  478. Private Sub PollQueue()
  479.     '-------------------------------------------------------------------------
  480.     'Purpose:   Called by the TimerProc.  Calls QueueMgr to
  481.     '           received task request data.  If data is returned, timer is
  482.     '           disabled and CheckService is called to process it.
  483.     'Assumptions:
  484.     '           If CheckService is processing a TaskRequest [gbNewService] is true.
  485.     '           [moQueueDelegatorMgr] is a valid refererence to AEQueueMgr.goQueueDelegator
  486.     'Effects:
  487.     '           [gudtService]
  488.     '               is filled with task request data if call to QueueMgr
  489.     '               returns a task request.
  490.     '           Timer is disabled if task request is received
  491.     '           [gbNewService] is made true if a task request is received
  492.     '-------------------------------------------------------------------------
  493.     Dim vServiceData As Variant     'Return value of moQueueDelegatorMgr.GetServiceRequest
  494.                                     'if a task request is returned this will be
  495.                                     'a variant array.  Elements of the array will
  496.                                     'be placed in the gudtService type
  497.     On Error GoTo PoleQueueError
  498.     'If I am already processing a Service do not pole the QueueManager
  499.     If gbNewService Or gbShutDown Then Exit Sub
  500.     vServiceData = goQueueDelegator.GetServiceRequest(glWorkerID)
  501.     If VarType(vServiceData) = vbArray + vbVariant Then
  502.         With gudtService
  503.             .ID = vServiceData(giSERVICE_ID_ELEMENT)
  504.             .Command = vServiceData(giCOMMAND_ELEMENT)
  505.             .DataPresent = vServiceData(giDATA_PRESENT_ELEMENT)
  506.             Select Case VarType(vServiceData(giSERVICE_DATA_ELEMENT))
  507.                 Case vbNull, vbEmpty
  508.                     .Data = Null
  509.                 Case vbObject, vbError, vbDataObject
  510.                     Set .Data = vServiceData(giSERVICE_DATA_ELEMENT)
  511.                 Case Else
  512.                     .Data = vServiceData(giSERVICE_DATA_ELEMENT)
  513.             End Select
  514.         End With
  515.         'If an Service was passed back call CheckService again
  516.         'Log whether or not a new Service was received
  517.         LogEvent giGET_REQUEST_END_NEW_SERVICE, gudtService.ID
  518.         gbNewService = True
  519.         SetEnabled False
  520.         CheckService
  521.     Else
  522.         gbNewService = False
  523.         SetEnabled True
  524.     End If
  525.     Exit Sub
  526. PoleQueueError:
  527.     Select Case Err.Number
  528.         Case RPC_E_CALL_REJECTED
  529.             'Collision error, the OLE server is busy
  530.             Dim il As Integer
  531.             Dim ir As Integer
  532.             Dim iRetry As Integer
  533.             If iRetry < giMAX_ALLOWED_RETRIES Then
  534.                 iRetry = iRetry + 1
  535.                 ir = Int((giRETRY_WAIT_MAX - giRETRY_WAIT_MIN + 1) * Rnd + giRETRY_WAIT_MIN)
  536.                 For il = 0 To ir
  537.                     DoEvents
  538.                 Next il
  539.                 'Shutdown may be called during DoEvents loop
  540.                 If gbShutDown Then Exit Sub Else Resume
  541.             Else
  542.                 'We reached our max retries
  543.                 LogError Err, gudtService.ID
  544.                 Exit Sub
  545.             End If
  546.         Case Is > giERROR_THRESHOLD
  547.             'Create error string and pass it back to the client
  548.             'Through the expediter and QueueMgr
  549.             LogError Err, gudtService.ID
  550.             SetEnabled True
  551.             Exit Sub
  552.         Case Else
  553.             LogError Err, gudtService.ID
  554.             SetEnabled True
  555.             Exit Sub
  556.     End Select
  557. End Sub
  558.  
  559. Private Function StartTimer(lInterval As Long) As Long
  560.     '-------------------------------------------------------------------------
  561.     'Purpose:   Starts a system timer
  562.     'In:        [lInterval]
  563.     '           The interval in milliseconds for the desired timer
  564.     'Effects:   Calls the SetTimer API, passing the AddressOF the TimerProc
  565.     '           Function and lInterval
  566.     '-------------------------------------------------------------------------
  567.     StartTimer = SetTimer(0, 0, lInterval, AddressOf TimerProc)
  568. End Function
  569.  
  570. Private Function StopTimer(lTimerID As Long) As Long
  571.     '-------------------------------------------------------------------------
  572.     'Purpose:   Stops a specific system timer
  573.     'In:        [lTimerID]
  574.     '           The ID of the specific system timer to stop
  575.     'Effects:   Calls the KillTimerID API, passing lTimerID
  576.     '-------------------------------------------------------------------------
  577.     StopTimer = KillTimer(0, lTimerID)
  578. End Function
  579.  
  580. Private Sub ChangeInterval(lInterval As Long, lTimerID As Long)
  581.     '-------------------------------------------------------------------------
  582.     'Purpose:   Changes the interval of an alreading existing system timer
  583.     'In:        [lTimerID]
  584.     '           The ID of the specific system timer to change
  585.     '           [lInterval]
  586.     '           The interval to change the timer to.
  587.     'Effects:   Calls the SetTimer API, passing lTimerID, lInterval, and the
  588.     '           AddressOf TimerProc
  589.     '-------------------------------------------------------------------------
  590.     Dim lResult As Long
  591.     lResult = SetTimer(0, lTimerID, lInterval, AddressOf TimerProc)
  592. End Sub
  593.  
  594. Private Sub TimerProc(ByVal lHwnd As Long, ByVal lMsg As Long, ByVal lTimerID As Long, ByVal lTime As Long)
  595.     '-------------------------------------------------------------------------
  596.     'Purpose:   Address of this function is passed in the SetTimer API.  When
  597.     '           a system timer is started it calls this function every set
  598.     '           interval
  599.     '-------------------------------------------------------------------------
  600.     Static stbInPollQueue As Boolean    'Static flag is used to keep PollQueue
  601.                                         'from being entered while it is in a
  602.                                         'DoEvents loop to handle error
  603.                                         'RPC_E_CALL_REJECTED
  604.     On Error Resume Next
  605.     If mbTimerEnabled And (Not stbInPollQueue) Then
  606.         stbInPollQueue = True
  607.         PollQueue
  608.         stbInPollQueue = False
  609.     End If
  610. End Sub
  611.  
  612.  
  613.