VB6 Outlook automation - vba

I have a block of code that will send emails using Outlook on the users PC. However when we email a bigger amount, it seems as though outlook isn't working as fast as the application so the application opens outlook sends the first email, but the second time it tries to open outlook but gets errors such as Outlook not available etc. So Outlook is taking to long to do the task while the application is trying to create the object again. I was using DoEvents previously but that doesn't work. Is there anyway to wait for outlook to finish its job Before it continues?
In this scenario outlook is not open yet, it is closed and the vb6 application is opening it.

You can trap Err.Number or Err.Description and generate a message box for the user to click to try again (Resume) or cancel (Exit Sub).
You may loop continually, attempting to create, to avoid user intervention. At some point generate the message box so users know the app is still working.
Edit 2015 05 06 - Maybe something less abstract. VBA but should be generic enough for other languages.
Option Explicit
Private Sub errorHandler_429()
Dim uErrorMsg1 As String
Dim uErrorMsg As String
Dim errCount As Long
uErrorMsg1 = "Click OK to try again."
On Error GoTo ErrorHandler
restart:
' code that triggers an error here
Err.Raise 429 ' <-- For testing
'Err.Raise 430 ' <--- For testing
ExitRoutine:
Exit Sub
ErrorHandler:
Select Case Err.Number
Case 429
errCount = errCount + 1
uErrorMsg = Err.Number & ": " & Err.Description & " occurred " & errCount & " times."
Debug.Print uErrorMsg
If (errCount Mod 200) = 0 Then
uErrorMsg = uErrorMsg1 & vbCr & vbCr & _
"Error # " & Err.Number & " was generated by " & _
Err.Source & Chr(13) & Chr(13) & Err.Description
Debug.Print uErrorMsg
If MsgBox(uErrorMsg, vbOKCancel, "errorHandler_429", Err.HelpFile, Err.HelpContext) = vbOK Then
Resume restart
Else
Resume ExitRoutine
End If
Else
Resume restart
End If
Case Else
uErrorMsg = Err.Number & ": " & Err.Description
'Debug.Print uErrorMsg
MsgBox uErrorMsg, , "errHandler_429", Err.HelpFile, Err.HelpContext
Resume ExitRoutine
End Select
End Sub
Sub errHandler_Description()
' Where the error number is negative and inconsistent
Dim uErrorMsg1 As String
Dim uErrorMsg As String
Dim errCount As Long
Dim LErrDesc As String
uErrorMsg1 = "Click OK to try again."
On Error GoTo ErrorHandler
restart:
' code that triggers an error here
Err.Raise 429 ' <--- For testing
'Err.Raise 430 ' <--- For testing
ExitRoutine:
Exit Sub
ErrorHandler:
LErrDesc = Left(Err.Description, 51)
Debug.Print " LErrDesc: " & LErrDesc
Select Case LErrDesc
Case "ActiveX component can't create object"
errCount = errCount + 1
Debug.Print " errCcount: " & errCount
If (errCount Mod 200) = 0 Then
uErrorMsg = uErrorMsg1 & vbCr & vbCr & _
"Error # " & Err.Number & " was generated by " & _
Err.Source & Chr(13) & Chr(13) & Err.Description
'Debug.Print uErrorMsg
If MsgBox(uErrorMsg, vbOKCancel, "errHandler_Description", Err.HelpFile, Err.HelpContext) = vbOK Then
Resume restart
Else
Resume ExitRoutine
End If
Else
Resume restart
End If
Case Else
uErrorMsg = "This error has not been handled."
uErrorMsg = uErrorMsg & vbCr & vbCr & _
"Error # " & Err.Number & " was generated by " & _
Err.Source & Chr(13) & Chr(13) & Err.Description
Debug.Print uErrorMsg
MsgBox uErrorMsg, , "errHandler_Description", Err.HelpFile, Err.HelpContext
Resume ExitRoutine
End Select
End Sub

Related

Loop through continuous form records and adding them to a table

Good afternoon,
I have a bound continuous form with a yes/no checkbox for each of the records shown. I'd like to have my users be able to click a "Select all" control and automatically have each one of those records be added to a different table.
So far, I have my loop working but not quite sure where to insert the proper code to add the records. I am using a frame control with a with a "Select all" "Deselect all" options. The [PrintPart] is the Yes/No field in the form.
Many thanks.
Private Sub SelectionFrame_Click()
Dim SQL as String
On Error GoTo errHandler
SQL = "INSERT INTO PARTS_T ([PRINTORDER], [PART_TITLE], [PARTID])
VALUES (" & Me.RecordsetClone.RecordCount + 1 & "," & Chr(34) &
Me.PART_TITLE & Chr(34) & "," & Me.PARTID & ");"
'Toggle select/deselect all
Select Case Me.SelectionFrame
Case 1 'Select
With Me.RecordsetClone
.MoveFirst
Do While Not .EOF
.Edit
!PrintPart = True
RunSQLCode
.Update
.MoveNext
Loop
End With
Case 2 'Deselect
With Me.RecordsetClone
.MoveFirst
Do While Not .EOF
.Edit
!PrintPart = False
.Update
.MoveNext
Loop
End With
End Select
Exit Sub
errHandler:
MsgBox "The following error has occurred: " & vbNewLine & vbNewLine & "Error Number: " & Err.Number & vbNewLine & "Error Description: " & Err.Description, vbCritical, "Error - " & APPNAME
End Sub
Don't run repeated SQL. DAO is way simpler and faster:
Private Sub SelectionFrame_Click()
Dim Source As DAO.Recordset
Dim Target As DAO.Recordset
Dim SQL As String
Dim PrintPart As Boolean
Dim PrintOrder As Long
On Error GoTo errHandler
Set Source = Me.RecordsetClone
PrintOrder = Source.RecordCount
If PrintOrder > 0 Then
SQL = "Select * From PARTS_T"
Set Target = CurrentDb.OpenRecordset(SQL, dbOpenDynaset, dbAppendOnly)
PrintPart = Me.SelectionFrame
Source.MoveFirst
While Not Source.EOF
If Source!PrintPart.Value <> PrintPart Then
Source.Edit
Source!PrintPart.Value = PrintPart
Source.Update
End If
Target.AddNew
Target!PRINTORDER.Value = PrintOrder + 1
Target!PART_TITLE.Value = Source!PART_TITLE.Value
Target!PARTID.Value = Source!PARTID.Value
Target.Update
Wend
Target.Close
End If
Source.Close
Exit Sub
errHandler:
MsgBox "The following error has occurred: " & vbNewLine & vbNewLine & "Error Number: " & Err.Number & vbNewLine & "Error Description: " & Err.Description, vbCritical, "Error - " & APPNAME
End Sub

What is the proper way to add retry loop to VBA code

In the following code, we occasionally get collision errors. If it would wait a second and retry, it would go through.
I want it to try once. If it fails, log the error and retry. If it fails 3 times, MsgBox to the user, give up and return. The only way I can think of is using a GOTO back to the ExeHandler. Seems there should be a better way.
Public Function RunADO(strContext As String, strSQL As String, Optional intErrSilent As Integer = 0, Optional intErrLog = -1) As Integer
On Error GoTo ErrHandler
ExeHandler:
PostToLog strContext, "SQL: " & strSQL
CurrentProject.Connection.Execute strSQL, dbFailOnError
RunADO = -1
Exit Function
ErrHandler:
RunADO = 0
If intErrSilent = 0 Then
MsgBox Err.Number & ": " & Err.Description, vbCritical, "Run ADO"
End If
If intErrLog = -1 Then
PostErrorToLog Err.Number, strContext, Err.Source & ":" & Err.Description & ": " & "SQL: " & strSQL
End If
End Function
Perhaps something like this...
Option Explicit
Private Const MaxRetries As Long = 3
Public Function RunADO(strContext As String, strSQL As String, Optional intErrSilent As Integer = 0, Optional intErrLog = -1) As Integer
Dim attemptCounter As Long
For attemptCounter = 1 To MaxRetries
RunADO = RunADOInternal(strContext, strSQL, intErrSilent, intErrLog)
If RunADO = -1 Then
Exit Function
End If
If intErrSilent = 0 And attemptCounter >= MaxRetries Then
MsgBox Err.Number & ": " & Err.Description, vbCritical, "Run ADO"
RunADO = 0
Exit Function
End If
If intErrLog = -1 Then
PostErrorToLog Err.Number, strContext, Err.Source & ":" & Err.Description & ": " & "SQL: " & strSQL
End If
Application.Wait (Now + TimeValue("0:00:01"))
Next attemptCounter
End Function
Private Function RunADOInternal(strContext As String, strSQL As String, Optional intErrSilent As Integer = 0, Optional intErrLog = -1) As Integer
On Error GoTo ErrHandler
PostToLog strContext, "SQL: " & strSQL
CurrentProject.Connection.Execute strSQL, dbFailOnError
RunADO = -1
Exit Function
ErrHandler:
RunADO = 0
End Function
Consider using a Do / Loop statement that ends when the maximum number of attempts have been made.
Public Function RunADO(strContext As String, _
strSQL As String, _
Optional intErrSilent As Integer, _
Optional intErrLog = -1) As Integer
Dim Attempts As Integer
Do While Attempts < 3
On Error Resume Next
PostToLog strContext, "SQL: " & strSQL
CurrentProject.Connection.Execute strSQL, dbFailOnError
If Err.Number Then
If intErrSilent = 0 Then
MsgBox Err.Number & ": " & Err.Description, vbCritical, "Run ADO"
End If
If intErrLog = -1 Then
PostErrorToLog Err.Number, strContext, _
Err.Source & ":" & Err.Description & ": " & "SQL: " & strSQL
End If
Attempts = Attempts + 1
Else
RunADO = -1
Exit Do
End If
Loop
End Function

How to set a variable referring to the library database

Currently I'm working on a library database for all my Access apps which have common code and forms in it. It is going quite well, but the only thing I cannot discover is how to set a variable referring to the reference. The library name is set by a constant and at startup is checked if the file exists in the app folder and if this is equal to the path stored in the reference.
However, I want to refer to the library with a short variable "dbl", because I don't want to use the library name every time. This name might change as well. How do I set the variable to do this? I have tried Set dbl = Application.References(APP_LIB), and this is accepted as valid, but I cannot call any routine or form with this variable.
Thx!
Art.
Public Function CkLib()
'Needs to stay in the App Module!
Dim ref As Reference
Dim strLib As String
On Error GoTo Err_Proc
For Each ref In Application.References
If ref.Name = APP_LIB Then
strLib = CurrentProject.Path & "\" & ref.Name & "." & APP_LIB_TYPE
If Dir(strLib, vbNormal) = "" Then 'File does not exist
MsgBox "The app library " & APP_LIB & " is missing. Please reinstall the app or ask for support!", vbCritical + vbOKOnly, APP_NAME & " App Error"
DoCmd.Quit acQuitSaveNone
Else
If ref.FullPath <> strLib Then 'Path needs to be updated
References.Remove ref
References.AddFromFile strLib
End If
Exit For
End If
End If
Next ref
If Nz(strLib, "") = "" Then
'Try to add ref
If Dir(CurrentProject.Path & "\" & APP_LIB & "." & APP_LIB_TYPE, vbNormal) <> "" Then
References.AddFromFile strLib
Else
MsgBox "Missing reference to app library " & APP_LIB & "! Please reinstall the app or ask for support!", vbCritical + vbOKOnly, APP_NAME & " App Error"
DoCmd.Quit acQuitSaveNone
End If
End If
Set dbl = Application.References(APP_LIB)
Exit_Proc:
Exit Function
Err_Proc:
Select Case Err.number
Case Else
MsgBox "Error: " & Trim(Str(Err.number)) & vbCrLf & _
"Desc: " & Err.description & vbCrLf & vbCrLf & _
"Module: Mod_Generic" & vbCrLf & _
"Function: CkLib", _
vbCritical, "Error!"
End Select
Resume Exit_Proc
End Function

Method ‘FindFirst’ of object ‘Recordset2’ failed. After not saving new record

In a form, create a new record, edit some data but before saving it use a combo box on the form to select another record to navigate to. This triggers the cboSalePicker_AfterUpdate. Then during this sub Form_BeforeUpdate executes. The user clicks no on the MsgBox to not save the new record. Then the rest of cboSalePicker_AfterUpdate is executed however the following error message is displayed:
Error Message
Error number -2147417848: Method ‘FindFirst’ of object ‘Recordset2’ failed.
Associated with the line Me.Recordset.FindFirst "[SaleID] = " & Str(Nz(cboSalePicker.Value, 0))
However, if the new record is saved no error is produced and the code performs as expected.
Form_BeforeUpdate
Private Sub Form_BeforeUpdate(Cancel As Integer)
On Error GoTo ErrorHandler
Dim strMsg As String
Dim iResponse As Integer
'Specify the mesage to display
strMsg = "Do you wish to save the changes?" & Chr(10)
strMsg = strMsg & "Click Yes to Save or No to Discard changes."
'Display the msg box
iResponse = MsgBox(strMsg, vbQuestion + vbYesNo, "Save Record?")
'Check response
If iResponse = vbNo Then
'Undo the change.
DoCmd.RunCommand acCmdUndo
'Cancel the update
Cancel = True
End If
Exit Sub
ErrorHandler:
MsgBox "Error number " & Err.Number & ": " & Err.Description
End Sub
cboSalePicker_AfterUpdate
Private Sub cboSalePicker_AfterUpdate()
On Error GoTo ErrorHandler
Me.Recordset.FindFirst "[SaleID] = " & Str(Nz(cboSalePicker.Value, 0))
Exit Sub
ErrorHandler:
MsgBox "Error number " & Err.Number & ": " & Err.Description
End Sub
Thanks
You are converting Your SaleID into a String using this
Str(Nz(cboSalePicker.Value, 0))
But your find first is looking for a number. If SaleID is a number then remove the Str() function from your code around the combobox value.
To show the concatenation try this
Private Sub cboSalePicker_AfterUpdate()
On Error GoTo ErrorHandler
Dim sCriteria as String
sCriteria = "[SaleID] = " & Nz(Me.cboSalePicker, 0)
debug.print sCriteria
Me.Recordset.FindFirst sCriteria
Exit Sub
ErrorHandler:
MsgBox "Error number " & Err.Number & ": " & Err.Description
End Sub
Comment out the first error handler line whilst you are debugging things.

How can I manage error code SQL in MS access form database?

I want manage SQL server error code in access form
sample duplicate error from SQL server
In Access VBA, you need to use:
On Error GoTo Error_Handler
' YOUR CODE HERE
.
.
.
Return_Label:
Exit Function
Error_Handler:
'What goes here depends on the data access model
Resume Return_Label
You may have to retrieve the Errors collection of the Error object as described here.
It shows this example code:
Sub DescriptionX()
Dim dbsTest As Database
On Error GoTo ErrorHandler
' Intentionally trigger an error.
Set dbsTest = OpenDatabase("NoDatabase")
Exit Sub
ErrorHandler:
Dim strError As String
Dim errLoop As Error
' Enumerate Errors collection and display properties of
' each Error object.
For Each errLoop In Errors
With errLoop
strError = _
"Error #" & .Number & vbCr
strError = strError & _
" " & .Description & vbCr
strError = strError & _
" (Source: " & .Source & ")" & vbCr
strError = strError & _
"Press F1 to see topic " & .HelpContext & vbCr
strError = strError & _
" in the file " & .HelpFile & "."
End With
MsgBox strError
Next
Resume Next
End Sub