Simple Excel Linking - vba

I have a fairly simple question that I have been unable to find an suitable answer for; I have an excel sheet with many SQL tables nested in the worksheet. I now need to add one more table, but this new table will be over 30 mb and when added to the current file, it makes the entire workbook trudge along very slowly for even simple calculations.
My question is: can I insert this table into a new excel file and then refresh it from my original file using the VBA code I already have that refreshes all my other SQL tables? If so, what would I have to add to my VBA code to refresh the new table in the new file? Let's assume the new table's name is "NewTable" and the file path would be C:\Users\davidmo\Desktop\David
Here is my current VBA Macro:
Sub Button1_Click()
ThisWorkbook.RefreshAll
DoEvents
ActiveSheet.Range("Q45") = Now
End Sub
If it helps, I am envisioning being able to open my original file, click the VBA macro button I use to refresh all my SQL tables and it would also refresh the table in the different file. Then I'd run my formulas in the original file and just reference the newly updated table from the other file.

So this will open the woorkbook and refresh the table and then close it, if the workbook is already opened it will stay open. There is no way to do it with a closed workbook, but its not visible for the user anyway.
Sub Button1_Click()
Dim wbk As Workbook
Dim FileName As String
Dim Path As String
Dim Opened As Boolean
ThisWorkbook.RefreshAll
Path = "C:\Users\User\Desktop\Files\1.xlsx" 'Edit Path
If IsWorkBookOpen(Path) = False Then
Set wbk = Workbooks.Open(Path)
Else
Path = Right(Path, Len(Path) - InStrRev(Path, "\"))
Set wbk = Workbooks(Path)
Opened = True
End If
wbk.RefreshAll
If Opened = False Then
wbk.Close (saveChanges = True)
End If
DoEvents
ActiveSheet.Range("Q45") = Now
End Sub
Function IsWorkBookOpen(FileName As String)
Dim ff As Long, ErrNo As Long
On Error Resume Next
ff = FreeFile()
Open FileName For Input Lock Read As #ff
Close ff
ErrNo = Err
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
End Function

Related

PowerPoint VBA: Calculating Active Users/ Is Presentation Open Function That Allows Multiple Users

I was wondering if someone could help me with a PowerPoint VBA issue that I have encountered. I have a system of two PowerPoint presentations that I have linked dynamically and interactively using VBA, and which open using an external VBS script in the same folder which plays the PowerPoints in presentation mode and resizes and positions them on the screen. The VBS script links to this sub which automatically runs the other linked subs:
Sub Open_Presentation_VEdit()
Dim Ret
Dim Ret2
Dim PPT1 As Object
Set PPT1 = CreateObject("PowerPoint.Application")
Dim PPT2 As Object
Set PPT2 = CreateObject("PowerPoint.Application")
Dim filePath As String
filePath = ActivePresentation.Path
Ret = IsWorkBookOpen(filePath & "\Stand Up Title Page - With Macros.pptm")
Ret2 = IsWorkBookOpen(filePath & "\Stand Up Summary and Breakdowns - With Macros.pptm")
If Ret = True And Ret2 = False Then
Set PPT1 = Presentations("Stand Up Title Page - With Macros.pptm")
Set PPT2 = Presentations.Open(filePath & "\Stand Up Summary and Breakdowns - With Macros.pptm")
Call TaskbarAutohideOn
Call Resize_Presentations
Else: MsgBox "Close all stand-up wall slides"
End If
End Sub
The problem I am having is that a function that I have, IsWorkBookOpen, is creating problems for allowing multiple users to the system:
Function IsWorkBookOpen(fileName As String)
Dim ff As Long, ErrNo As Long
On Error Resume Next
ff = FreeFile()
Open fileName For Input Lock Read As #ff
Close ff
ErrNo = Err
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
End Function
I have this function written in because I was having problems with the opening sequence if someone pressed the script multiple times, lots of versions of the two PowerPoints tried to open which caused issues with the code and errors.
However, the system needs to be opened by multiple people at once, who are accessing this over a network. Is it possible to write a function that can tell if an individual user has the two presentations open? I.e. allow only one copy of each presentation to be open at one time by an individual user, but allow multiple users.
Thanks in advance for any help!

Open workbook if not already open, if already, then get that reference

Ive a scenario to do some changes in a workbook in another workbook path. But the question is I need to check whether the workbook already open or not. If not I need to get that opened instance to a workbook variable.
Here is the code Im using for checking whether workbook open or not and then the code for opening
Function IsFileOpen(fileFullName As String)
Dim FileNumber As Integer
Dim errorNum As Integer
On Error Resume Next
FileNumber = FreeFile() ' Assign a free file number.
' Attempt to open the file and lock it.
Open fileFullName For Input Lock Read As #FileNumber
Close FileNumber ' Close the file.
errorNum = Err ' Assign the Error Number which occured
On Error GoTo 0 ' Turn error checking on.
' Now Check and see which error occurred and based
' on that you can decide whether file is already
' open
Select Case errorNum
' No error occurred so ErroNum is Zero (0)
' File is NOT already open by another user.
Case 0
IsFileOpen = False
' Error number for "Permission Denied." is 70
' File is already opened by another user.
Case 70
IsFileOpen = True
' For any other Error occurred
Case Else
Error errorNum
End Select
End Function
Public Function getConsolidatedDataFile() As Workbook
Dim p As String
p = ActiveWorkbook.Path
Dim cf As String
cf = printf("{0}\ConsolidatedData.xlsx", p)
Dim wb As Workbook
Dim fo As Boolean
fo = IsFileOpen(cf)
If fo = False Then wb = Workbooks.Open(filename:=cf)
''I need to get the code for this place of fo is true
getConsolidatedDataFile wb
End Function
So if file open I need to get that workbook in to that wb variable.
Ive got a solution
If fo = False Then
Set wb = Workbooks.Open(filename:=cf)
Else
Dim w As Workbook
For Each w In Workbooks
If w.FullName = cf Then
Set wb = w
End If
Next
End If
Here is in the loop its traversing through all workbook and if its there take that reference..
I hope this help
Dim dict As Dictionary
Function OpenFile(fileFullName As String) As Workbook
If (dict.Exists(fileFullName)) Then
OpenFile = dict.Item(fileFullName)
End If
dict.Add "fileFullName", Workbooks.Open(Filename:=fileFullName)
OpenFile = dict.Item(fileFullName)
End Function
Application.ActiveWorkbook = OpenFile(fileFullName)
To reference a workbook to the workbook collection it should be opened -
The Workbook object is a member of the Workbooks collection. The Workbooks collection contains all the Workbook objects currently open in Microsoft Excel.
MSDN Wrokbook Object
Thus, if your workbook is in the same Excel instance, then try like this:
Public Sub TestMe()
Dim wb As Workbook
Set wb = Workbooks("12.xlsx")
End Sub
If it is not in the same instance, then GetObject should work:
Public Sub TestMe()
Dim wb As Workbook
Set wb = GetObject("C:\path\12.xlsx")
Debug.Print wb.Worksheets(1).Name
End Sub
GetObject MSDN
This is how 3 workbooks in the same instance look like:
This is how 2 workbooks look like in 2 different instances:
Pros and Cons for using multiple instances (Source answers.microsoft.com):
Pros
If you have 32-bit Excel, each instance can use up to 3 GB memory. If you have a powerful computer, very heavy files, and 32-bit Excel, each instance of Excel can use 3 GB. So with e.g. 2 instances of Excel.exe, you could say that the total memory Excel could use triples. (Please note that this is not needed with 64-bit Excel as it is not limited by 3 GB memory per instance)
If you want to have a separate Undo chain, so that each Undo only undos in the currently active workbook, then separate instances will indeed achieve this.
Cons
If you want to have a common Undo chain shared by all open files, then using multiple instances will not achieve this.
If you want to be able to e.g. press Ctrl+F6 to jump between your open files quickly, then using multiple instances will not achieve this.
Paste Special will not work between instances. See this for more info.
Making workbook links between 2 files in separate running instances cannot be made by clicking, and will not update in real-time.
The code looks ok, simply use the Set keyword:
If fo = False Then set wb = Workbooks.Open(filename:=cf)
Here is a quick function that will open the workbook if it's not already open:
Function GetWorkBook(ByVal sFullName As String, Optional ReadOnly As Boolean) As Workbook
Dim sFile As String: sFile = Dir(sFullName)
On Error Resume Next
Set GetWorkBook = Workbooks(sFile)
If GetWorkBook Is Nothing Then Set GetWorkBook = Workbooks.Open(sFullName, ReadOnly:=ReadOnly)
On Error GoTo 0
End Function

How to avoid self reference with IsWorkBookOpen

I wanted to use shared excel workbooks on server which would be variously connected to each other.
I worked on it for many days to only find out it has many problems to cope with as shared workbooks do not support many features.
I wanted the macro to check on opening the file to find out whether the file is opened by someone else and if "yes", it would tell the person to come back later.
Unfortunately, I am now referencing to myself and this creates a loop.
I open the file, it checks itself it is opened already and then after the message it closes.
Could you please help me to evade the loop so it would suit the purpose?
I believe only the upper part of the code relates to my problem, so I do not post it in full:
Option Explicit
Private Sub Workbook_Open()
Dim Ret
Ret = IsWorkBookOpen(ThisWorkbook.FullName)
If Ret = True Then
MsgBox "Come back later."
ThisWorkbook.Close savechanges:=False
End If
End Sub
Function IsWorkBookOpen(FileName As String)
Dim ff As Long, ErrNo As Long
On Error Resume Next
ff = FreeFile()
Open FileName For Input Lock Read As #ff
Close ff
ErrNo = Err
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
End Function
I don't think you need to use that function for your purpose.
You can actually check the status of the file using:
ThisWorkbook.ReadOnly
which returns a boolean; true if file is readonly.
Now, before opening the file you really cannot suppress the pop up asking if you want to open it as read only or not. But you can still try putting this code which will trigger once the user opened the file as read only.
Private Sub Workbook_Open()
If ThisWorkbook.ReadOnly Then
MsgBox "Comeback some other time. File in use"
ThisWorkbook.Close False
End If
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Application.Quit
End Sub
The beauty of the IsWorkBookOpen approach is the speed compared to opening the workbook over a network compared to a ReadOnly test.
I would recommend you change your approach to load the check from a vbs, or a separate Excel file - as this is the best method.
The code below can be save in NotePad on your network drive as a vbs, say check.vbs. The code checks if the file is open, if not then it launches the file in a new instance of Excel. If it is, a message is provided.
vbs code
Dim objExcel
FileName = "C:\temp\file.xlsm"
If Not IsWorkBookOpen(FileName) Then
Set objExcel = CreateObject("Excel.Application")
Set ojbWb = objExcel.Workbooks.Open(FileName)
objExcel.Visible = True
Else
wscript.echo FileName & " already opened"
End If
Function IsWorkBookOpen(FileName)
Set oFSO = CreateObject("Scripting.FileSystemObject")
On Error Resume Next
Set objFile = oFSO.OpenTextFile(filename, 8, False)
ErrNo = Err
ObjFile.Close
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
set objFSO = Nothing
End Function
If you want to run the check from the actual file then you will need to change to the ReadOnly test
code
Private Sub Workbook_Open()
If Me.ReadOnly Then MsgBox "file already opened", vbCritical
End Sub
I post this as I have seen this question unanswered on other forums, too.
I wanted to use many shared excel workbooks on server which would be variously connected to each other.
I wanted to use the so called shared workbook so everyone could access it and especially for the reason that it would track the changes within (users, time,...)
I wanted the macro to check on opening the file to find out whether the file is opened by someone else and if "yes", it would tell the person to come back later.
Suggested replies here could not help and I believe there is no chance to create a macro for path of the file itself so that IsWorkBookOpen(ThisWorkbook.FullName)
could be used the way I tried.
I decided to write macro that would track changes within the Workbook as if it was "shared". This way I was able to "unshare" it and use the ReadOnly approach discussed here.

How to check if a workbook is open and use it

I've made a macro to open two workbooks and do some stuff with them. This macro runs from a third workbook that calls any other two user selected workbooks for which, before they're opened, I don't know their name.
So! I know Excel 2010 doesn't have a built in function to check if a workbook is open so, I've been trying to compare the workbook against Nothing but it doesn't work and every workaround I find in different sites tend to use the name of the workbook.
Is there another way of doing this?
The idea is to run a macro with the two user defined workbooks and then, maybe, re-running it in the same workbooks but Excel warms me of discarding changes.
Maybe a workaround could be to tell excel when it prompts for reopening, not to reopen and handle that error to just use the same workbooks, for which at least, I know how part or the names will be. For example, one will have the text "cluster" in it, and the other the word "translation" so, maybe in a loop like the next one, I could find and use the workbook I need but just If I already checked if it's open. Or, does this way works to see if it's opened already?
For each wbk in Application.Workbooks
If wbk.Name Like "*cluster*" Then
WorkingWorkbook = wbk.Name
End If
next
My code is as follows:
Sub structure()
Application.ScreenUpdating = False
Dim translationWorkbook As Worksheet
Dim clusterWorkbook As Workbook
If Not clusterWorkbook Is Nothing Then
Set clusterWorkbook = Application.Workbooks.Open(ThisWorkbook.Sheets(1).Range("E5").Value2)
Else
Set clusterWorkbook = Application.Workbooks(parseFilePath(ThisWorkbook.Sheets(1).Range("E5")))
End If
Set translationWorkbook = Application.Workbooks.Open(ThisWorkbook.Sheets(1).Range("E6").Value2).Worksheets("String_IDs_Cluster") 'Translation table target for completing
End Sub
The parameter passed to Workbooks.Open is the one written in the sheet by my next function:
Private Sub MS_Select_Click()
Dim File As Variant
Dim Filt As String
Filt = "Excel 97-2003 File(*.xls), *.xls," & "Excel File(*.xlsx),*.xlsx," & "Excel Macro File (*.xlsm),*.xlsm"
File = Application.GetOpenFilename(FileFilter:=Filt, FilterIndex:=2, Title:="Select Menu Structure File")
If File = False Or File = "" Then
MsgBox "No File Selected"
Exit Sub
End If
ThisWorkbook.ActiveSheet.Range("E5").Value2 = File
End Sub
Same for translationWorkbook but in a different cell and also, I was trying to create a function to parse and use the filename in a full path(Then I discovered the command Dir lol) but when I pass the filename, without the xls extension to Application.Workbooks(file) it sends me a "subscript range error". Why could that be?
Basically my questions are:
How can I check for an open workbook and use it? Either by handling the
error for excel's prompt or by not trying to reopen the same file.
Why does trying to open a workbook with Application.Workbooks() with the return of my function fails? And here my question splits in two... First: with my function, wouldn't it work if I give a string as an argument? Or maybe, before passing it as an argument, I need to assign the result of my function to a variable?
Second: If I try to open a workbook like this Application.Workbooks("clusterworkbook") it sends me another "subscript error" but, before I used the File Dialog prompt, I made it this way and worked fine.
Any help will be appreciated.
EDIT
Function ParseFilePath added:
Function parseFilePath(fullpath As Range) As String
Dim found As Boolean
Dim contStart As Integer
Dim contEnd As Integer
contEnd = InStr(fullpath, ".") - 1
contStart = contEnd
found = False
Do While found = False
If fullpath.Characters(contStart, 1).Text = "\" Then
found = True
Else
contStart = contStart - 1
End If
Loop
parseFilePath = fullpath.Characters(contStart + 1, (contEnd - contStart)).Text
End Function
How can I check for an open workbook and use it? Either by handling the error for excel's prompt or by not trying to reopen the same file.
Have done some small modifications to your procedure structure. Similar to what you were trying testing for the workbook variable to be nothing, only that you have to first attempt to set the variable, the way you were doing it will always return empty as you did not try to set it before. I have also tested for the translation workbook, as it mightt be open as well.
I'm assuming the values in E5 and E6 contain the FullName of the workbook (i.e. path + filename) and that parseFilePath is a function to extract the filename from the FullName.
Sub structure()
Application.ScreenUpdating = False
Dim clusterWorkbook As Workbook
Dim translationWorkbook As Workbook
Dim translationWorksheet As Worksheet
With ThisWorkbook.Sheets(1)
On Error Resume Next
Set clusterWorkbook = Application.Workbooks(parseFilePath(.Range("E5").Value2))
On Error GoTo 0
If clusterWorkbook Is Nothing Then Set clusterWorkbook = Application.Workbooks.Open(.Range("E5").Value2)
'Set Translation table target for completing
On Error Resume Next
Set translationWorkbook = Application.Workbooks(parseFilePath(.Range("E6").Value2))
On Error GoTo 0
If translationWorkbook Is Nothing Then
Set translationWorksheet = Application.Workbooks.Open(.Range("E6").Value2).Sheets("String_IDs_Cluster")
Else
Set translationWorksheet = translationWorkbook.Sheets("String_IDs_Cluster")
End If
End With
End Sub
Why does trying to open a workbook with Application.Workbooks() with
the return of my function fails? And here my question splits in two...
First: with my function, wouldn't it work if I give a string as an
argument? Or maybe, before passing it as an argument, I need to assign
the result of my function to a variable?
Not sure why it did not work, change the prodedure as indicated.
I tested the procedure above using this function to extract the Filename from the Fullname and it worked:
Function parseFilePath(sFullName As String) As String
parseFilePath = Right(sFullName, Len(sFullName) - InStrRev(sFullName, "\"))
End Function
Second: If I try to open a workbook like this Application.Workbooks("clusterworkbook") it sends me another
"subscript error" but, before I used the File Dialog prompt, I made it
this way and worked fine.
Bear in mind that you did not used that line alone, it most probably has something like:
set Workbook = Application.Workbooks("clusterworkbook")
So the command was to set a variable, not to open the workbook, as such the only situation in which this works is that the workbook is already open so the variable gets set. The times when it failed was when the workbook was not open and you tried to set the variable, given you an error.
Suggest to visit these pages
Excel Objects, On Error Statement
I have been using the below code to identify if the excel workbook is open. If yes, then i activate it and do some stuff. If not, i open it and do some stuff.
sub test()
Dim Ret
Ret = IsWorkBookOpen("Your excel workbook full path")
If Ret = False Then
Workbooks.Open FileName:="Your excel workbook full path", UpdateLinks:=False
Else
Workbooks("Workbook name").Activate
End If
end sub
Function IsWorkBookOpen(FileName As String)
Dim ff As Long, ErrNo As Long
On Error Resume Next
ff = FreeFile()
Open FileName For Input Lock Read As #ff
Close ff
ErrNo = Err
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
End Function

VBA Code to Update Links if Linked-to Workbook Closed

I have a workbook within which there are links to number of other workbooks. Ideally I'd like to code: When I open the workbook containing the links, will update the links, but only if the workbook that is being linked to is not open (either on my PC or another user's PC on the network, that can access it).
This is because:
a) if the workbook is already open the link should update anyway,
b) updating links to workbooks that are already open seems to cause errors.
I hope I'm making sense, please tell me if I'm not.
Thanks.
Try this
Sub UpdateLinks()
Dim v As Variant, i As Long
v = ThisWorkbook.LinkSources(XlLink.xlExcelLinks)
For i = 1 To UBound(v)
If Not FileInUse(v(i)) Then
Workbooks.Open (v(i))
End If
Next i
ActiveWorkbook.UpdateLink Name:=ActiveWorkbook.LinkSources
End Sub
Public Function FileInUse(sFileName) As Boolean 'Checks if a workbook is open
On Error Resume Next
Open sFileName For Binary Access Read Lock Read As #1
Close #1
FileInUse = IIf(Err.Number > 0, True, False)
On Error GoTo 0
End Function