How to release an Aspen object and clear memory - excel

This is my first time using such forum.
I have exactly the same question as here:
How to release an object and clear memory in VBA
In this thread, the question was unfortunately not solved...
With Excel VBA I connect to another program (namely Aspen EDR). For that purpose I have an according Add-In installed. To access Aspen EDR I need to add an object. After I'm done I want to release the object to save some memory. First thing I tried is this:
Dim ObjEDR As BJACApp
Dim Path As String
Path = 'assume this is the correct path to the file i want to open
Set ObjEDR = New BJACApp ' Create the BJAC object
If Not ObjEDR.FileOpen(Path) Then
MsgBox "Can't open file!"
End If
'...
Set ObjEDR = Nothing
After I set the object nothing, Excel does not release the memory (as I can see in my task manager). Of course after a few hundred iterations (I have to open a lot of these files) I get an error message, that Excel is out of memory. I read a few threads and apparently nothing only deletes some kind of reference to the object but not the object itself, so I tried adding fileclose
'...
ObjEDR.FileClose
Set ObjEDR = Nothing
When executing the FileClose I can see that a little memory is released (0.5 of 3MB) but still there is a lot of memory accumulating.
Also when not using the "Now" it is not working and I get "runtime error'424': Object required" when executing Set ObjEDR = BJACApp
I also read about "pointers" that might cause the staying memory increase, but how can I find and clear/delete them?
Does anyone has an idea?
I would really appreciate it!

If .Quit (or the object's equivalent) and setting the object to Nothing is not working for you, then you could try relying on VBA's garbage collector to do the job.
Essentially what this means is that you would need to split the sub in two, have the main sub, and within that sub call the sub that will open and close your object. Hopefully, upon the second sub exiting, VBA will clean up those objects.
Sub Main()
Dim filePath As String
For Each [..] In [..] ' Or use a Do...Loop
filePath = 'assume this is the correct path to the file i want to open
openObj filePath 'call the sub below
Next [..]
End Sub
Sub openObj(ByVal Path As String)
Dim ObjEDR As BJACApp
Set ObjEDR = New BJACApp ' Create the BJAC object
If Not ObjEDR.FileOpen(Path) Then
MsgBox "Can't open file!"
End If
[...] 'your code to perform the needed actions with your obj
ObjEDR.FileClose
Set ObjEDR = Nothing
End Sub
I don't know anything about this object, but you should also try .Quit and .Close
Another method is to not create a new object for each path. Place the Set ObjEDR on the outside of your loop, and utilize the same object every time you open the new file.

Ok, to those who are interested:
The support of Aspen Tech told me that
ObjEDR.dispose()
should work, but just for versions above V8.4.
So this did not solved my problem and I built a workaround using MATLAB which opens and closes Excel after each run. So I loose time opening and closing the Excel file, but the memory of excel is not increasing until it stops working.

Related

Referencing an ExcelApp Object That Is Running in a Different Process (by A Different User) in VB6

So I have this problem with my app. It is supposed to take user inputs and archive them in Excel files. All of that would work just fine, if I didn't need to access said Excel files as a special user due to the company's safety restrictions.
I have a working piece of code that opens said restricted files just fine through creating a new process (it is pretty much the same as the one here).
I use the code as such:
Sub RunAsUser_Main()
Dim ExeCommand As String
ExeCommand = "C:\Program Files\Microsoft Office\Office16\EXCEL.EXE \\192.168.88.3\share\public\Workbook.xlsm"
RunAsUser "username", "password", "domain", ExeCommand, "C:\Windows"
'-------------------- OPEN WORKBOOK --------------------
Dim ret As Integer
Dim ExcelApp As Object
Dim WorkbookPath As String
Dim MyWorkbook As Object
On Error Resume Next
Set ExcelApp = GetObject("Excel.Application").Application
If ExcelApp Is Nothing Then
ret = MsgBox("error!", vbCritical + vbOKOnly, title)
Exit Sub
End If
...
All goes good right until the GetObject statement. The new process starts, Excel opens the workbook as it should and I have verified that it is run by the special user.
After this though, I am unable to reference the running ExcelApp object. It just returns nothing.
What is wrong with this code? I have very little experience with creation and management of processes, so I might be failing to see the obvious.
Thanks in advance!
Edit: After some more trying, I believe that there is no way to reference the workbook using standard commands (GetObject etc.). I will need some special code to make this work, and have no idea for where to look for it. Any advice on this?
I've also used the code from this thread that is supposed to list all current instances of excel. It does list the ones running under my current user, but does't register the one under my special user, same as with my previous attempts.

Excel VBA hangs when expanding [+] workbooks object variable in locals window

I'm having a problem trying to debug some code I've written that opens a shared Excel file from SharePoint (in desktop Excel app), scrapes schedule data, makes a few changes, saves and closes that file, then populates the scraped data into the current workbook formatted as a calendar.
As is typical, the code executes fine for me, but only works about 50% of the time when another user runs it. I'm still searching for fixes to those bugs - they are not the reason for my question today. I'll try as best I can to describe my problem and hopefully someone can tell what I'm doing wrong.
First step I do is to check whether the SharePoint file exists and if so, open it (no problems/errors typically encountered here for myself or anyone else):
Sub getcalendardata()
...define variables...
Application.EnableEvents = False
Application.ScreenUpdating = False
schedule = "https://mycompany.sharepoint.com/sites/Schedule/Shared Documents/Schedule.xlsx"
If URLExists(schedule) = 0 Then
MsgBox "Schedule not found. Check internet connection, login to Office 365, and try again."
Exit Sub
End If
Set schedulewb = Workbooks.Open(schedule, False, False)
schedulewb.AutoSaveOn = False
Application.WindowState = xlMinimized
Set schedulews = schedulewb.Worksheets("Design")
...more code here...
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
Function URLExists(url As String) As Boolean
Dim Request As Object
Dim ff As Integer
Dim rc As Variant
On Error GoTo EndNow
Set Request = CreateObject("WinHttp.WinHttpRequest.5.1")
With Request
.Open "GET", url, False
.Send
rc = .StatusText
End With
Set Request = Nothing
If rc = "OK" Then URLExists = True
Exit Function
EndNow:
On Error Goto 0
End Function
*** Occasionally, I run into issues with the cached file in MS Office's Upload Center becoming out-dated and asking to save a copy or discard changes, but that is a problem for another day.
The main problem I've come here for is that after stepping through the Workbooks.Open line, if I open the "Locals Window" to view the stored variables and try and expand the Workbook object "schedulewb" (Here:
Locals Window during code execution), code execution seems to stop or go into an infinite loop. It's like VBA is trying to expand the schedulewb object to display the properties, but isn't getting a response, so it just waits. I've not been patient enough to see if it ever self recovers.
The only thing I see is that the Locals Window schedulewb line goes blank (like it's trying to expand) and I can no longer step through, continue, or reset/end the code execution. I can however, break/pause the execution, at which point, schedulewb returns to the Locals Window list and I'm able to expand it with a very brief delay. Restarting or resetting code execution after this just puts the program into the previous stall pattern and the only recovery option (besides waiting potentially forever) is to close and restart excel via Task Manager. Interestingly, the actual Schedule Workbook I'm trying to peak inside now shows up in the Office Upload Center as a pending upload or having just been synced.
I've tried bypassing SharePoint by opening a local version of the Schedule Workbook saved to my computer, and as expected, I can interact with the Locals Window variables without consequence.
Is there something wrong with setting a SharePoint Workbook to a variable like I've done?
Has an upload/refresh been triggered by me trying to inspect the object properties, causing some other uncontrollable VBA/SharePoint event to infinitely loop in the background?
Could this be connected somehow to the Upload Center cache headache that I think is unrelated?
Thank you in advance for any insight...

How can I have an Excel VBA application in use without multiuser lock?

I have an app I coded in Excel that suits the needs of my project; it serves the purpose of keeping track of quite a lengthy process and prerequisites and such.
It feeds off of a certain number of tables in my file.
The thing is, only one user can currently work on that file; and since we have multiple teams working on different parts in parallel, it would be nice to host that somehow in a way that would remove the single-user restriction.
Do any of you have an idea of how I could work around this?
I worked on a solution for a very similar project of keeping track of a hospital's labor utilization (nursing employee census, if you will) on a day-to-day basis across every nursing-based department in the hospital system. This solution relies on a couple conditions:
That it will be unlikely two or more people will need to save data to the final file at the same time (meaning within seconds of each other).
All the various users of the file will have access to at least one commonly-shared network drive or location.
In our case, we created a new file each day, but it wouldn't be difficult to adjust the data-writing code to append data, rather than create a new file and dump data into that new file.
The rough outline of the process is this:
Create a read-only destination file (.xlsx in our case) in a network location that contains tables of data split between n worksheets.
Create an interactive form (.xlsm) that allows user input and then on form submission, opens the destination .xlsx file and saves the form data to it, then closes it. This interactive .xlsm file can be placed in the same network location, with shortcuts created on as many peoples' desktops (or departmental shares, for example) as necessary.
With the speed of Excel and VBA, this means you're only "opening" the destination file for a second or two to write the form data, no matter how long one user may have a copy of the form open.
One thing that will be necessary is to check if the file is open, and gracefully alert the user if they need to try again, which you can do with a function covering the related error codes, for example:
Function IsFileOpen(FileName As String)
Dim iFilenum As Long
Dim iError As Long
On Error Resume Next
iFilenum = FreeFile()
Open FileName For Input Lock Read As #iFilenum
Close iFilenum
iError = Err
On Error GoTo 0
Select Case iError
Case 0: IsFileOpen = False
Case 70: IsFileOpen = True
Case 53: IsFileOpen = "Not Found"
Case Else: Error iError
End Select
End Function
which can be called via some code like (pseudo code):
Private Sub UpdateData(ByVal thesheet As String)
Dim xlApp As New Excel.Application
Dim xlWkbk As New Excel.Workbook
If Not IsFileOpen(FileName) Then
Set xlWkbk = xlApp.Workbooks.Open(filename)
xlWkbk.Worksheets(theSheet).Activate
Else
MsgBox "Sorry, the file is currently in use. Please try again", vbOKOnly
Exit Sub
End If
End Sub
Or you could have it simply wait a few seconds (e.g. Wait 5) or more if the writing process doesn't cover that much data. The specific amount of seconds to wait would depend on testing write times based on your scenario and your data. That would be added as a nested If Not statement inside the previous one.
Then, when the result is that the file is not in use, simply write a series of subroutines to write the form data (stored as variables) to the destination sheet. End with something like
xlWkbk.Save
xlWkbk.Close
Set xlWkbk = Nothing
Set xlApp = Nothing
to save and close the workbook and clear your variables (memory cleanup and all that).
You may already be aware of this practice, but while you'll want to keep Excel visible during development, you'll definitely want to set Application.Visible = False on the production files for two reasons:
This will prevent users from getting confused by a lot of automation
It covers Application.Updating as well, which will really speed up data processing.

Unable to find the right excel file library reference error

Every time I open this Excel file I get this error which is in screenshot 1 and screenshot 2.
When I click OK it takes me to code windows and asks me to select library.
I tried everything to make it work but no luck.
Screenshot one and screenshot two:
Make sure that these references are in this Priority order.
HTML and Internet Controls need to be above OLE Automation.
If you are still having this issue after this, run a Repair on the Office install and it refreshes the .DLL files that may have been corrupted.
Update: 7/6/2017
The pervious answer above will re-associate the references and allow the script to compile.
However, there is a better way.
This issue occurs when the VBA script is shared to other computers that are not identical platforms(OS and MS Office versions) and use early binding. Early binding reduces latency and is the correct way when only intended for one computer.
The answer is to use late binding format in the script and not select any references. Change any data type objects other than object back to object and use the following format:
Sub Late_Binding()
Dim IE_App_obj As Object
Dim MyShell_obj As Object
Dim IE_Window_obj As Object
Dim Windows_cnt As Long
Dim x_cnt As Variant
Dim HTML_Element_obj As Object
Set IE_App_obj = CreateObject("InternetExplorer.Application")
'Use IE_App_obj to Navigate to webpage and control it.'
Set MyShell_obj = CreateObject("Shell.Application")
'Use MyShell_obj to find an existing webpage and control it.'
Let Windows_cnt = MyShell.Windows.Count
For x_cnt = Windows_cnt - 1 To 0 Step -1
On Error Resume Next
If Instr(MyShell_obj.Windows(x_cnt).Document.Title,"WebPage_Title") > 0 Then
Set IE_Window_obj = MyShell_obj.Windows(x_cnt)
Exit For
End If
Next
Set HTML_Element_obj = IE_Window_obj.Document.getElementByID("ID_text")
End Sub
Latency will increase but so will stability.

VBA Closing Excel Files

Say I have some VBA code in Access that uses excel for whatever reason. Sometimes I have trouble closing the file properly.
The code (I think) should look somewhat like this:
WBO.Close savechanges:=True
Set WBO = Nothing
XLO.Application.Quit
Set XLO = Nothing
rs.Close
db.Close
Here XLO is an excel object, WBO is a workbook object, rs is a DAO recordset and db is a DAO database. Even though the physical excel file closes there's still an "EXCEL.EXE" process occurring on my system, which stops me from running my program twice in a row. Does anyone know why this happens?
EDIT
I took out the rs.Close and then db.Close lines since I decided to manually export the data I was using from Access to Excel (there's too many rows and columns to copy each cell over efficiently). However, this didn't change the problem at hand.
Thank you,
Jesse Smothermon
There isn't an actual Excel object. Application is the top-level object but that Application object has an Application property which actually points to "the creator of the specified object". So trying to quit XLO.Application won't do what you think it should.
Presuming that XLO is of type Excel.Application then try just XLO.Quit instead of XLO.Application.Quit
Why not just:
application.displayalerts = false
WBO.save (or saveas whatever it matters)
WBO.close
set WBO = nothing
I don't see a memory problem with that...
Refer to this answer.
It worked for me.
Dim sKill As String
sKill = "TASKKILL /F /IM msaccess.exe"
Shell sKill, vbHide
If that works, mark the answer in the link with a ^, not mine.

Resources