VBA Selection.InlineShapes.AddPicture keeps pasting on initial document - ms-access

The below code is part of a program that populates a word document from an access database.
This part of the code adds a picture with the user's signature at the bookmark location 'Signature'. For some reason it works the first attempt, but the nex time it runs it pastes at the initial document's bookmark location and not the new document.
appword.ActiveDocument.Bookmarks("Signature").Select
Selection.Find.ClearFormatting
With Selection.Find
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.InlineShapes.AddPicture FileName:= _
SASignaturePath, _
LinkToFile:=False, SaveWithDocument:=True
I've attempted to use a few other selection commands like:
Selection.Goto What:=wdGoToBookmark, Name:="Signature"
and
objWork.ActiveDocument.Bookmarks("Signature").Range.Select
with no luck.
Edit: Adding additional info as requested.
The entire function pulls some global variables from access and autopopulates a word document with them. The global variable 'SASignaturePath' has the file location of the signature image.
Below is the entire function being called when the user presses the 'create cost letter' button.
Function fillCostLetter()
Dim appword As Word.Application
Dim doc As Word.Document
Dim Path As String
TodayDate = Format(Now(), "mmmm dd, yyyy")
On Error Resume Next
Error.Clear
Set appword = GetObject(, "word.application")
If Err.Number <> 0 Then
Set appword = New Word.Application
appword.Visible = True
End If
Path = "Z:\DocFolder\ServiceAssociateToolBox\CostLetterTestStage.docx"
Set doc = appword.Documents.Open(Path, , True)
With doc
.FormFields("Date").Result = TodayDate
.FormFields("BillName").Result = BillName
.FormFields("BillAmmount").Result = BillAmmount
.FormFields("BillAddress").Result = BillAddress
.FormFields("BillAmmount").Result = BillAmmount
.FormFields("BillCity").Result = BillCity
.FormFields("BillState").Result = BillState
.FormFields("BillZip").Result = BillZip
.FormFields("SiteZip").Result = SiteZip
.FormFields("SiteState").Result = SiteState
.FormFields("SiteCity").Result = SiteCity
.FormFields("SiteStreetType").Result = SiteStreetType
.FormFields("SiteStreetName").Result = SiteStreetName
.FormFields("SiteStreetNo").Result = SiteStreetNo
.FormFields("BillName2").Result = BillName
.FormFields("WorkRequest").Result = WR_NO
.FormFields("CustName").Result = CustName
.FormFields("SAName").Result = SAName
.FormFields("SADeptartment").Result = SADept
.FormFields("SAPhone").Result = SAPhone
Selection.Find.ClearFormatting
With Selection.Find
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
ActiveDocument.Bookmarks("Signature").Range.InlineShapes.AddPicture FileName:= _
SASignaturePath, _
LinkToFile:=False, SaveWithDocument:=True
Selection.Goto What:=wdGoToLine, Which:=wdGoToAbsolute, Count:=1
End With
appword.Visible = True
appword.Activate
Set doc = Nothing
Set appword = Nothing
End Function

Changing and then using the selection as an insertion point is generally bad practice. What you should rather do is use the actual Range of the bookmark, which can be obtained by calling:
ActiveDocument.Bookmarks("BookmarkName").Range
The obtained Range can then be used in your above code instead of Selection, i.e.
ActiveDocument.Bookmarks("BookmarkName").Range.InlineShapes.AddPicture (...)

Related

Not in List Error after replacing Chr(), yet added to list correctly

I have some combo boxes with code for adding new items to the source table with a form when it doesn't exist.
The code will replace Chr(47) / and Chr(92) \ with Chr(45) - if present. This is done because a file name is created using concatenation later.
The problem is if a character is replaced, I get an Access error that the item is not in the list. This does not happen if a character is not replaced. In both instances the correct items are added to the corresponding tables.
I have tried replacing the character before passing it to OpenArgs, AfterUpdate, on the form after it opens, etc. The error does not break so the program is working, I just want to eliminate a unnecessary pop-up message.
Any help is greatly appreciated.
Private Sub cboManual_NotInList(NewData As String, Response As Integer)
Dim MyMessage As String
Dim myButtons As Integer
Dim myTitle As String
Dim strSQL As String
On Error GoTo ErrHandler
MyMessage = "This Manual does not exist. Create it?"
myButtons = vbYesNo + vbDefaultButton1 + vbQuestion + vbApplicationModal
myTitle = "Add Manual?"
MyChoice = MsgBox(MyMessage, myButtons, myTitle)
If MyChoice = 6 Then
If Not DBAuthority = "Admin" And Not DBAuthority = "Data Entry" Then
Response = acDataErrContinue
MsgBox "Sorry, authorized access only", _
vbOKOnly, "Important Information"
Exit Sub
Else
Response = acDataErrAdded
CallerField = "Manual"
CallerForm = "NewDocument"
NewData = Replace(NewData, Chr(47), Chr(45))
NewData = Replace(NewData, Chr(92), Chr(45))
DoCmd.OpenForm "AddManual", windowmode:=acDialog, OpenArgs:=NewData
Me.cboManual.RowSource = Me.cboManual.RowSource
Me.cboManual.value = strAddManual
strManual = Me.cboManual.value
strAddManual = vbNullString
Me.cboSection.value = strAddSection
strSection = Me.cboSection.value
strAddSection = vbNullString
Me.cboEngine.value = strAddEngine
strEngine = Me.cboEngine.value
strAddEngine = vbNullString
End If
ElseIf MyChoice = 7 Then
Response = acDataErrContinue
MsgBox "Select Manual from list.", vbOKOnly, "Select Manual"
Me.cboManual.Undo
Me.cboManual.SetFocus
Exit Sub
End If
Exit Sub
ErrHandler:
If Err = 20 Then
Response = acDataErrContinue
ElseIf Err = 94 Then
Response = acDataErrContinue
Resume Next
ElseIf Err = 2237 Then
Response = acDataErrContinue
Resume Next
ElseIf Err = 0 Then
Response = acDataErrContinue
Else
MsgBox "cboManual.NotInList Err = " & Err.Number & " :" & Err.Description
Exit Sub
End If
Exit Sub
End Sub
Option one
Replace while typing
Select Case KeyCode
Case vbKeyDown
Me![cboNewPart].Dropdown
Case 220, 191 ' / and \
KeyCode = 189 ' with -
Case Else
End Select
Option two
after adding the new value to the table. do
me.combo.undo, me.combo.requery. me.combo.value = newValue
followed by acDataErrContinue
this way you won't get error message but the list will flicker a and it's purely a hack.
Try using a different variable name (other than NewData) to store the modified version of the value passed to the NewData argument, i.e.:
Dim NewString as String
NewString = NewData
NewString = Replace(NewString, Chr(47), Chr(45))
NewString = Replace(NewString, Chr(92), Chr(45))
DoCmd.OpenForm "AddManual", windowmode:=acDialog, OpenArgs:=NewString
Since VBA arguments are passed ByRef unless otherwise stated, any modification to the argument value will be modifying the original value passed to your cboManual_NotInList event handler.
Given the above, you could alternatively try changing the NewData argument to be passed by value (ByVal):
Private Sub cboManual_NotInList(ByVal NewData As String, Response As Integer)

Create table in Word Document From Access using VBA

I am trying to create tables in a Word document template from my Access database.
This bit of code runs fine from Word itself and creates tables as required. I was wondering if its possible to run this code from Access and point to a specific word document in which to create the tables.
Dim numberOfTables As Integer
Dim iCount As Integer
numberOfTables = InputBox("How many tables to make?", "Tables")
For iCount = 0 To numberOfTables - 1
ActiveDocument.Tables.Add Range:=Selection.Range, NumRows:=2, NumColumns:= _
3, DefaultTableBehavior:=wdWord9TableBehavior, AutoFitBehavior:= _
wdAutoFitFixed
With Selection.Tables(1)
If .Style <> "Table Grid" Then
.Style = "Table Grid"
End If
.ApplyStyleHeadingRows = True
.ApplyStyleLastRow = False
.ApplyStyleFirstColumn = True
.ApplyStyleLastColumn = False
'.ApplyStyleRowBands = True 'Office 2010
'.ApplyStyleColumnBands = False 'Office 2007
End With
Selection.EndKey Unit:=wdStory
Selection.TypeParagraph
Next iCount
What you need to do is to first open a new instance of Word from Access. This is done by the following command:
Set wrdApp = CreateObject("Word.Application")
Then to make it visible and to add a document, you use this object from that point on:
wrdApp.Visible = True
Set myDoc = wrdApp.Documents.Add 'Here you should also keep the new document as an object so you can directly refer to it
Or if you use a template you need to open it instead:
wrdApp.Visible = True
Set myDoc = wrdApp.Documents.Open ("C:\database\template.docx")
And then comes your code that you need to modify accordingly to the above:
For iCount = 0 To numberOfTables - 1
myDoc.Tables.Add Range:=Selection.Range, NumRows:=2, NumColumns:= _
3, DefaultTableBehavior:=wdWord9TableBehavior, AutoFitBehavior:= _
wdAutoFitFixed
With myDoc.ActiveWindow.Selection.Tables(1)
'Note here that for the Selection object you need to refer to the active window
If .Style <> "Table Grid" Then
.Style = "Table Grid"
End If
.ApplyStyleHeadingRows = True
.ApplyStyleLastRow = False
.ApplyStyleFirstColumn = True
.ApplyStyleLastColumn = False
'.ApplyStyleRowBands = True 'Office 2010
'.ApplyStyleColumnBands = False 'Office 2007
End With
myDoc.ActiveWindow.Selection.EndKey Unit:=wdStory
myDoc.ActiveWindow.Selection.TypeParagraph
Next iCount
This should get you started.

Visual Basic - How to use a variable from one function in another

I have checked Google, and the suggested answers here, but have had no luck unfortunately.
The last thing I need to do is have an email read the rateNbr variable into the email body, but it just comes up empty.
I tried to make Public Function FuncRateCheckFile read as Public Function FuncRateCheckFile(ByVal rateNbr As String), to try and enable it to be called outside the function, but this then breaks the function when it is called elsewhere. :(
Here is the code, with comments as to where I am referring:
Public Function FuncRateCheckFile()
Dim blnContinue As Boolean
Dim strLine As String
Dim strSearchFor, strSearchWrd, LineCount, objFSO, objTextFile, arrLines
Dim dteNow As Date
Dim newDate As String
'//==============================================================================================
'// DECLARED
Dim rateNbr As String
'//==============================================================================================
FuncRateCheckFile = False
blnContinue = True
If blnContinue Then
Const ForReading = 1
'Get todays date and reformat it
dteNow = DateValue(Now)
newDate = Format(dteNow, "dd/MM/yy")
strSearchWrd = newDate
'Read the whole file
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile(m_RateCheckFile, ForReading)
LineCount = 0
Do Until objTextFile.AtEndOfStream
strLine = objTextFile.ReadLine()
If InStr(strLine, strSearchWrd) <> 0 Then
arrLines = Split(strLine, vbCrLf)
LineCount = LineCount + 1
End If
Loop
'Log a message to state how many lines have todays day, and if there are none, log an error
If LineCount <> 0 Then
'//==============================================================================================
'// "rateNbr" IS WHAT I AM TRYING TO GET TO PUT IN THE EMAIL
LogMessage "Rate file date is correct"
rateNbr = "Number of rates for " & newDate & " in the file recieved on " & newDate & " is " & LineCount
LogMessage rateNbr
EmailAdvice2
objTextFile.Close
'//==============================================================================================
Else
blnContinue = False
LogError "Failed to retrieve Current Rate date, please check rate file.."
EmailAdvice
objTextFile.Close
End If
End If
FuncRateCheckFile = blnContinue
LogMessage "Completed Check Rate file"
End Function
Private Function EmailAdvice2()
Dim strSMTPFrom As String
Dim strSMTPTo As String
Dim strSMTPRelay As String
Dim strTextBody As String
Dim strSubject As String
Dim oMessage As Object
'//==============================================================================================
'// DECLARED AGAIN
Dim rateNbr As String
'//==============================================================================================
Set oMessage = CreateObject("CDO.Message")
strSMTPFrom = "no-reply#work.com.au"
strSMTPTo = "me#work.com.au"
strSMTPRelay = "smtp.relay.com"
'//==============================================================================================
'// THIS MAKES THE TEXT BODY BLANK, BUT THE EMAIL STILL SENDS
strTextBody = rateNbr
'//==============================================================================================
strSubject = "Todays rates"
'strAttachment = "full UNC path of file"
oMessage.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
oMessage.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = strSMTPRelay
oMessage.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
oMessage.Configuration.Fields.Update
oMessage.Subject = strSubject
oMessage.From = strSMTPFrom
oMessage.To = strSMTPTo
oMessage.textbody = strTextBody
'oMessage.AddAttachment strAttachment
oMessage.Send
End Function
I am positive that it is blank because I have declared rateNbr under EmailAdvice2() and then not given it anything to fill the variable with. But I don't know how to make it call the variable under FuncRateCheckFile().
Thanks to all for any assistance.
As Plutonix stated, this is a scope issue.
Move the declaration of your 'rateNbr' variable out to class level, and remove the local declarations inside your functions:
Dim rateNbr As String ' <-- out at class level it will be accessible from both functions
Public Function FuncRateCheckFile()
...
' REMOVE both the decalarations of "rateNbr" that are INSIDE your functions
...
End Function
Private Function EmailAdvice2()
...
' REMOVE both the decalarations of "rateNbr" that are INSIDE your functions
...
End Function

Can not update database through DataGridView - no errors

One button and datagridview. If button text1 ("Edit database") datagridview reads into database, if button text2 ("ACCEPT CHANGES") datagridview writes into database, but the latter can not happen, no matter what I do. No errors just doesn't make changes to database file.
Dim ConnString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=w:\PD_Z.mdb"
Dim SQLString As String = "SELECT * FROM ZARADE"
Dim OleDBConn1 As System.Data.OleDb.OleDbConnection = New System.Data.OleDb.OleDbConnection(ConnString)
Dim DataSet1 As New DataSet()
Dim OleDbDataAdapter1 As System.Data.OleDb.OleDbDataAdapter = New System.Data.OleDb.OleDbDataAdapter(SQLString, OleDBConn1)
OleDBConn1.Open()
OleDbDataAdapter1.Fill(DataSet1, "ZARADE")
DataGridView1.DataSource = DataSet1.Tables("ZARADE")
DataGridView1.Columns.Remove(DataGridView1.Columns(0).Name)
If Button2.Text = "Edit database" Then
DataGridView1.ReadOnly = False
Button2.Text = "ACCEPT CHANGES"
Button2.ForeColor = Color.DarkRed
Button1.Enabled = False
ComboBox1.Enabled = False
Else
Button2.Text = "Edit database"
DataGridView1.ReadOnly = True
Button2.ForeColor = Color.Black
Button1.Enabled = True
ComboBox1.Enabled = True
'Dim cb As New OleDbCommandBuilder(OleDbDataAdapter1) ' THIS ONE DOESN'T WORK
' cb.QuotePrefix = "["
' cb.QuoteSuffix = "]"
' OleDbDataAdapter1.Update(DataSet1.Tables("ZARADE"))
Using con = New OleDbConnection(ConnString) ' THIS ONE DOESN'T WORK TOO
Me.Validate()
OleDbDataAdapter1.Update(DataSet1.Tables("ZARADE"))
DataSet1.AcceptChanges()
End Using
DataSet1.AcceptChanges()
OleDBConn1.Close()
This code is in Button_click event.
after you executed
OleDbDataAdapter1.Fill(DataSet1, "ZARADE")
all rows in your dataset have RowWtate = Unchanged ... so when you call Update(DataSet1....) there is nothing to update ... check the return value ... I guess it will be 0 because no rows have been affected ...

Sending messages with HTML contents using the MAPI control in VB6

How can I send a mail using MAPI with an HTML body? I need to create table in a message body.
I'm using vb6 and the MAPI control. Any ideas?
Function MailSend(sSendTo As String, sSubject As String, sText As String) As Boolean
On Error GoTo ErrHandler
With MAPISession1
If .SessionID = 0 Then
.DownLoadMail = False
.LogonUI = True
.SignOn
.NewSession = True
MAPIMessages1.SessionID = .SessionID
End If
End With
With MAPIMessages1
.Compose
.RecipAddress = sSendTo
.AddressResolveUI = True
.ResolveName
.MsgSubject = sSubject
.MsgNoteText = sText
.Send False
End With
MailSend = True
Exit Function
ErrHandler:
'MsgBox Err.Description
MailSend = False
End Function
MAPI control uses Simple MAPI, which does not handle HTML. There is a trick when using Simple MAPI directly (MAPISendMail) - set the body to NULL and attach and HTML file: it will be used as the message body. I don't know if that trick will work with the MAPI control.
Why not switch to using the Outlook Object Model? It is perfectly capable of handling HTML:
set App = CreateObject("Outlook.Application")
set NS = App.GetNmaespace("MAPI")
NS.Logon
set Msg = App.CreateItem(0)
Msg.To = sSendTo
Msg.Subject = sSubject
Msg.HTMLBody = sYourHTMLBody
Msg.Send 'or Msg.Display
keep
.MsgNoteText ="";
.AttachmentPathName = result
ie.
With MAPIMessages1
.Compose
.RecipAddress = sSendTo
.AddressResolveUI = True
.ResolveName
.MsgSubject = sSubject
.MsgNoteText =""
.AttachmentPathName = "c:\yourHtml.html"
.Send False
End With