I have two workbooks on a shared network drive:
Workbook A (Table)
Workbook B (Pivot Table -Connected to source Workbook A)
I'm trying to, when Workbook B is opened, run macro and do this:
Unprotect a certain worksheet on Workbook B
If workbook A is Open, refresh data connections on workbook B
If workbook A is closed, open workbook A and refresh data connections on workbook B, then close workbook A.
Protect a certain worksheet on Workbook B
The code below works as intended in most scenarios when testing so far, but if someone else tries to open workbook B on their computer when someone else has Workbook A opened on another computer, it opens workbook A as a read-only file and keeps it open on their computer. I need it to close on their computer, and keep the initial one open that's on the other computer.
Public Sub RefreshPvt()
ThisWorkbook.Worksheets("Sheet1").Unprotect
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim wkb As Workbook
If IsFileOpen("S:\\Testing\Job Closeout Status Test.xlsx") Then
ThisWorkbook.RefreshAll
Else
Set wkb = Workbooks.Open(filename:="S:\\Testing\Job Closeout Status Test.xlsx")
ThisWorkbook.RefreshAll
wkb.Close SaveChanges:=False
End If
ThisWorkbook.Worksheets("Sheet1").Protect DrawingObjects:=True, Contents:=True, Scenarios:=True _
, AllowFormattingCells:=True, AllowFormattingColumns:=True, _
AllowFormattingRows:=True
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Function IsFileOpen(filename As String)
Dim filenum As Integer, errnum As Integer
On Error Resume Next ' Turn error checking off.
filenum = FreeFile() ' Get a free file number.
' Attempt to open the file and lock it.
Open filename For Input Lock Read As #filenum
Close filenum ' Close the file.
errnum = Err ' Save the error number that occurred.
On Error GoTo 0 ' Turn error checking back on.
' Check to see which error occurred.
Select Case errnum
' No error occurred.
' File is NOT already open by another user.
Case 0
IsFileOpen = False
' Error number for "Permission Denied."
' File is already opened by another user.
Case 70
IsFileOpen = True
' Another error occurred.
Case Else
Error errnum
End Select
End Function
if you run ThisWorkbook.RefreshAll on workboook B in the immediate window does it work?
You could also make XLApp.Visible = true to see whether or not it's opening
I think you should be using something more like:
Dim pt As PivotTable
For Each pt In ActiveSheet.PivotTables
pt.RefreshTable
Next pt
To do the whole workbook you could use:
Sub AllWorkbookPivots()
Dim pt As PivotTable
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
For Each pt In ws.PivotTables
pt.RefreshTable
Next pt
Next ws
End Sub
Microsoft Office tracks those locks using files that are created in the same directory as the original file. The document filename.xlsx gets a temporary lock file: ~$filename.xlsx. If the document is in use, other user/macro opens the document as read-only. It's by design.
We might try to use Shared workbook feature of Excel, but there are some limitations.
For more detail information, please refer to the following link:
https://support.office.com/en-za/article/Use-a-shared-workbook-to-collaborate-79bd9dee-1aa3-49b5-bc27-a1ad28ffcbce
As mentioned here: https://social.technet.microsoft.com/Forums/ie/en-US/c1b179e1-ec4a-4ab9-abf4-21dc8b0c9326/vba-excel-to-excel-data-connection-it-opens-the-source-file-at-refresh?forum=excel
Related
I want to close the active macro workbook inside the Userform_Terminate event. The problem I am facing is that, a ghost window of excel application lingers on even after workbook has been closed.
Have tried most of the suggested ways, I could get my hands on (described in detail in the code snippet) but to no avail. If anybody can help, much grateful.
NOTE: Have released almost all excel related objects from memory by setting it to nothing.
Code :
Private Sub UserForm_Terminate()
' Application.DisplayAlerts = False ' The excel ghost window lingers on
' ThisWorkbook.Close , False
' Application.DisplayAlerts = True
'
' Application.DisplayAlerts = False ' The excel ghost window lingers on
' ThisWorkbook.Saved = True
' ThisWorkbook.Close , False
' Application.DisplayAlerts = True
' Application.DisplayAlerts = False 'The excel ghost window lingers on.
' ThisWorkbook.Close , False
' Application.Quit
' Application.DisplayAlerts = True
Application.DisplayAlerts = False 'Ghost window is closed but also kills all instances of excel currently open
Application.Quit
Application.DisplayAlerts = True
'NOTE:
'Have released all excel related objects from memory by setting it to nothing, post use.
End Sub
Snap:
Well, your "gost" problem has the next explanation:
An Excel session/instance means the same Application handler. If you open a workbook from the Excel existing interface, it is open in the same instance. Pressing Ctrl + F6 will jump to the next workbook open in the same instance...
If there are open workbooks not seen in the Ctrl + F6 sequence, this only means that they are open in a different instance.
Another instance is open, for instance :), in this way:
Din ExApp as Object
Set ExApp = CreateObject("Excel.Application")
ExApp.Workbooks.add 'without this line, the instance is quit by itself...
Set ExApp = Nothing 'this only releases the memory
You can see more open Excel instances (if they exist) looking in TaskManager and seeing more the one such application (Excel.exe)...
When you close a workbook, and this specific workbook is the single one of the instance, the application Window, what you name a "gost" remains!. If there are some other workbooks open, the so named "gost" window disappears, too.
In order to handle both situations, please try the next approach:
Private Sub UserForm_Terminate()
If Workbooks.Count > OpenWb Then
ThisWorkbook.Close , False
Else
Application.Quit
End If
End Sub
Function OpenWb() As Long
Dim count As Long, wb As Workbook, arr
For Each wb In Workbooks
arr = Split(wb.Name, ".")
If UCase(arr(UBound(arr))) = "XLSB" Then count = count + 1
Next
OpenWb = count + 1
End Function
Quitting the application is done here only because you asked for it... When you try programmatically to open and close many workbooks, it is more efficient to keep the application open. To open a new instance takes time. To open a workbook in an existing instance takes less time... But to do that, your code must find that existing instance:
Sub testExcelInstance()
Dim Ex As Object
On Error Resume Next
Set Ex = GetObject(, "Excel.Application")
If Ex Is Nothing Then
Err.Clear: On Error GoTo 0
Set Ex = CreateObject("Excel.Application")
End If
On Error GoTo 0
Ex.Workbooks.Add 'just doing something after having the Excel instance object
End Sub
Releasing the objects from the memory does not do anything, in terms of the object itself existence. If physically disappears only if you quit it.
I have a function that looks for open workbooks and pulls them into a master workbook. It works just fine when I'm importing a workbook created with a modern version of office, but it doesn't seem to detect workbooks that open in compatibility mode. Only the left 24 characters are constant for the workbook in question.
For a wide variety of reasons I've gone over in other posts downloading the workbook in question is not an option.
Here is the function.
Public Sub FindReport()
Debug.Print "Finding Report"
On Error GoTo Failed
Dim rName() As String
Dim wb As Workbook
Dim tWb As Workbook
rName(0) = "Case Detail"
rName(1) = "Disability_Claim_Status_"
'rName(2) = "placeholder"
For Each wb In Workbooks
'This line gives no output when I have the function try to find a workbook
'that has opened in compatibility mode
Debug.Print wb.Name
If Left(wb.Name, 11) = rName(0) Then
Set tWb = wb
ImportReport tWb
tWb.Close
CaseFAS
Exit For
End If
If Left(wb.Name, 24) = rName(1) Then
Set tWb = wb
ImportReport tWb
tWb.Close
'CaseFAS
Exit For
End If
'If Left(wb.Name, 11) = rName(2) Then
' Set tWb = wb
' ImportReport tWb
' tWb.Close
' 'CaseFAS
' Exit For
'End If
Next wb
Failed:
End Sub
EDIT for clarification:
I had another version of this code that pulled in a specific worksheet that opens from a website, now that I need to expand it to handle another sheet I modified the declarations accordingly, and screwed up declaring the array.
Before assuming something complicated is the problem make sure you didn't screw up something basic!
Here is the answer to my question....
Declare and Initialize String Array in VBA
I've encountered a strange thing: I've joined three workbooks: Personal Data Tracker, Global Tracker and the workbook with pivots and charts. The logic is as it follows: the user clicks on a button after the work is finished so the data is copied to the GL Tracker. Once the change event is triggered in the GL Tracker Table, the last workbook opens, the pivot is refreshed upon the open vent and the wb is closed.
Everything seems to be working fine, however when I run the macro live, at the very end I get an error message about
"Application-defined or object-defined error".
Only OK and Help button displayed, it doesn't make the VBE Open so I could debug it.
Would anyone know what it may be happening even if the whole chain works fine?
Thank you.
Code from the Personal Tracker:
Sub test()
Dim path As String
Dim wb As Workbook
path = ThisWorkbook.path & "\Dest.xlsm"
Application.ScreenUpdating = False
ThisWorkbook.Sheets("Total").Range("R1").Value = Date
Range("R1").Font.Color = VBA.ColorConstants.vbWhite
Worksheets("TOTAL").Range("B2:B13").Copy
On Error GoTo Handler
Workbooks.Open (path)
On Error GoTo 0
Set wb = Workbooks("Dest")
Worksheets("Sheet1").Range("B2").PasteSpecial Paste:=xlPasteValues
Exit Sub
Handler:
MsgBox "Someone else is saving their data at the moment." & vbNewLine & _
"Please try in a few seconds"
End Sub
Code from the GL Tracker:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim MRange As Range
Dim wbPivot As Workbook
Dim pt As PivotTable
Dim ws As Worksheet
Dim Name As String
Dim answer As VbMsgBoxResult
Set MRange = ThisWorkbook.Sheets(1).Range("Table1")
Name = Application.UserName
Application.ScreenUpdating = False
If Not Intersect(Target, MRange) Is Nothing Then
Application.EnableEvents = True
Set wbPivot = Workbooks.Open("C:\Users\jakub\Desktop\Excel - various\Pivot.xlsm")
End If
'refresh
For Each ws In wbPivot.Worksheets
For Each pt In ws.PivotTables
pt.PivotCache.Refresh
pt.Update
pt.RefreshTable
Next
Next
'saving
Application.ScreenUpdating = True
If Application.UserName <> "Jakub Tracz" Then
MsgBox "User not authorised. Workbook will be closed."
wbPivot.Close True
ThisWorkbook.Close True
Else
answer = MsgBox(Prompt:="Do you want to save and close the workbook?", _
Buttons:=vbYesNo + vbQuestion)
Select Case answer
Case vbYes
wbPivot.Close True
ThisWorkbook.Close True
Case vbNo
MsgBox "Welcome, " & Application.UserName
End Select
End If
End Sub
I'm going to give you a proof of concept code as an example for you to use. This will not exactly answer your question with code you can just copy/paste, but you will be able to use this to put it together the way you want it to work instead of me making assumptions about many things and restructuring it myself.
This simply demonstrates how to use a workbook object variable in one routine that can reference another workbook, and how to make changes to that 2nd workbook and save/close it.
Sub Tracker_Update()
Dim wbPivot as Workbook
' open the workbook
Set wbPivot = Workbooks.Open("C:\Users\jakub\Desktop\Excel - various\Test.xlsx")
' optionally make it hidden
wbPivot.Visible = False
With wbPivot
' pretend this code updates the pivot table
.Worksheets(1).Range("A1") = "hello world"
' Close and save it
.Close True
End With
' optionally clear the variable
' this is not really needed in VBA, but if you eventually
' start using VB.NET with Excel as a COM object,
' you will want to know how to do this part when you are done
Set wbPivot = Nothing
End Sub
I think you will like this approach in the end much better in the end anyway, as the code isn't scattered around so much in different places. Easier to debug later, and easier for someone else to understand what you are doing if and when you leave the company.
I have two .xlsm workbooks. Only workbook B runs a macro on the other.
Workbook A: Job Closeout Status.xlsm
Workbook B: Weekly Payment Sheet.xlsm
Workbook B has a pivot table where the data source is workbook A.
The macro on wkbk B refreshes the pivot table when opened.
I am getting an out of memory error. I have researched that I should set objects to nothing. However I can't edit the macro. Every time I try to add a line of code it gives the "out of memory" error. Can anyone help me out on how to optimize performance, and resolve this "out of memory" issue? Thanks.
I have also noticed that in Visual Basics App, when I only have wkbk B open, wkbk A appears in my project explorer and the worksheet icons are highlighted blue. Usually I only see workbooks that are open in project explorer.
Here is my code in workbook B:
In ThisWorkbook module:
Option Explicit
Private Sub Workbook_Open()
ThisWorkbook.Worksheets("RETENTION").Unprotect
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim wkb As Workbook
On Error Resume Next
If IsFileOpen("S:\ACCOUNTING\Subcontracts\Job Closeout Tracking\Job Closeout Status.xlsm") Then
GoTo Protect
Else
On Error Resume Next
Set wkb = Workbooks.Open(filename:="S:\ACCOUNTING\Subcontracts\Job Closeout Tracking\Job Closeout Status.xlsm")
ThisWorkbook.RefreshAll
wkb.Close SaveChanges:=False
End If
Protect:
ThisWorkbook.Worksheets("RETENTION").Protect DrawingObjects:=True, Contents:=True, Scenarios:=True _
, AllowFormattingCells:=True, AllowFormattingColumns:=True, _
AllowFormattingRows:=True
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
In a separate module:
Function IsFileOpen(filename As String)
Dim filenum As Integer, errnum As Integer
On Error Resume Next ' Turn error checking off.
filenum = FreeFile() ' Get a free file number.
' Attempt to open the file and lock it.
Open filename For Input Lock Read As #filenum
Close filenum ' Close the file.
errnum = Err ' Save the error number that occurred.
On Error GoTo 0 ' Turn error checking back on.
' Check to see which error occurred.
Select Case errnum
' No error occurred.
' File is NOT already open by another user.
Case 0
IsFileOpen = False
' Error number for "Permission Denied."
' File is already opened by another user.
Case 70
IsFileOpen = True
' Another error occurred.
Case Else
Error errnum
End Select
End Function
I am new to VBA. I have written a code to delete a particular sheet. After execution of that delete sheet macro, excel macro stopped execution. It didnt execute futher..
Here is my code..
Sub CopyAcross()
Dim sheetName As String
sheetName = "Master_Base"
If WorksheetExists(sheetName) Then
DeleteSheet (sheetName)
End If
MsgBox "Debug"
Workbooks("Master_Base.csv").Sheets("Master_Base").Copy Before:=Workbooks("Copy of test.xlsm").Worksheets("Sheet3")
End Sub
Sub DeleteSheet(strSheetName As String)
' deletes a sheet named strSheetName in the active workbook
Application.DisplayAlerts = False
Sheets(strSheetName).Delete
Application.DisplayAlerts = True
End Sub
Can any one help on this,
Thanks in advance.
I was experiencing the same issue, on a Windows 7 computer with Excel version 16.0.10730.20264 32-bit, the code ran fine without issue. However, on a Windows 10 computer with the same Excel install version, the macro would immediately stop execution following the Sheets.Delete line.
I found that this was only happening where I was attempting to manipulate a workbook that contained VBA code, that I had opened during the macro.
The issue is caused by the macro security settings on the computer. If you set Automation Security to Low before opening the workbook, you should no longer get the error:
Use the code:
Application.AutomationSecurity = msoAutomationSecurityLow
Since you are working with multiple workbooks, use objects. Else your code MAY work with the wrong workbook/worksheet
Try this (UNTESTED)
Sub CopyAcross()
Dim wbI As Workbook, wbO As Workbook
'~~> The workbook from where the code is running
Set wbO = ThisWorkbook
'~~> Here you open the csv
Set wbI = Workbooks.Open("E:\OPM\OPM Sheet\Master_Base.csv")
'~~> This will delete the sheet if it exists
'~~> no need to check if it exists
On Error Resume Next
Application.DisplayAlerts = False
wbO.Sheets("Master_Base").Delete
Application.DisplayAlerts = True
On Error GoTo 0
'~~> The csv will always have 1 sheet
'~~> so no need providing a name
wbI.Sheets(1).Copy Before:=wbO.Worksheets("Sheet3")
End Sub