Code Interruption Converting Macros to VBA - ms-access

I am trying to figure out how to get VBA code to continue after being interrupted by a popup inquiring if I want to convert. I think I can figure out how to handle the first and subsequent popups that appear via the Windows API. However, I can't figure out how to put focus on my code when the popup appears so I can't run the line "MsgBox FindWindow(vbNullString, "Convert macro: " & m.Name)." Is there away for the code to continue running? I know that I will have to add a loop to check for the popup with the title "Convert macro: " & m.Name. Below is the code I have so far.
Sub ConvertMacrosToVBA()
Dim strDB As String
Dim appAccess As Access.Application
Dim m As Object
strDB = "C:\Users\Me\Desktop\testme.accdb"
Set appAccess = New Access.Application
appAccess.OpenCurrentDatabase strDB
For Each m In appAccess.CurrentProject.AllMacros
appAccess.DoCmd.SelectObject acMacro, m.Name, True
appAccess.DoCmd.RunCommand acCmdConvertMacrosToVisualBasic
MsgBox FindWindow(vbNullString, "Convert macro: " & m.Name)
Next
Set appAccess = Nothing
End Sub

Related

Search through VBA code files in other Access Databases

I read through a pretty thorough response in the link How to search through VBA code files and it works just fine for the current project. However, I'm just feeling slow in opening up other projects and looking through their code.
The response mentioned using OpenDatabase but I'm not seeing examples about the association between the database and the Application.VBE.ActiveVBProject. I've not been lazy about this, but 4 days of searching the web has exhausted my options.
Any help would be really appreciated.
My apologies. Found other way to make this work.
Public Sub FindWordInOtherModules(ByVal pSearchWord As String, sApplicationFilePath As String)
Dim objComponent As VBComponent
' VBComponent requires reference to Microsoft Visual Basic
' for Applications Extensibility; use late binding instead:
Dim lStartLine As Long
Dim lEndLine As Long
Dim lStartColumn As Long
Dim lEndColumn As Long
Dim accApp As Access.Application
Set accApp = New Access.Application
With accApp
.Visible = True
.OpenCurrentDatabase (sApplicationFilePath)
.UserControl = True
'MsgBox .VBE.ActiveVBProject.VBComponents.Count
'MsgBox .CurrentDb.Name
For Each objComponent In .VBE.ActiveVBProject.VBComponents
If objComponent.CodeModule.Find(pSearchWord, lStartLine, lStartColumn, lEndLine, lEndColumn, _
FindWholeWord, MatchCase, PatternSearch) = True Then
MsgBox "Found text " & StringToFind & vbCrLf _
& "Start line: " & lStartLine & vbCrLf _
& "Line text: " & objComponent.CodeModule.Lines(lStartLine, lEndLine - lStartLine + 1), vbOKOnly, objComponent.CodeModule.Name
End If
Next objComponent
End With
accApp.CloseCurrentDatabase
Set accApp = Nothing
End Sub
You should probably add accApp.Quit:
accApp.CloseCurrentDatabase
accApp.Quit
Set accApp = Nothing
before Set accApp = Nothing to speed up closing the application and close it during execution of this code (Public Sub FindWordInOtherModules), on the line accApp.Quit, not later. On my computer mouse is still inactive several seconds after execution such kind of Sub if accApp.Quit is not added.
But there is no need to open another database, because the current database can be only "linked' to it by creating temporary reference:
Private Sub FindWordInOtherModules2()
Dim objComponent As VBComponent
...
...
Dim lEndColumn As Long
Dim ref As Reference
Dim RefName As String
Const FileName = "C:\Users\....mdb"
With Application 'instead of accApp
.References.AddFromFile FileName
'.References.Count because the new one is supposed be the last one (?)
RefName = .References(.References.Count).Name
Dim VBProj As VBProject
For Each VBProj In .VBE.VBProjects
If VBProj.FileName <> .CurrentDb.Name Then Exit For
Next
For Each objComponent In VBProj.VBComponents
'Debug.Print objComponent.Name
...
...
Next
Set objComponent = Nothing '?
Set VBProj = Nothing '?
Set ref = .References(RefName)
.References.Remove ref
Set ref = Nothing '??
End With
End Sub
This seems be faster then opening another database file, but VBA can't be updated.
References.Remove ref removes reference, but VBA folders are still visible in the left panel and all the code works, what is a little disturbing ...
Application.VBE.VBProjects.Remove VBProj doesn't work. It may have something to do with "Trust access to the VBA project object model" option in Trust Center - Macro Settings, which is not available in Access.
But the project is not visible after closing and opening the database.

Navigating IE object via VBA code

I have a VBA code which allows me to read/place string in HTML objects (like input boxes).
This is the example of code:
Sub ReadCheck()
Dim objlement As Object
Dim i As Integer
Dim isNothing As Boolean
'
Dim shellWins As ShellWindows
Dim ie As InternetExplorer
'Set shellWins = New ShellWindows
Set shellWins = New ShellWindows
i = shellWins.Count
'On Error Resume Next
For i = 0 To i - 1
If shellWins.Item(i).Parent = "Internet Explorer" Then
If shellWins.Item(i).Document.URL = "https://intservices.mybebpage" Then
Set ie = shellWins.Item(i)
Exit For
End If
End If
Next i
On Error GoTo 0
isNothing = ie Is Nothing
Debug.Print Format(Now, "HH:MM:SS") & " IE is nothing: " & isNothing
If isNothing Then Exit Sub
'combo box
Set objlement = ie.Document.getelementsbyname("txtboxx")
objlement (0).Value = "Some text to place"
End Sub
Due to my testing, this code works fine with 99% of cases, but sometimes it returns error 91 (Object variable or With block variable not set), in the last line.
I'm pretty sure, that I can get correct object for objelement, but it looks like there were no .Value property for it.
This is wierd, becouse I know that this code works.
In my opinion the most possible reason for this is that I should use some different properties than .Value for this.
Do you have any comments for this?

Error 1004 When using MacroOption Access 2007

I have an application in Access 2007 that is creating a workbook with N sheets i created a macro to be inserted into this workbook which works perfectly fine. But the next step is to add a Shortcut Key to the Marco so far i've seen to methods online to assist. The First attempt gives no errors but does not assign the shortcut key either
1)
Excel_App.OnKey "^{h}", "Sheet1.HideChange"
2)Excel_App.MacroOptions Macro:="Sheet1.HideChange", Description:="Hide Columns in Line Level", hasshortcutkey:=True, ShortcutKey:="h"
My variables assigned to my method
Dim Excel_App As Excel.Application
Dim wkb As Excel.Workbook
Dim wks, wks2, wks3, wks4, wks5, wks6, wks7, wks8 As Excel.Worksheet
Dim i As Integer
Dim xlmodule As Object 'VBComponent
Dim coaches As Recordset
Set Excel_App = New Excel.Application
Excel_App.Visible = False
Set wkb = Excel.Workbooks.Add
Below is where i last placed the shortcut, i've attempted to move the line of code before and after saving however i still get 1004 err.
With wkb
ActiveSheet.Move Before:=Worksheets(1)
.Title = "CHANGE REQUEST"
.Subject = "CHANGE REQUEST"
' Add a macro to the module...
Dim strCode As String
strCode = _
"Sub HideChange()" & vbCr & _
" Columns(""A:A"").Select Selection.EntireColumn.Hidden = True " & vbCr & _
"end sub"
Dim module As VBComponent
Set module = wkb.VBProject.VBComponents(2)
module.CodeModule.AddFromString strCode
Excel_App.MacroOptions Macro:="Sheet1.HideChange", Description:="Hide Columns in Line Level", hasshortcutkey:=True, ShortcutKey:="h"
.SaveAs FileName:=strDir & "\CHANGE REQUEST FORM.xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled
.Close
End With
Excel_App.Quit
Can anyone help me figure out how this works ?
if you need more details to my question please ask, Thank you for your time!
Try removing "Sheet1" from "Sheet1.HideChanges", it is not required (or correct).
MacroOptions :MSDN
OnKey :MSDN

Mail merge started by VBA in Access let Word open Database again

I'm working on a Access database which generates some mails with mail merge called from VBA code in the Access database. The problem is that if I open a new Word document and start the mail merge (VBA), Word opens the same Access database (which is already open) to get the data. Is there any way to prevent this? So that the already opened instance of the database is used?
After some testing I get a strange behavior: If I open the Access database holding the SHIFT-Key the mail merge does not open an other Access instance of the same database. If I open the Access database without holding the key, I get the described behavior.
My mail merge VBA code:
On Error GoTo ErrorHandler
Dim word As word.Application
Dim Form As word.Document
Set word = CreateObject("Word.Application")
Set Form = word.Documents.Open("tpl.doc")
With word
word.Visible = True
With .ActiveDocument.MailMerge
.MainDocumentType = wdMailingLabels
.OpenDataSource Name:= CurrentProject.FullName, ConfirmConversions:=False, _
ReadOnly:=False, LinkToSource:=False, AddToRecentFiles:=False, _
PasswordDocument:="", PasswordTemplate:="", WritePasswordDocument:="", _
WritePasswordTemplate:="", Revert:=False, Format:=wdOpenFormatAuto, _
SQLStatement:="[MY QUERY]", _
SQLStatement1:="", _
SubType:=wdMergeSubTypeWord2000, OpenExclusive:=False
.Destination = wdSendToNewDocument
.Execute
.MainDocumentType = wdNotAMergeDocument
End With
End With
Form.Close False
Set Form = Nothing
Set word = Nothing
Exit_Error:
Exit Sub
ErrorHandler:
word.Quit (False)
Set word = Nothing
' ...
End Sub
The whole thing is done with Access / Word 2003.
Update #1
It would also help if someone could tell me what the exact difference is between opening Access with or without the SHIFT-Key. And if it is possible to write some VBA code to enable the "features" so if the database is opened without the SHIFT-Key, it at least "simulates" it.
Cheers,
Gregor
When I do mailmerges, I usually export a .txt file from Access and then set the mail merge datasource to that. That way Access is only involved in exporting the query and then telling the Word document to do the work via automation, roughly as follows:
Public Function MailMergeLetters()
Dim pathMergeTemplate As String
Dim sql As String
Dim sqlWhere As String
Dim sqlOrderBy As String
'Get the word template from the Letters folder
pathMergeTemplate = "C:\MyApp\Resources\Letters\"
'This is a sort of "base" query that holds all the mailmerge fields
'Ie, it defines what fields will be merged.
sql = "SELECT * FROM MailMergeExportQry"
With Forms("MyContactsForm")
' Filter and order the records you want
'Very much to do for you
sqlWhere = GetWhereClause()
sqlOrderBy = GetOrderByClause()
End With
' Build the sql string you will use with this mail merge
sql = sql & sqlWhere & sqlOrderBy & ";"
'Create a temporary QueryDef to hold the query
Dim qd As DAO.QueryDef
Set qd = New DAO.QueryDef
qd.sql = sql
qd.Name = "mmexport"
CurrentDb.QueryDefs.Append qd
' Export the data using TransferText
DoCmd.TransferText _
acExportDelim, , _
"mmexport", _
pathMergeTemplate & "qryMailMerge.txt", _
True
' Clear up
CurrentDb.QueryDefs.Delete "mmexport"
qd.Close
Set qd = Nothing
'------------------------------------------------------------------------------
'End Code Block:
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
'Start Code Block:
'OK. Access has built the .txt file.
'Now the Mail merge doc gets opened...
'------------------------------------------------------------------------------
Dim appWord As Object
Dim docWord As Object
Set appWord = CreateObject("Word.Application")
appWord.Application.Visible = True
' Open the template in the Resources\Letters folder:
Set docWord = appWord.Documents.Add(Template:=pathMergeTemplate & "MergeLetters.dot")
'Now I can mail merge without involving currentproject of my Access app
docWord.MailMerge.OpenDataSource Name:=pathMergeTemplate & "qryMailMerge.txt", LinkToSource:=False
Set docWord = Nothing
Set appWord = Nothing
'------------------------------------------------------------------------------
'End Code Block:
'------------------------------------------------------------------------------
Finally:
Exit Function
Hell:
MsgBox Err.Description & " " & Err.Number, vbExclamation, APPHELP
On Error Resume Next
CurrentDb.QueryDefs.Delete "mmexport"
qd.Close
Set qd = Nothing
Set docWord = Nothing
Set appWord = Nothing
Resume Finally
End Function
To use this, you need to set up your Resources\Letters subfolder and put your mailmerge template word file in there. You also need your "base" query with the field definitions in your Access App (in the example, it is called MailMergeExportQry. But you can call it anything.
You also need to figure out what filtering and sorting you will do. In the example, this is represented by
sqlWhere = GetWhereClause()
sqlOrderBy = GetOrderByClause
Once you have got your head round those things, this is highly reusable.

how do you view macro code in access?

I have a Microsoft Access database and there is a macro there. How do I view the code of the macro?
Open the Access Database, you will see Table, Query, Report, Module & Macro.
This contains the macros which can be used to invoke common MS-Access actions in a sequence.
For custom VBA macro, press ALT+F11.
You can try the following VBA code to export Macro contents directly without converting them to VBA first. Unlike Tables, Forms, Reports, and Modules, the Macros are in a container called Scripts. But they are there and can be exported and imported using SaveAsText and LoadFromText
Option Compare Database
Option Explicit
Public Sub ExportDatabaseObjects()
On Error GoTo Err_ExportDatabaseObjects
Dim db As Database
Dim d As Document
Dim c As Container
Dim sExportLocation As String
Set db = CurrentDb()
sExportLocation = "C:\SomeFolder\"
Set c = db.Containers("Scripts")
For Each d In c.Documents
Application.SaveAsText acMacro, d.Name, sExportLocation & "Macro_" & d.Name & ".txt"
Next d
An alternative object to use is as follows:
For Each obj In Access.Application.CurrentProject.AllMacros
Access.Application.SaveAsText acMacro, obj.Name, strFilePath & "\Macro_" & obj.Name & ".txt"
Next
EDIT:
Per Michael Dillon's answer, SaveAsText does save the commands in a macro without having to go through converting to VBA. I don't know what happened when I tested that, but it didn't produce useful text in the resulting file.
So, I learned something new today!
ORIGINAL POST:
To expand the question, I wondered if there was a way to retrieve the contents of a macro from code, and it doesn't appear that there is (at least not in A2003, which is what I'm running).
There are two collections through which you can access stored Macros:
CurrentDB.Containers("Scripts").Documents
CurrentProject.AllMacros
The properties that Intellisense identifies for the two collections are rather different, because the collections are of different types. The first (i.e., traditional, pre-A2000 way) is via a documents collection, and the methods/properties/members of all documents are the same, i.e., not specific to Macros.
Likewise, the All... collections of CurrentProject return collections where the individual items are of type Access Object. The result is that Intellisense gives you methods/properties/members that may not exist for the particular document/object.
So far as I can tell, there is no way to programatically retrieve the contents of a macro.
This would stand to reason, as macros aren't of much use to anyone who would have the capability of writing code to examine them programatically.
But if you just want to evaluate what the macros do, one alternative would be to convert them to VBA, which can be done programmatically thus:
Dim varItem As Variant
Dim strMacroName As String
For Each varItem In CurrentProject.AllMacros
strMacroName = varItem.Name
'Debug.Print strMacroName
DoCmd.SelectObject acMacro, strMacroName, True
DoCmd.RunCommand acCmdConvertMacrosToVisualBasic
Application.SaveAsText acModule, "Converted Macro- " & strMacroName, _
CurrentProject.Path & "\" & "Converted Macro- " & strMacroName & ".txt"
Next varItem
Then you could use the resulting text files for whatever you needed to do.
Note that this has to be run interactively in Access because it uses DoCmd.RunCommand, and you have to click OK for each macro -- tedious for databases with lots of macros, but not too onerous for a normal app, which shouldn't have more than a handful of macros.
This did the trick for me: I was able to find which macro called a particular query. Incidentally, the reason someone who does know how to code in VBA would want to write something like this is when they've inherited something macro-ish written by someone who doesn't know how to code in VBA.
Function utlFindQueryInMacro
( strMacroNameLike As String
, strQueryName As String
) As String
' (c) 2012 Doug Den Hoed
' NOTE: requires reference to Microsoft Scripting Library
Dim varItem As Variant
Dim strMacroName As String
Dim oFSO As New FileSystemObject
Dim oFS
Dim strFileContents As String
Dim strMacroNames As String
For Each varItem In CurrentProject.AllMacros
strMacroName = varItem.Name
If Len(strMacroName) = 0 _
Or InStr(strMacroName, strMacroNameLike) > 0 Then
'Debug.Print "*** MACRO *** "; strMacroName
Application.SaveAsText acMacro, strMacroName, "c:\temp.txt"
Set oFS = oFSO.OpenTextFile("c:\temp.txt")
strFileContents = ""
Do Until oFS.AtEndOfStream
strFileContents = strFileContents & oFS.ReadLine
Loop
Set oFS = Nothing
Set oFSO = Nothing
Kill "c:\temp.txt"
'Debug.Print strFileContents
If InStr(strFileContents, strQueryName) 0 Then
strMacroNames = strMacroNames & strMacroName & ", "
End If
End If
Next varItem
MsgBox strMacroNames
utlFindQueryInMacro = strMacroNames
End Function
In Access 2010, go to the Create tab on the ribbon. Click Macro. An "Action Catalog" panel should appear on the right side of the screen. Underneath, there's a section titled "In This Database." Clicking on one of the macro names should display its code.