In Excel-VBA, you can minimize the Excel Application once you opened the Workbook:
Private Sub Workbook_Open()
Application.WindowState = xlMinimized
End Sub
In Word-VBA, I tried this code, but it didn't work:
Private Sub Document_Open()
Application.WindowState = wdWindowStateMinimize
End Sub
It should be minimize the Word Application once you opened the Document.
Ok, after some testing I got it running, but it's a bit strange. It seems to be a timing problem.
This works:
Using DoEvents two times always works in my tests.
Only one DoEvents is not enough.
Info from Microsofts documentation about DoEvents:
Yields execution so that the operating system can process other events.
Private Sub Document_Open()
DoEvents: DoEvents
Application.WindowState = wdWindowStateMinimize
End Sub
That doesn't work either:
So I thought about adding a delay by using the API procedure Sleep and call this and DoEvents in a loop. But it didn't work.
Private Declare PtrSafe Sub Sleep Lib "Kernel32" (ByVal dwMilliseconds As LongPtr)
Private Sub Document_Open()
Dim index As Integer
For index = 1 To 5
DoEvents
Sleep 50
Next index
Application.WindowState = wdWindowStateMinimize
End Sub
Contrary to the Excel documentation, the Word documentation of the Application.WindowState property says that the windows state can only be set with an active window:
The state of an inactive window cannot be set. Use the Activate method to activate a window prior to setting the window state.
So maybe you try to call Application.Activate first and see if that helps.
Contrary to the Excel documentation, the Word documentation of the
Application.WindowState property says that the windows state can only
be set with an active window:
Unhandled Exception gave a best description about the Application.WindowState.
Private Sub Document_Open()
ActiveWindow.WindowState = wdWindowStateMinimize
End Sub
Related
We have an AddIn to get data from Sun Financials. It uses Sendkeys so we get the problem of NumLock randomly turning off.
Data is retrieved from Sun when the worksheet/book is recalculated.
I have VBA to turn NumLock back on if it's turned off, but how can I get it to run in any workbook I have open?
I tried putting an Application_Calculate in Personal.xlsb ThisWorkbook but it doesn't run.
How can I get it to run?
Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Private Sub Application_Calculate(ByVal Sh As Object)
If CBool(GetKeyState(vbKeyNumlock) And 1) = False Then SendKeys "{NUMLOCK}", True
End Sub
PS Putting it into the ThisWorkbook outside of personal.xlsb isn't an option, there's thousands of files it needs to work on plus they don't like workbooks with VBA in (company policy).
Got this working, by placing the following code into ThisWorkbook in Personal.xlsb
Bizarre. or not. It now works, but it's not worked until everything was correct. Here's what I've got:-
Code:
Option Explicit
Public WithEvents App As Application
Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
Private Sub App_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Set App = Application
If CBool(GetKeyState(vbKeyNumlock) And 1) = False Then SendKeys "{NUMLOCK}", True
End Sub
Private Sub Workbook_Open()
Set App = Application
End Sub
Private Sub App_SheetCalculate(ByVal Sh As Object)
Set App = Application
End Sub
So, when I hit F9 or change a cell, NumLock turns back on.
One stightly bizarre but useful feature is that the Undo list is preserved! I was expecting to have to restore it once I'd got the Numlock bit working, but as the VBA is only doing a Sendkey and not flagging anything as changing from within the VBA Excel miraculously isn't emptying the Undo or Redo list. So the maxim that VBA always empties the Undo/Redo lists isn't true.
The following code works as intended when I open word then open my test document. However, if I open the test document to start the first instance of Word, the timer kicks off while Word is loading up. Word then sits at loading till the timer runs out, document closes and a empty Word application is opened. The intended operation is open document; if idle for set time, save and close document.
I have users that share a document and same have a bad habit of locking their computer with the doc open, locking the file from anyone else editing it.
the goal of this is to save the file and close the doc after x time.
Private Sub Document_open()
StartCheckingIdle
End Sub
The TIMEOUTTIME below is set to 5 seconds for testing, but set it to 5 min say, and the document just sits at loading for that five minutes if Word was not open prior to double clicking the document to open.
Option Explicit
'Set the constant below for how long you want it to be idle before triggering
' Enter the time in hours:minutes:seconds form, like "00:30:00" for 30 minutes
Private Const TIMEOUTTIME As String = "00:00:05"
Private Declare Function GetQueueStatus Lib "user32" (ByVal fuFlags As Long) As Long
Private Const QS_KEY = &H1
Private Const QS_MOUSEMOVE = &H2
Private Const QS_MOUSEBUTTON = &H4
Private Const QS_MOUSE = (QS_MOUSEMOVE Or QS_MOUSEBUTTON)
Private Const QS_INPUT = (QS_MOUSE Or QS_KEY)
Private bCancel As Boolean
Private Sub WaitForIdle()
Dim t As Double
t = Now
Do While bCancel = False
If GetQueueStatus(QS_INPUT) Then
t = Now
DoEvents
End If
If Now - t >= TimeValue(TIMEOUTTIME) Then Exit Do
Loop
End Sub
Public Sub StartCheckingIdle()
Do Until bCancel
WaitForIdle
If bCancel = False Then
bCancel = True
ThisDocument.Close True
End If
Do Until GetQueueStatus(QS_INPUT) Or bCancel
DoEvents
Loop
Loop
End Sub
Public Sub StopCheckingIdle()
bCancel = True
End Sub
Currently trying to get working on a Word doc, but eventually will need to apply this to an excel file as well.
Yes, I burrowed this code from another question on here, though I think it might be slightly outdated. I am running Office 2010.
May try to check for an active window first in your document.
Private Sub Document_Open()
Do While Application.ActiveWindow.Active = False
DoEvents
Loop
MsgBox "Open"
End Sub
I have this Vba code that takes a lot of time to execute and i did this sub to stop the execution, But it didnt work , i used the Sendkeys function.
sub stop ()
SendKeys "{Ctrl,Pause}"
end sub
i want also to resume the execution of my Macro, i tried clicking Ctrl+Break but it didnt resume.
Thank you for helping.
Open VBE and insert a module and copy-paste the below code
Sub Main()
For i = 1 To 100000
DoEvents
Debug.Print i
Next i
End Sub
Sub PauseMacro()
Application.SendKeys "^{BREAK}"
End Sub
Go back to Sheet1 and on the developer tab insert a button and assign the PauseMacro to it.
Now run the Main sub and hit the button to stop the execution of the Main macro
Oh, btw. here's how to use the Application.SendKeys method.
You should avoid using SendKeys.
An approach similar to the one suggested by me how, but without using SendKeys could be this:
Global IsTimeToStop As Boolean
Sub Main()
IsTimeToStop = False
For i = 1 To 100000
DoEvents
Debug.Print i
If IsTimeToStop Then Exit Sub
Next i
End Sub
Sub PauseMacro()
IsTimeToStop = True
End Sub
Replace Global with Dim if this is not a standard module.
What about setting up a watch on a variable that breaks if it changes?
just right click on a variable and add a new watch.
I have an Excel workbook that has links to a webpage. The user can click on the links, which minimize the Excel window and open their browser. When they are done with the site, they minimize or close their browser, which returns them to Excel (as it was their previous active window).
I would like VBA to take an action (update a table) when the user is returned to Excel.
I've looked at the Workbook_WindowActivate event, but this only works if you are moving from one Excel Workbook to another within the Excel Application.
Maybe I could use Application.name or the Windows function GetActiveWindow somehow but I am not sure how best to do this.
Any ideas? Thanks!
You want to add an event handler for Workbook_SheetFollowHyperlink. You can then use the code below. This just checks to see if the webpage has focus. the ' DO EVENTS ' is where you would add your code and then exit the sub
'********************* References used
'* Microsoft Shell Controls An Automation : shell32.dll*
'* Microsoft HTML Objects Library: MSHTML.dll expand ยป *
'* Microsoft Internet Controls: IEFRAME.dll *
Private Sub Workbook_SheetFollowHyperlink(ByVal Sh As Object, ByVal Target As Hyperlink)
Dim ie As InternetExplorer 'IE window variable
Dim sUrl 'url of the webpage
Dim dt As Date 'timer
'set the url to look for
sUrl = Target.Address
'set initial timeout period *used instead of browser ready due to page redirection.
'you should also check the browser ready status
dt = DateAdd("s", 5, DateTime.Now)
Do While dt > DateTime.Now
DoEvents
Loop
'reset the timeout period to allow time to view and select
dt = DateAdd("s", 30, DateTime.Now)
Dim shShell As New Shell ' windows shell variable
'continue loop until we hit the timeout or the webpage no longer has focus
Do While dt > DateTime.Now
'Loop through all the IE windows
For Each ie In shShell.Windows
'check to see if the URL's match
If InStr(ie.LocationURL, sUrl) Then
Dim hDoc As HTMLDocument
'get the webpage document
Set hDoc = ie.document
'check to see if it has focus
If Not hDoc.hasFocus Then
ThisWorkbook.Activate
'''''''''''''
' DO EVENTS '
'''''''''''''
Exit Sub
End If
Set hDoc = Nothing
End If
Next ie
Loop
End Sub
Here's what I've ended up doing. I borrowed quite a bit from this post: How to make a macro which executes periodically in Excel?
When the user clicks on a hyperlink, the code starts periodically checking whether Excel is their active window. I've found that the GetActiveWindow function returns zero if the user is not in the Excel application and some positive number if they are. If the code finds that the user returned to Excel from a different window (the previous check found that they were in a different window and the current one finds they are in Excel) then my table gets updated and the timer stops checking for the active window.
Doing it this way has the advantage of working for any web browser.
Option Explicit
Dim ExcelIsActive As Boolean
Private Declare Function GetActiveWindow Lib "user32" () As Long
Dim m_dtNextTime As Date
Dim m_dtInterval As Date
Dim DisableFlag As Boolean
Private Sub Workbook_SheetFollowHyperlink(ByVal Sh As Object, ByVal Target As Hyperlink)
Call start
End Sub
Public Sub Enable(Interval As Date)
Call Disable
m_dtInterval = Interval
Call starttimer
End Sub
Private Sub starttimer()
m_dtNextTime = Now + m_dtInterval
Application.OnTime m_dtNextTime, "TestActive"
End Sub
Public Sub TestActive()
If GetActiveWindow > 0 Then
If ExcelIsActive = False Then
ExcelIsActive = True
Call RefreshQuery
End If
Else
ExcelIsActive = False
End If
If Not DisableFlag Then
Call starttimer
Else
Call Disable
End If
End Sub
Public Sub Disable()
Dim dtZero As Date
If m_dtNextTime <> dtZero Then
' Stop timer if it is running
On Error Resume Next
Application.OnTime m_dtNextTime, "TestActive", , False
On Error GoTo 0
m_dtNextTime = dtZero
End If
m_dtInterval = dtZero
End Sub
Sub start()
'Start the timer
DisableFlag = False
ExcelIsActive = True
'Sets the interval to be three seconds
Call Enable(#12:00:03 AM#)
End Sub
Public Sub RefreshQuery()
'I do my stuff here
'Stop the timer until the next time the user launches the browser
DisableFlag = True
End Sub
Say I have a button embedded into my spreadsheet that launches some VBA function.
Private Sub CommandButton1_Click()
SomeVBASub
End Sub
Private Sub SomeVBASub
DoStuff
DoAnotherStuff
AndFinallyDothis
End Sub
I'd like to have an opportunity to have some sort of a "cancel" button that would stop SomeVBASub execution at an arbitrary moment, and I'm not into involving Ctrl+Break here, 'cause I'd like to do it silently.
I guess this should be quite common issue, any ideas?
Thanks.
Add another button called "CancelButton" that sets a flag, and then check for that flag.
If you have long loops in the "stuff" then check for it there too and exit if it's set. Use DoEvents inside long loops to ensure that the UI works.
Bool Cancel
Private Sub CancelButton_OnClick()
Cancel=True
End Sub
...
Private Sub SomeVBASub
Cancel=False
DoStuff
If Cancel Then Exit Sub
DoAnotherStuff
If Cancel Then Exit Sub
AndFinallyDothis
End Sub
How about Application.EnableCancelKey - Use the Esc button
On Error GoTo handleCancel
Application.EnableCancelKey = xlErrorHandler
MsgBox "This may take a long time: press ESC to cancel"
For x = 1 To 1000000 ' Do something 1,000,000 times (long!)
' do something here
Next x
handleCancel:
If Err = 18 Then
MsgBox "You cancelled"
End If
Snippet from http://msdn.microsoft.com/en-us/library/aa214566(office.11).aspx
Or, if you want to avoid the use of a global variable you could use the rarely used .Tag property of the userform:
Private Sub CommandButton1_Click()
Me.CommandButton1.Enabled = False 'Disabling button so user cannot push it
'multiple times
Me.CommandButton1.caption = "Wait..." 'Jamie's suggestion
Me.Tag = "Cancel"
End Sub
Private Sub SomeVBASub
If LCase(UserForm1.Tag) = "cancel" Then
GoTo StopProcess
Else
'DoStuff
End If
Exit Sub
StopProcess:
'Here you can do some steps to be able to cancel process adequately
'i.e. setting collections to "Nothing" deleting some files...
End Sub
what jamietre said, but
Private Sub SomeVBASub
Cancel=False
DoStuff
If not Cancel Then DoAnotherStuff
If not Cancel Then AndFinallyDothis
End Sub
I do this a lot. A lot. :-)
I have got used to using "DoEvents" more often, but still tend to set things running without really double checking a sure stop method.
Then, today, having done it again, I thought, "Well just wait for the end in 3 hours", and started paddling around in the ribbon. Earlier, I had noticed in the "View" section of the Ribbon a "Macros" pull down, and thought I have a look to see if I could see my interminable Macro running....
I now realise you can also get this up using Alt-F8.
Then I thought, well what if I "Step into" a different Macro, would that rescue me? It did :-)
It also works if you step into your running Macro (but you still lose where you're upto), unless you are a very lazy programmer like me and declare lots of "Global" variables, in which case the Global data is retained :-)
K
~ For those using custom input box
Private Sub CommandButton1_Click()
DoCmd.Close acForm, Me.Name
End
End Sub
This is an old post, but given the title of this question, the END option should be described in more detail. This can be used to stop ALL PROCEDURES (not just the subroutine running). It can also be used within a function to stop other Subroutines (which I find useful for some add-ins I work with).
As Microsoft states:
Terminates execution immediately. Never required by itself but may be placed anywhere in a procedure to end code execution, close files opened with the Open statement, and to clear variables*. I noticed that the END method is not described in much detail. This can be used to stop ALL PROCEDURES (not just the subroutine running).
Here is an illustrative example:
Sub RunSomeMacros()
Call FirstPart
Call SecondPart
'the below code will not be executed if user clicks yes during SecondPart.
Call ThirdPart
MsgBox "All of the macros have been run."
End Sub
Private Sub FirstPart()
MsgBox "This is the first macro"
End Sub
Private Sub SecondPart()
Dim answer As Long
answer = MsgBox("Do you want to stop the macros?", vbYesNo)
If answer = vbYes Then
'Stops All macros!
End
End If
MsgBox "You clicked ""NO"" so the macros are still rolling..."
End Sub
Private Sub ThirdPart()
MsgBox "Final Macro was run."
End Sub