VBA - Closing or clicking OK in MsgBox from another workbook, - excel

Hi I the following code in Excel VBA,
Sub A ()
Workbooks.open ("A.xls")
ActiveWorkbook.Worksheets("1").Select
ActiveSheet.CommandButton1.value = true
End Sub
I'm opening another workbook (the code inside is protected so I can't modify the workbook "B") and clicking a run button on the worksheet, and it returns a MsgBox with OK button.
I want to know how I can use VBA to close this MsgBox or clicking "OK" ...I tried to use,
`application.DisplayAlert = false`
before opening the workbook "B" but this does not work..
Thanks for your help!

There might be an approach using SendKeys -- but SendKeys is notoriously temperamental. Here is a more reliable approach:
1) If you don't already have it organized like this, have the click-event handler of the button a 1-line sub that looks like:
Private Sub CommandButton1_Click()
Process
End Sub
Where Process is the sub which actually does the heavy lifting. In general, I think it a good idea to have event handlers mostly functioning as dispatchers to subs.
2) Change the code for Process (or whatever you choose to name it) in the following way:
a) Modify the first line to look like
Sub Process(Optional Verbose As Boolean = True)
b) Where Process has something like
MsgBox "Processed!"
replace it by
If Verbose Then MsgBox "Processed!"
3) In the code you gave above, replace the line
ActiveSheet.CommandButton1.value = true
by the line
Application.Run "A.xls!Process", False
This approach will bypass the button entirely and run the code which the button normally triggers, but run it in silent mode.
On Edit: To use SendKeys you could do the following. Put the line
Application.SendKeys "~"
before the line
ActiveSheet.CommandButton1.value = True
~ is the character shortcut for Enter. SendKeys doesn't itself send the keystroke, instead it puts something on the Windows Message Queue. VBA doesn't have any direct control about exactly when this message will be processed. In this case the lack of control is a benefit. The VBA interpreter moves onto the next line, which triggers the MsgBox. By the time the SendKeys message is processed the default Okay button on the message box has the focus hence receives the enter key. This can even happen before the box is painted, making it seem that the MsgBox was never there -- but that is better to think of it as being destroyed before you have time to see it.
The reason why it is necessary to have the SendKeys line before the line which clicks the button is that once the message box appears it will cause the VBA interpreter to wait until it is closed -- hence the calling code will suspend its execution until after the message box is closed, hence the SendKeys wouldn't be processed until it is no longer needed.
I don't really trust SendKeys. I suspect that sometimes when you run the code what will happen is that A1 in the newly activated sheet will receive the enter key (shifting the selection from A1 to A2) before the message box appears. I'm not sure if this can happen, but if it does a workaround might be to move the SendKeys to a VBScript program. Launch this program (with window minimized and not waiting for return) before the button is clicked. The VBScript program can have say an 0.5 second pause before it uses SendKeys. The script will be running in a different thread so it won't be blocked by the message box.

Related

Displaying an userform multiples times in a loop

I'm having trouble to loop an userform and get data from it.
My code is already properly working whenever I use it for a single use (out of the loop).
The objective is to send data obtained using the ComboBox values (which is done in the Userform code) in a sheet and this has to be done X times (X being defined by the user at the start of the code) but whenever I enter the loop, my userform is only displayed once.
I did see that some people used the vbModeless option but since I didn't notice any change, I thought of it being a hint but didn't find anything close to it that solved my problem.
Sub nouveau_controle()
Dim nbre_controle As Integer
nbre_controle = InputBox("Entrez le nombre de contrôles à effectuer")
For j = 1 To nbre_controle Step 1
Formulaire_nouveau_controle.Show vbModeless
Next j
End Sub
Thank you for any help you can give me.
If you open a form vbModeless, it means 2 things:
(1) you can continue to work with excel while the form is open
(2) your code will immediately continue to run after the Show
As the code continues to run, your code hits the Show-command without stop. When the user closes it, it is not reopened as the code is already executed completely
The opposite is to open the form modal (this is the default). Execution stops at the Show command and waits until the form is closed. In that case, you should see you form multiple times. Examples for typical modal forms are InputBox or MsgBox

Excel freeze after ListBox_DblClick if the mouse cursor is moved outside the Listbox during the event

Context
I'm using the Listbox_DblClick event of on an Excel Userform (within a .xlam AddIn) to do a bunch of thing (which mainly update the Userform, but alost does some external logging...). Those actions can take up to a few seconds.
Problem
Excel winbdows are let almost frozen if the user move the mouse cursor outside the Listbox during the ListBox_DblClick event.
Consequences
I cannot click anywhere on the UserForm or ActiveSheet or the VBA window. Even the close button of Excel is unresponding. But nothing seems to be running (the last line of the event has already ran, nothing visible on the CPU...)
To be able to interact with Excel again, I need to either :
move temporarly the mouse cursor back over the ListBox
or change temporarly the current Windows application (like by doing Alt+Tab twice).
Excel is then globally fine. There isn't any other consequence and everything runs OK after this freeze.
What I already checked
It's not related to an EnableEvents or ScreenUpdating issue. Those are correctly managed by the macro. Even adding two lines to set them to True at the end of the event don't resolve the issue.
It's not that the macro is still running. Adding Debug.Print "Finished" at the end of the event show that "Finished" prints normally, while Excel is kept frozen.
Since I don't want the user to launch a new event while the current event is still running, I prevent that by locking/delocking the many ListBox (including the one realted to the event) using ListBox.Locked at the beginning/end of the event. But commenting these lines doesn't resolve the issue.
Minimal Reproductible Exampe
Add an Array on a UserForm
Add the following code
Private Sub ListBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
For n = 1 To 3000
Me.Caption = n
Next n
Me.ListBox1.List = Array("Apple")
End Sub
Private Sub UserForm_Initialize()
Me.ListBox1.List = Array("Apple", "Banana")
End Sub
Double click on "Banana" and moove the mouse cursor
Note
In this post form 2012 (Editing listbox items in Dblclick event freezes Excel unless mouse moves over listbox), the user seems to encounter a similar issue.

How to create a code of clicking the button in VBA?

I have created a messagebox and coded so that the excel goes to the specific range where the button exists. But I do not know how to code so that the macro automatically clicks the button.
Sub Start()
Range("A4").Select
< >
End Sub
Sub MessageBox()
MsgBox "Hi" & vbCrLf & "Professor", _
vbInformation, "Greetings"
End Sub
I need something < > in this space but the process to automatically get linked.
Anyone have an idea?
In your example it looks like you have the name of the macro, and if that's the case it should be easy to just call it. See below
Sub Start()
Range("A4").Select
Call MessageBox
End Sub
Sub MessageBox()
MsgBox "Hi" & vbCrLf & "Professor", vbInformation, "Greetings"
End Sub
However, I'm guessing that doesn't help you because what you're asking doesn't truly make sense. I'm going to guess that maybe by MsgBox, you actually mean Form or Command Button. These look similar but they are distinctly different.
A MsgBoxis more of an alert to the user with the option to capture a small amount of information back (i.e. yes/no/ok/cancel etc). Clicking on a MsgBoxwill never directly launch another macro. An ANSWER to a MsgBox(i.e yes/no) MIGHT determine if another Macro is run based on an if-statement, or if the next line of code is simply just to execute another macro.
If you have a macro running distinctly based on a click, the button is likely a Form or an active X command Button. You need to figure out what macro this object is executing and then you just need to include this in your code. Google "how to see what macro a form button runs in VBA" or if it's an active X button, right click on it and hit "View Code". Both of these approaches should drive you to a macro name such as CommandButton1_Click.
Unfortunately, you might have to get more fancy as if it's a sheet Commandbutton1_Click you may have to make it public. Hopefully you can insert a call that code in your current macro.
Hope that helps.

Waiting for user input - with DoEvents a good idea?

My macro is going to compare a sheet with another sheet. This second sheet needs the user to paste data in there. (Note: The data being copied is not in Excel).
One way is to run the macro, and end it by prompting the user to paste the data in, then run "Macro2". However, I'd like to keep it all in one macro, so have found a way to wait for user input before continuing. This seems to work for me, so my main question is:
How stable is doing it this way?
...macro stuff above here
MsgBox ("[Please copy the data into the new sheet, after clicking 'OK']")
Do While WorksheetFunction.CountA(newWS.Cells(1, 7)) < 1
DoEvents
Loop
...then after the user pastes info, continue on, using the data that's been pasted.
The idea is that DoEvents just runs and runs while my sheet is blank. Right after the user pastes the data into the newWS, the macro continues on (since it will see data in column 7)...
Is this an okay method, or is it a bad idea to use like that? I've never really used DoEvents, so don't know if it's doing something in the background that could cause issues.
Edit: The data is in Lotus Notes, which I can export to Excel. However, that takes a few more steps (and I'd rather not create some new temporary excel files), so copy/pasting is my preferred method. This question is half practical, and half theoretical. Sorry for any confusion!
Probably not the best idea. Instead, allow them to select the data and perform the copy, all through VBA:
MsgBox ("[Please select data to copy into the new sheet, then press 'OK']")
newWs.Cells(1,1).PasteSpecial '### Modify to your specific location to paste the data
'Here you can add logic to validate that they have pasted enough data,
' and use control statement to prompt them to paste more data, etc.,
' if necessary, or exit sub early
'For example:
If WorksheetFunction.CountA(newWS.Cells(1, 7)) < 1 Then
MsgBox "Try again!"
Exit Sub
End If
Alternatively, you can use a DataObject:
Dim dataObj As New MSForms.DataObject
dataObj.GetFromClipboard
newWs.Cells(1,7).Value = dataObj.GetText
You could restructure the code so that it lives inside of a userform with ShowModal set to false (in the properties). Code prior to when you want the user to gather data can be put in the useform's initialize event. Then the userfrom shows (with a simple label caption and an okay button). Since it is modeless the user can copy data from an external program and paste it in. Then the rest of the code runs after the user hits okay. The form itself can be hidden during this phase. As proof of concept I created the following form:
with the following code:
Private Sub CommandButton1_Click()
Me.Hide
MsgBox Range("A1").Value
Unload Me
End Sub
Private Sub UserForm_Initialize()
'macro code can go here
'it runs before the form shows
'e.g.
MsgBox "Initializing"
End Sub
I launch the form on a blank sheet. First a message box appears before the code (confirming that code can run while the form is being initialized but before it is visible) then the form shows:
I go to an open instance of Notepad which contain a sentence and, while the form is still open -- paste it into A1:
Finally I press okay and the userform then hides itself but continues to run code (which now has access to the copied data):
Remember to unload the form at the end.

How to copy-paste from DOS application to Excel using SendKeys?

I'm trying to simulate this action:
activate another application,
send keystroke ctrl+c,
go back to Excel,
send key stroke ctrl+v
and have that value in a cell.
It's a DOS window style application, so keystroke is the only way to manage it.
I managed to activate and to input keystrokes such as ENTER into that DOS style application, but when I try ctrl+C it is not seen to do anything.
I tried simulating it in Excel VBA with:
Range("E7").Select
SendKeys "^c"
Range("G7").Select
SendKeys "^v"
The E7 value is not copied, but G7 (paste destination) is highlighted as if it was selected for copying.
Note: I am not trying to copy things from Excel to Excel, but to execute keystrokes using Excel.
I ran into the same issue today.
I solved it by waiting a bit after sending CTRL-C to the application. It seems nothing is copied if you immediately execute another script line.
SendKeys "^c"
WScript.Sleep 100 ' wait a bit after CTRL+C (otherwise nothing is copied)
In fact, the same issue seems to happen when switching to another app and sending CTRL+V.
Again, I solved it by waiting a bit:
AppActivate "Microsoft Excel"
WScript.Sleep 100 ' wait a bit after making window active
SendKeys "^v"
The problem is that copying and pasting takes some time and VBA is not waiting for it.
First you need to specify second argument of send keys method which is "Wait". Set it to true. Thus VBA execution is waiting for until sending keys is completed.
Secondly you need to wait until process of copying data to clipboard is completed. "Wait" in sendkeys is not doing it because it's not about sendking keys by VBA but it's about Windows working with clipboard. To do it please use my function IsCopyingCompleted.
Here's how final can look like:
SendKeys "^a", True 'Select all
SendKeys "^c", True 'Copy
Do
DoEvents
Loop Until Me.IsCopyingCompleted()
YourSheet.Paste
Function IsCopyingCompleted() As Boolean
'Check if copying data to clipboard is completed
Dim tempString As String
Dim myData As DataObject
'Try to put data from clipboard to string to check if operations on clipboard are completed
On Error Resume Next
Set myData = New DataObject
myData.GetFromClipboard
tempString = myData.GetText(1)
If Err.Number = 0 Then
IsCopyingCompleted = True
Else
IsCopyingCompleted = False
End If
On Error GoTo 0
End Function
I had this same problem - I developed code and it worked on my computer - SendKeys "^v"...but it did not work on another user's computer! I was trying EVERYTHING...delays, appreciate, accessig access from Excel, having the user check various settings, selection.paste...no good. Finally I noticed different syntaxes...we were using the same office version, I'm not sure about Windows. But I entered 6 different syntaxes and had it skip over if it failed....SendKeys with a capital v, enclosed in squigley brackets, each component in squigleys separated by a plus sign, etc. IT WORKED! 2 of the commands put the ^V in the body of outlook...I remove those 2 and I'm golden.

Resources