I have a VBA sub in Excel that executes DoEvents until the requirements are met. During this loop, I need to get external data & import that data as a table into the active worksheet. I cannot click "Existing connections" when the VBA code is in this section, and I don't understand why I can't do this. Can anyone explain to me why this isn't possible?
DoEvents allows other applications time to run and prevents your VBA code from locking the entire system. It does not allow you to interact with the VBA host application (Excel in this case), because the VBA code is currently executing.
From the MS documentation:
The DoEvents function surrenders execution of the macro so that the operating system can process other events. The DoEvents function passes control from the application to the operating system. Some instances in which DoEvents may be useful include the following:
Hardware I/O
Delay Loops
Operating System Calls
DDE Deadlocking
Emphasis mine
You may want to investigate integrating the 'get external data & import' process into your VBA code. It would, however, have to happen either before or after the DoEvents loop, not during.
Related
I have written a fairly complex application that uses Excel (2016) as front-end application for data stored in a MS Access database, using the ADO 6.1 library. I have noticed during macro code execution that SQL transactions triggered by my Excel application can take quite long to complete, and often the execution of the next line of code in my Excel macro depends on this SQL transaction first being completed. Unfortunately, macro code execution and SQL transactions are asynchronous operations, which means that the macro jumps to the next line of code even though the SQL transaction hasn't been completed.
My current work-around is to use a Sleep() function using the Windows API to insert a fixed delay, but this is a really ugly solution as it does reduce the performance of my application and depends very much on the CPU load, so it may sometimes work, sometimes not.
I haven't been able to find so far a solution to this problem, I can't find any hints on the Internet either.
Using Application.CalculateUntilAsyncQueriesDone doesn't help here either.
Does anyone have an idea or a hint how to halt macro code execution in Excel until an SQL transaction has been completed? Is there a method in ADO to check the completion of an SQL transaction?
Is your query within the Data/connections section?
I had this problem to, I turned off "Enable Background refresh" and added "DoEvents" to the VBA, this forces the data connection to refresh before it allows the code to continue. Downside to this is it makes excel feel like its locked up, But this resolved my issue.
Sub Button1_Click()
ActiveWorkbook.Connections("ScrapData").Refresh
DoEvents
....Other code....
End With
The application is writing data to the excel sheet.
As per our security standards we are blocking macros related to excel and word.
McAfee antivirus is blocking the macros.
The application is in C++ and the data written to excel is done by using MFC and worksheet functions.
when i debugging the code, it is trying to write or execute VBE7.dll and VBE7.dll is blocking by McAfee.
why it is trying to write or execute to VBE7.dll?
I have the following code in a Form Module in an xlsm:
Public Sub DoModal() ' Note: Called by LaunchHelper which is associated with F12 in Workbook_Open
Dim ewsActive As Worksheet: Set ewsActive = ThisWorkbook.ActiveSheet
If ewsActive Is Overview Then ' Overview is the CodeName of one of the Worksheets
Set ewsOverview = ewsActive ' This is a Private variable in the Form Module
ShowSafe
End If
End Sub
Private Sub ShowSafe() ' Calling Show directly caused random crashes, I concluded that these were caused by that the Form was not loaded into memory, this function makes sure, it is in memory before calling Show
Dim blnLoaded As Boolean: blnLoaded = False
Dim objForm As Object: For Each objForm In UserForms
If objForm.name = Me.name Then
blnLoaded = True
Exit For
End If
Next objForm
If blnLoaded = False Then
Load Me
End If
Show
End Sub
As far as I know:
VBA is single-threaded, it can never happen that two Subs or Functions are executed in parallel (e.g. while processing Worksheet_Activate, Worksheet_SelectionChange is also called, and the order of executing the statements inside those two functions is undetermined).
However, if we look at Excel+VBA as a system, then it is multi-threaded because Excel and VBA run in parallel (and Excel is multi-threaded itself, in addition).
My problem is:
I see a race condition in DoModal, because checking and acting is not atomic, and the following scenario is possible:
(1) The condition ewsActive Is Overview is evaluated as true, so we start executing the branch inside the If block.
(2) The execution is taken over by Excel, where the user switches to a different Worksheet.
(3) ShowSafe is called while we the ActiveSheet is not Overview but something else.
Do you agree with my reasoning? Is it correct that in spite of the checking, the Form might show up on a different Worksheet? So far, I have not succeded in making this error happen but I would like to know if it was possible in theory, even if it has only a low chance.
Where can I find more information about problems and guarantees related to multi-threading in VBA?
For the user to switch the ActiveSheet, Excel needs to process User Events. Experienced VBA programmers usually let Excel process user events by explicitly calling DoEvents, because Excel's GUI freezes/starves for CPU while VBA code is running. This suggests that the race condition you describe is extremely unlikely, if possible at all.
However, this non-concurrency between Excel's GUI and its VBA runtime is only know by practice. I didn't find official documentation that formally confirms that there's absolutely zero chance for Excel to process user events while VBA code is running (without explicitly yielding). We only know by practice that this chance is "almost zero".
For this reason I would say that your suggested race condition is, though extremely unlikely, theoretically possible until we have an official statement or documentation that rules out that concurrency.
p.s. I consider this question as of academic interest only, and the code of illustrative purpose only, because obviously there no relevance for a form to "check" whether it is actually loaded.
I'm not seeing what you're trying to do. Why does it matter what sheet is active when you show your user form? If it needs to be Worksheets("overview") then just Activate it on form Load event? It won't hurt if it's already active.
Similarly if you aren't sure if it's loaded then call Load just before your Show
Finally you're referring to the user form as Me - which implies that you're running this from the user form itself. So this code will not run unless the form is loaded into memory, so ShowSafe is pointless code.
I made function which use do while(true) - infinite loop (which controls other apps)
I am searching solution how to make form accessable - when I start app, access just loading and my form cannot be changed. At least I tried to make some "listening function" for key "S" to stop while and it doesnt work too (maybe I am doing it bad, is it possible?)
I just used
Do While (run) <code> Loop
I guess I will need at least 2 thread (1 thread handle infinite while, 2 thread for form, but I read access cannot handle Multithreading.)
I can ask, is there some possibility of make this work?
Jan.
MS Access or MS office are single threaded platforms and cannot perform parallel executions. Generally, having a blind loop or uncontrolled loop is not a good practice at all. If you have a blind loop function without a controller, you are wasting process cycles of your vba application.
what you can do:
use timer and set intervals how often your code must execute
Add "Do events" within the loop to use the process cycles to execute some other code when a code within loop is waiting for an external signal.
Add any sort of controller to break the loop.. simple if else condition
Migrate your code to an external .DLL and execute/control the function outside VBA
In short, VBA cannot perform threading. Using uncontrolled will freeze your application which will force you to use [CTRL] + F12 to stop the execution manually.
I used function "DoEvents" (it at least react for input - keyboard / mouse)
I'd like to be able to schedule an Excel macro (VBA) to run in the middle of the night (after a file is ready) to create a customized workbook (multiple sheets, pivot tables, charts, filters, outlines, custom formatting, etc.). Currently, the macro is fired up manually the next day. Furthermore, it needs to run unattended on a server (laptop goes home at night!). Anybody successfully do something like this? Please, no Unix-side hacks (e.g., Perl modules) - need full access to VBA features, including database functions. Thanks!
Well you have some options.
First, for all Excel has to be installed on server.
Then you create a sheduled task to call a program.
In this case you can write e.g. a vbscript or .NET program to call the app, load the document and starts its content (your VBA). That should work at all.
Or you move the VBA code to a program and target Excel with your code, but prolly more work.
If you do this with .NET you have prolly best success. e.g. you can add an eventlog for successful run, etc.
If you can leave Excel running on the server all the time, you can use Application.OnTime to schedule the next runs of a particular macro (once it's run, reschedule another in the macro code). When I worked in banking we used this all the time to run night-time jobs.
If you cannot leave Excel running, I have to say you may be in a world of pain. It's possible to start Excel using an AT job (scheduled task) but you may have headaches getting it to run under the correct user privileges and if you use any addins you'll experience regular disasters where they failed to load and stopped Excel from starting up. At the end of the day, Excel isn't really meant to be run on servers (it's actually a violation of the terms of use) and starting/running/stopping it is not going to be a reliable system even if you do get it to work.