Find out if excel is in edit mode from word-vba - vba

I am trying to find out from word if excel is in edit mode, I looked at this thread and tried to modify it, but it does not work if you have excel in edit mode, then run it, then exit edit mode rerun it still says it is edit mode:
'*********************************************************
'********* define if we need to close excel after sub is done
'***********************************************************
Public Function setExcelObject(ByRef oXLApp As Object) As Boolean
On Error Resume Next
Set oXLApp = GetObject(, "Excel.Application")
If oXLApp Is Nothing Then
Set oXLApp = CreateObject("Excel.Application")
End If
setExcelObject = IsInEditMode(oXLApp)
End Function
Public Function IsInEditMode(ByRef exapp As Object) As Boolean
If exapp.Interactive = False Then
IsInEditMode = False
Else
On Error GoTo terminate
exapp.Interactive = False
exapp.Interactive = True
IsInEditMode = False
End If
Exit Function
terminate:
IsInEditMode = True
Exit Function
End Function
Note: It also takes awful long(15s) to figure out that it is in edit mode...

Here is a working code:
'**********************************************************************
'********* See if we can open excel, true is Yes we can work with excel
'**********************************************************************
Public Function setExcelObject(ByRef oXLApp As Object) As Boolean
On Error Resume Next
Set oXLApp = GetObject(, "Excel.Application")
If oXLApp Is Nothing Then
Set oXLApp = CreateObject("Excel.Application")
End If
setExcelObject = Not IsInEditMode(oXLApp)
If setExcelObject = False Then Set oXLApp = Nothing
End Function
' *****************************************************************
' **************** Check if excel is in edit mode ****************
'*****************************************************************
Public Function IsInEditMode(ByRef exapp As Object) As Boolean
On Error GoTo terminate
exapp.Interactive = False
exapp.Interactive = True
IsInEditMode = False
Exit Function
terminate:
IsInEditMode = True
Exit Function
End Function
' *************************************************************
' *************** Check if excel is open, true, means we should not close excel after we are done.....
'*****************************************************************
Function ExcelOpen() As Boolean
ExcelOpen = FindWindow("XLMAIN", vbNullString)
End Function
The above code I then call from several procedure like this:
' Get excel object
If Not FileHandling.setExcelObject(oXLApp) Then
failMessage = "You are editing a cell in excel, stop doing that!"
GoTo terminate
End If
' check if we need to close after
closeExcelMy = FileHandling.ExcelOpen
'See if we can open workbook
If Not FileHandling.GetWorkbook(wbName, oXLApp, xlApp) Then
failMessage = "Failed to open workbook"
GoTo terminate
End If
oXLApp.Visible = True

Related

Automation Error - Unspecified Error (Runtime Error -2147467259)

I need some help. I am new to Excel VBA. I am trying to create a userform for stock inventory records and I been geting the automation error -2147467259. My problem is that the code works but after a few mouse clicks (10 or more) or after long usage, I keep getting this error. My code:
Private Sub cbPickID_Change()
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim tbl_issuance As ListObject
Set tbl_issuance = shIssuance.ListObjects("tblIssuance")
If Not tbl_issuance.DataBodyRange Is Nothing Then
tbl_issuance.DataBodyRange.Delete
End If
Dim tbl_pick As ListObject
Set tbl_pick = shPickList.ListObjects("tblPickList")
On Error GoTo ErrDetect
With tbl_pick.DataBodyRange
.AutoFilter field:=1, Criteria1:=Me.cbPickID.Value
End With
Dim pick_row As Long
pick_row = shPickList.Range("A" & Application.Rows.Count).End(xlUp).Row
shPickList.Range("A3:L" & pick_row).SpecialCells(xlCellTypeVisible).Copy
shIssuance.Range("A3").PasteSpecial (xlPasteValuesAndNumberFormats)
tbl_pick.AutoFilter.ShowAllData
Application.CutCopyMode = False
Dim issued_row As Long
issued_row = shIssuance.Range("A" & Application.Rows.Count).End(xlUp).Row
With Me.lbPickList
.ColumnHeads = True
.ColumnCount = 12
.ColumnWidths = ("40,40,40,110,0,45,40,60,90,0,0,0")
.RowSource = shIssuance.Range("A3:L" & issued_row).Address
End With
ErrDetect:
If Err.Number = 1004 Then
MsgBox "No records found!"
Exit Sub
End If
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
When I click debug, the error point at this
tbl_issuance.DataBodyRange.Delete
all my reference are in the same file. if I want to use the Excel VBA again, I need to close all Excel file and re-open them again.
any advice is highly appreciated.

Error 4605 on opening Word document when another document is already open

So I have this problem on the error handler when I want to open a specific word document.
What the program does so far when I start it is: First time start is fine. Then when I run again the program keeps loading until I manually close Word. And after that Word gives me and option to access the file in read-only mode.
I've searched on forums and MSDN for a few hours now and can't find a solution.
Also it keeps giving me
error code 4605
when I run the code a second time.
Code:
Sub OpenWord()
Dim WordApp As Word.Application
Set WordApp = CreateObject("Word.Application")
WordApp.DisplayAlerts = wdAlertsNone
On Error GoTo ErrorHandler:
WordApp.Documents.Open ("C:\Users\mvandalen\Desktop\Test.docx")
WordApp.Visible = True
Exit Sub
''just for testing
VariableCheese = 5 + 5
ErrorHandler:
WordApp.Documents.Close <<< Here it gives error 4605
WordApp.Quit
Resume Next
End Sub
final edit:
Thanks to #Brett I've found a solution. I copied his code and removed the following lines (tagged with >>>):
Sub final()
Set TestDoc = GetObject("C:\Users\mvandalen\Desktop\Test.docx")
>>>>If TestDoc Is Nothing Then
Set Wd = GetObject(, "Word.Application")
If Wd Is Nothing Then
Set Wd = CreateObject("Word.Application")
If Wd Is Nothing Then
MsgBox "Failed to start Word!", vbCritical
Exit Sub
End If
>>>>f = True
**Else** Added line
**MsgBox "Failed to start Word!", vbCritical** Added line
End If
>>>Set TestDoc = Wd.Documents.Open("C:\Users\mvandalen\Desktop\Test.docx")
>>>If TestDoc Is Nothing Then
>>>MsgBox "Failed to open help document!", vbCritical
>>>If f Then
>>>Wd.Quit
>>>End If
>>>Exit Sub
End If
Wd.Visible = True
>>>Else
>>>With WordDoc.Parent
>>>.Visible = True
>>>.Activate
>>>End With
>>>End If
End sub
This code opens the file once and then not again until you close it.
But for some reason this line is required Set TestDoc = GetObject("C:\Users\mvandalen\Desktop\Test.docx"). If not the Word document will become read-only.
I would start by going to File > Options > General and see if there is a check mark in the box: Open e-mail attachments and other uneditable files in reading view. If there is, remove it.
Source: https://answers.microsoft.com/en-us/msoffice/forum/msoffice_word-mso_windows8-mso_2013_release/run-time-error-4605-in-word-2013-no-information/1ca02c04-5cea-484e-bd23-f4d18183c1b2
That said, My feel is that you are trying to close a document that has already been closed (or not active) or that there is no error.
To remedy this check there is an an error:
If Err <> 0 Then
''Insert your error handling code here
Err.Clear
Resume Next
See: https://support.microsoft.com/en-au/help/813983/you-receive-run-time-error-4248-4605-or-5941-when-you-try-to-change-pr
Alternatively, the problem is that you are not checking to see if the document is already opened. This likely results in a continuous loop. I suggest using code similar to the example below to detect if the document is already opened.
Set TestDoc = GetObject("C:\Users\mvandalen\Desktop\Test.docx")
If TestDoc Is Nothing Then
Set Wd = GetObject(, "Word.Application")
If Wd Is Nothing Then
Set Wd = CreateObject("Word.Application")
If Wd Is Nothing Then
MsgBox "Failed to start Word!", vbCritical
Exit Sub
End If
f = True
End If
Set TestDoc = Wd.Documents.Open("C:\Users\mvandalen\Desktop\Test.docx")
If TestDoc Is Nothing Then
MsgBox "Failed to open help document!", vbCritical
If f Then
Wd.Quit
End If
Exit Sub
End If
Wd.Visible = True
Else
With WordDoc.Parent
.Visible = True
.Activate
End With
End If
This code will activate the document if it is already opened.
Source: https://social.msdn.microsoft.com/Forums/en-US/29265e5f-8df9-4cab-8984-1afb9b110d2f/in-excel-use-vba-to-check-if-a-word-document-is-open?forum=isvvba
Based on your new information another possible cause is that Visual Basic has established a reference to Word because of a line of code that calls a Word object, method, or property without qualifying the element with a Word object variable. Visual Basic does not release this reference until you end the program. This errant reference interferes with automation code when the code is run more than one time. To fix this, change the code so each call to a Word object, method, or property is qualified with the appropriate object variable.
The nearest to explain this is an Excel article: https://support.microsoft.com/en-hk/help/178510/excel-automation-fails-second-time-code-runs
To help you more I would need to know:
What version of Word you are using.
Are you using MacOS or Windows.
What are your macro security settings?
If you kill all Word process does the error still show?
Is the document is ready only or otherwise protected?
If you open the document and it's in the active window when you go to the Developer tab and run your macro does the error still occur?
Given we know the document keeps getting protected try removing protection by going into the trust center and ensuring Word 2003/7 Binary Documents and Templates is not ticked.
On looking at your code more closely, I think the problem is that you don't release the Word objects. Since this code is running from within Excel, those objects are being held in memory, not being released when the macro ends. And Word notoriously has problems with trying to open a document that is still open - because you have an object to it in memory holding it open.
See my changes to your code, below - the Set [variable] = Nothing lines.
(Please note that you mix the variable names "TestDoc" and "WordDoc" in your code sample - I just copied it - so the code, as it stands, cannot run correctly.)
Set TestDoc = GetObject("C:\Users\mvandalen\Desktop\Test.docx")
If TestDoc Is Nothing Then
Set Wd = GetObject(, "Word.Application")
If Wd Is Nothing Then
Set Wd = CreateObject("Word.Application")
If Wd Is Nothing Then
MsgBox "Failed to start Word!", vbCritical
Exit Sub
End If
f = True
End If
Set TestDoc = Wd.Documents.Open("C:\Users\mvandalen\Desktop\Test.docx")
If WordDoc Is Nothing Then
MsgBox "Failed to open help document!", vbCritical
If f Then
Wd.Quit
Set Wd = Nothing
End If
Exit Sub
End If
Wd.Visible = True
Else
With WordDoc.Parent
.Visible = True
.Activate
End With
End If
Set WordDoc = Nothing
Set Wd = Nothing
Try the following code. It:
• starts Word if it's not already running.
• opens the document if it's not already open.
• saves & closes the document after editing if it opened it.
• quits Word if it started it.
You can, of course, omit the document close and app quit code if you want to keep the document open. Depending on whether you want to prevent edits to the file being saved, you may want to set ReadOnly:=True, also.
Sub OpenWord()
Dim WdApp As Word.Application, WdDoc As Word.Document
Dim bQuit As Boolean, bClose As Boolean
Const StrFlNm As String = "C:\Users\mvandalen\Desktop\Test.docx"
If Dir(StrFlNm) = "" Then
MsgBox "Cannot find the file:" & vbCr & StrFlNm, vbCritical
Exit Sub
End If
bQuit = False: bClose = True
On Error Resume Next
Set WdApp = GetObject(, "Word.Application")
If WdApp Is Nothing Then
Set WdApp = CreateObject("Word.Application")
On Error GoTo 0
If WdApp Is Nothing Then
MsgBox "Can't start Word.", vbExclamation
Exit Sub
End If
bQuit = True
End If
On Error GoTo 0
With WdApp
.Visible = True
For Each WdDoc In .Documents
If WdDoc.FullName = StrFlNm Then
bClose = False: Exit For
End If
Next
If WdDoc Is Nothing Then
Set WdDoc = .Documents.Open(Filename:=StrFlNm, ReadOnly:=False, AddToRecentFiles:=False, Visible:=True)
End If
With WdDoc
'Do your document edits here
If bClose = True Then .Close SaveChanges:=True
End With
If bQuit = True Then .Quit
End With
End Sub
you have to carefully handling the possibility of having already running Word session as well as not being able to get a Word session
so you may use a helper function:
Function GetWord(WordApp As Word.Application) As Boolean
On Error Resume Next
Set WordApp = GetObject(, "Word.Application") 'try getting an already running Word instance
If WordApp Is Nothing Then Set WordApp = CreateObject("Word.Application") ' if unsuccesful then try creating a new Word instance
GetWord = Not WordApp Is Nothing ' notify the result
End Function
and therefore your main code would be refactored as follows
Option Explicit
Sub OpenWord()
Dim WordApp As Word.Application
If Not GetWord(WordApp) Then 'if unsuccesful in getting/creating a Word session then exit sub
MsgBox "Couldn't get an existing instance or create a new instance of Word", vbCritical
Exit Sub
End If
With WordApp 'reference the Word session you just got/created
.DisplayAlerts = wdAlertsNone
.Visible = True
On Error GoTo WordErrorHandler:
.Documents.Open ("C:\Users\mvandalen\Desktop\Test.docx")
' rest of your code exploiting the opened document
End With
On Error GoTo 0 'disable Word Error processing
' here goes the rest of your code to work without Word object/data
Exit Sub ' exit not to process statements following 'WordErrorHandler'
WordErrorHandler:
With WordApp
If .Documents.Count > 0 Then .Documents.Close '<<< Here it gives error 4605
.Quit
End With
Set WordApp = Nothing
Resume Next
End Sub
Save the document as a Template (.dotx) and change .Open() to .Add().
Dim WordApp As Word.Application
Dim WordDoc As Word.Document
Set WordApp = New Word.Application
Set WordDoc = WordApp.Documents.Add "C:\Users\mvandalen\Desktop\Test.dotx"
WordApp.Visible = True
'...
WordDoc.Close wdDoNotSaveChanges
Since you have a reference to Word, no need to call CreateObject("Word.Application").
Either remove the reference to Word Library and declare WordApp and WordDoc as Object, or use the New keyword.
This way you can open as many instances you want simultaneously.

VBA: test if workbook is nothing

Edit: My real question is how to test if object was set that was instantiated. I am not really looking to "correct" my code. Its just an example.
I have a function that returns a workbook:
Edit: Added code
Sub GetWb() as Workbook
Application.DisplayAlerts = False
Application.EnableEvents = False
On Error Resume Next
Set wM = Application.Workbooks.Open("Z:\somepath.xlsm", ReadOnly:=True)
Application.EnableEvents = True
Application.DisplayAlerts = True
On Error GoTo 0
end sub
In another sub I want to check if that object was set properly by the function. I usually do something like this with objects generally:
dim w as Workbook
set w = GetWb
if w is nothing then
debug.print "no workbook"
else
debug.print "workbook"
end if
However, the is nothing test does not work because the object is instantiated, but was not set so it is something, not nothing.
I have resorted to this ugly solution, which works fine:
dim w as Workbook
set w = GetWb
on error goto someerrorhandling
if w.name = "" then
end if
on error goto 0
'other code here
someerrorhandling:
msgbox "no workbook"
In other words, I check a property of the object to force an error, or not. There must be a better/cleaner way.
I checked and this link states that the way I am doing it is the best way:
VBA: Conditional - Is Nothing
change your error handling for GetWB so it returns nothing incase of error, also use Function instead of sub.
Function GetWb() As Workbook
Application.DisplayAlerts = False
Application.EnableEvents = False
On Error GoTo errHandler:
Set GetWb = Application.Workbooks.Open("Z:\somepath.xlsm", ReadOnly:=True)
Application.EnableEvents = True
Application.DisplayAlerts = True
errHandler:
If Err.Number <> 0 Then
Set GetWb = Nothing
Application.EnableEvents = True
Application.DisplayAlerts = True
End If
End Function

How to bypass "Macros have been disabled" message and have macros run Workbook_Activate?

I have some VBA code that formats/resizes the screen when the workbook/worksheet is activated.
The code is as follows:
Private Sub Workbook_Activate()
Dim SaveSelection As Object
Set SaveSelection = Selection
Application.ScreenUpdating = False
Range("A1:T50").Select
ActiveWindow.Zoom = True
Application.DisplayFullScreen = False
Application.DisplayFormulaBar = False
ActiveWindow.DisplayWorkbookTabs = True
ActiveWindow.DisplayHeadings = False
ActiveWindow.DisplayGridlines = False
Range("A1:T50").Select
ActiveWindow.Zoom = True
On Error GoTo ExitPoint
SaveSelection.Select
Application.ScreenUpdating = True
ExitPoint:
End Sub
The problem here is that when the user first opens the workbook, they get this Security Warning message "Macros have been disabled", so the macro does not run when the user first opens the workbook because the message appears.
Does anyone know of a workaround to this?
This can often be resolved by including the workbook's folder path in their Trusted Locations.
As sigil pointed out adding the file's folder location to the Trusted Locations will prevent the Enable Content and Enable Macros dialog boxes from appearing.
Alternately, you could create a VBScript file to open the workbook.
Paste this could into NotePad
Adjust the FILE_NAME constant
Hold down Ctrl+S
Click [Save as type]
Select All Files (.)
Save the file with .vbs as it's extension
Const FILE_NAME = "C:\Excel FIles\Hello World.xlsm"
Dim oExcel
On Error Resume Next
Set oExcel = GetObject(, "Excel.Application")
On Error Goto 0
If TypeName(oExcel) = "Empty" Then Set oExcel = WScript.CreateObject("Excel.Application")
oExcel.Visible = True
oExcel.Workbooks.Open FILE_NAME

Why is this "Delete Method of Range class failed" error popping up?

I am trying to figure out why this "Delete Method of Range Class" error is popping up. It does not always occur when this macro runs, which makes it all the more perplexing.
Can anybody explain this?
Sub ResetSheet()
If WindowsOS Then
'*******************************************************************************************************'
'Resets the Data sheet. Called by the resetSheetButton procedure (located in module: m7_Macros1_5). '
'Also called by the OkCommandButton_Click procedure in the OnOpenUserForm form. '
'*******************************************************************************************************'
Application.EnableEvents = False
Sheet4.Visible = True
Sheet4.Activate
Sheet4.Select
Sheet4.Rows("2:101").Select
Selection.Copy
'TC Edit
Sheet1.Activate
Sheet1.Range("A2").PasteSpecial (xlPasteAll)
'Sheet1.Paste
Sheets("Data").Select
Sheet1.Rows("102:10000").EntireRow.Delete
Sheet4.Visible = False
'TC Edit 2.0 - Adding code to reset the exception checkboxes
If WindowsOS Then
Call resetCheckBoxes
End If
Application.EnableEvents = True
This is the macro code that causes the error (sometimes)
This is the error pop-up
try with below simplified code
Sub ResetSheet()
'If WindowsOS Then
Application.EnableEvents = False
With Worksheets("Sheet4")
.Visible = True
.Rows("2:101").Copy Worksheets("Sheet1").Range("A2")
End With
With Worksheets("Sheet1")
.Rows("102:101").EntireRow.Delete
End With
Worksheets("Sheet4").Visible = False
If windowsOS Then
Call resetCheckBoxes
End If
Application.EnableEvents = True
End Sub