Issue With Event For A Textbox Class - excel

I have created a textbox class for a form.
When the textbox classes are on a form, the events work fine. However, when I place the textbox classes on a multipage, the events no longer work
(Separately, I understand that OnEnter, OnExit, BeforeUpdate and AfterUpdate events are not present in VBA (as in VB), however I have some code that I references external libraries that allows these 'events' to work).
I have extracts of the code below. Perhaps some kind soul might see what the problem is.
clsBusinessCaseTextBoxEvents:
Public WithEvents objTextBox As MSForms.TextBox
Private objParent As clsBusinessCaseEventControl
'------------------------------------------
'Initialize
'------------------------------------------
Public Sub Initialize(Parent As clsBusinessCaseEventControl)
Set Me.Parent = Parent
With Parent.UserForm.Controls
'Set objTextBox = .Add("Forms.TextBox.1")
End With
End Sub
'------------------------------------------
'Parent Property
'------------------------------------------
Public Property Set Parent(sglValue As clsBusinessCaseEventControl)
Set objParent = sglValue
End Property
Public Property Get Parent() As clsBusinessCaseEventControl
Set Parent = objParent
End Property
clsBusinessCaseEventControl
Private colCollection As Collection
Private objUserForm As UserForm
Public Event Change(objTextBox As clsBusinessCaseTextBoxEvents)
Public Event AfterUpdate(objTextBox As clsBusinessCaseTextBoxEvents)
Public Event Enter(objTextBox As clsBusinessCaseTextBoxEvents)
Public Property Set UserForm(frmUserForm As UserForm)
Set objUserForm = frmUserForm
End Property
Public Property Get UserForm() As UserForm
Set UserForm = objUserForm
End Property
Public Function AddTextBox() As clsBusinessCaseTextBoxEvents
Dim objTextBox As clsBusinessCaseTextBoxEvents
Set objTextBox = New clsBusinessCaseTextBoxEvents
'
objTextBox.Initialize Me
End Function
Private Sub Class_Initialize()
Set colCollection = New Collection
End Sub
and as a sample in this class
Public Sub Enter(objTextBox As clsBusinessCaseTextBoxEvents)
RaiseEvent Enter(objTextBox)
End Sub
And then in a normal module to add a textbox class
Dim objTextBoxControl As control
Set objTextBoxControl = frmBusinessCase.mtpBusinessCase.Page0.Controls.Add("Forms.TextBox.1", strTextBoxName, True)
As noted, when I enter the class textbox - when it is on a form - the 'OnEnter' event fires normally. But not when the class textbox is placed on a multipage on the form.
Can anyone help? Thx, JonS
Hi Rory, is this what you mean?
'==================================================================================================================
'############ Section BEGIN for: OnEnter, OnExit, BeforeUpdate and AfterUpdate ####################################
'------------------------------------------------------------------------------------------------------------------
'
'Unlike VB, VBA does not bring across the 'OnEnter, 'OnExit', 'BeforeUpdate' and 'AfterUpdate' events as methods
'into it's textbox class.
'
'Instead, to obtain this functionality, it is necessary to make a Windows API call to 'ConnectToConnectionPoint'
'
'The code in these partitioned blocks deals with these functions using this Windows API call
'------------------------------------------------------------------------------------------------------------------
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
#If VBA7 Then
Private Declare PtrSafe Function IIDFromString Lib "ole32.dll" (ByVal lpsz As LongPtr, lpiid As GUID) As Long
Private Declare PtrSafe Function ConnectToConnectionPoint Lib "shlwapi" Alias "#168" (ByVal punk As stdole.IUnknown, ByRef riidEvent As GUID, ByVal fConnect As Long, ByVal punkTarget As stdole.IUnknown, ByRef pdwCookie As Long, Optional ByVal ppcpOut As LongPtr) As Long
#Else
Private Declare PtrSafe Function IIDFromString Lib "ole32.dll" (ByVal lpsz As Long, lpiid As GUID) As Long
Private Declare PtrSafe Function ConnectToConnectionPoint Lib "shlwapi" Alias "#168" (ByVal punk As stdole.IUnknown, ByRef riidEvent As GUID, ByVal fConnect As Long, ByVal punkTarget As stdole.IUnknown, ByRef pdwCookie As Long, Optional ByVal ppcpOut As Long) As Long
#End If
'==================================================================================================================
'############ Section END for: OnEnter, OnExit, BeforeUpdate and AfterUpdate ####################################
'==================================================================================================================
'==================================================================================================================
'############ Section BEGIN for: OnEnter, OnExit, BeforeUpdate and AfterUpdate ####################################
'==================================================================================================================
Public Property Let SetControlEvents(ByVal TextBox As Object, ByVal SetEvents As Boolean)
Const S_OK = &H0
Static lCookie As Long
Dim tIID As GUID
Set objTextBox = TextBox
If IIDFromString(StrPtr("{00020400-0000-0000-C000-000000000046}"), tIID) = S_OK Then
Call ConnectToConnectionPoint(Me, tIID, SetEvents, TextBox, lCookie)
If lCookie Then
'Debug.Print "Connection set for: " & TextBox.Name
'MsgBox "Connection set for: " & TextBox.Name
Else
'Debug.Print "Connection failed for: " & TextBox.Name
End If
End If
End Property
Public Sub OnEnter()
'Attribute OnEnter.VB_UserMemId = &H80018202
'Debug.Print "[ENTER EVENT] " & oTextBox.Name & vbTab & "Value: " & vbTab & oTextBox.Value
MsgBox "On Enter"
Call TurnActiveFieldToYellow(objTextBox)
Call FormBusinessCaseDollarFieldsBlue(objTextBox)
End Sub

The whole issue appeared when placing class textboxes on a 'multipage' on a form, rather than the form itself (which does not cause this problem)
I am not strong on classes. However, the suggestion of gathering all of the textbox objects into a collection (after they have been created) and then hooking them up to the class, like in this link, got the events working again. You could probably improve on my code below.
To solve, and after the class textboxes have been created using the 'add controls' method.
Dim objTextBoxControl As Control
Set objTextBoxControl = frmBusinessCase.mtpBusinessCase.Page0.Controls.Add("Forms.TextBox.1", strTextBoxName, True)
I used this in an ordinary module and call the sub 'InitialiseEvents' once the textboxes have been created
Dim colCollection As Collection
Sub InitializeEvents()
Dim ctl As Object
Dim clsEvents As clsBusinessCaseTextBoxEvents
If colCollection Is Nothing Then
Set colCollection = New Collection
End If
'Loop through all the controls
For Each ctl In frmBusinessCase.Controls
If TypeName(ctl) = "TextBox" Then
'Create a new instance of the event handler class
Set clsEvents = New clsBusinessCaseTextBoxEvents
'Tell it to handle the events for the text box
Set clsEvents.Control = ctl
'Add the event handler instance to our collection,
'so it stays alive during the life of the workbook
colCollection.Add clsEvents
End If
Next
End Sub
Sub TerminateEvents()
'Here the collection of classes is destroyed so memory will be freed up:
Set colCollection = Nothing
End Sub
and then added this to, or have present in, the class module 'clsBusinessCaseTextBoxEvents':
Public WithEvents objTextBox As MSForms.TextBox
Private objParent As clsBusinessCaseEventControl
Public Property Set Control(objTextBoxNew As MSForms.TextBox)
Set objTextBox = objTextBoxNew
End Property
Private Sub Class_Terminate()
Set objTextBox = Nothing
End Sub

Related

Best way to activate an unsaved workbook

I have various code to create reports. The reports are added to a new workbook that does not get saved, the theory being that the user can choose whether to save the workbook or just close it after looking at the results. My code below will activate the unsaved workbook.
Sub ActivateWorkbook(wbResults As Workbook)
Dim objWindow As Window
With Application
.VBE.MainWindow.WindowState = vbext_ws_Minimize
For Each objWindow In .Windows
With objWindow
If .Caption <> wbResults.Name Then .WindowState = xlMinimized
End With
Next objWindow
With .Windows(wbResults.Name)
.WindowState = xlMaximized
.Activate
End With
End With
End Sub
This works okay with a single monitor. But if there is already more than one workbook and they are different monitors, it minimises windows in both (all) monitors and looks less than ideal. I am thinking that if I am able to identify which monitor has the active workbook, I could only minimize windows for that monitor (including the VBE, if required).
In reply to chris neilsen, I will include some basic code to illustrate what I'm calling the above procedure with. Please keep in mind that each procedure is varied in purpose and most of the code in each doesn't really pertain to this particular problem.
Sub ExampleCode()
Dim wbXXX As Workbook
Set wbXXX = Workbooks.Add
With wbXXX
'Main code here
End With
Call ActivateWorkbook(wbXXX)
Set wbXXX = Nothing
End Sub
Thanks to anybody trying to help. It is appreciated.
Okay, this seems to be working for me. It's not pretty. Note that "Microsoft Visual Basic for Applications Extensibility 5.3" is required to minimise the VBE, which is where the code is being run from, not the main Excel application. In any case, Activate has not worked for me reliably in the past. If it works for you, no need for any of this I guess. If anybody is game to test it, please let me know how you go. I have only tested on a dual monitor setup so far.
Objective: Show the new workbook in the same monitor as the active workbook when Activate does not work.
Private Declare PtrSafe Function FindWindow _
Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) _
As LongPtr
Private Declare PtrSafe Function MonitorFromWindow _
Lib "user32" _
(ByVal hwnd As LongPtr, _
ByVal dwFlags As Long) _
As LongPtr
Private Declare PtrSafe Function EnumDisplayMonitors _
Lib "user32.dll" _
(ByVal hdc As Long, _
ByRef lprcClip As Any, _
ByVal lpfnEnum As Long, _
ByVal dwData As Long) _
As Long
Private Declare PtrSafe Function GetSystemMetrics _
Lib "user32" _
(ByVal Index As Long) _
As Long
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Const MONITOR_DEFAULTTONEAREST = &H2
Private Const SM_CMONITORS As Long = 80
Private hWndMonitor As LongPtr
Private hActiveWorkbook As LongPtr
Private hVBE As LongPtr
Private lngMode As Long
Function MonitorCount() As Long
MonitorCount = GetSystemMetrics(SM_CMONITORS)
End Function
Function MonitorsAreTheSame() As Boolean
MonitorsAreTheSame = True
'Count of monitors
If MonitorCount > 1 Then
'Check the ActiveWorkbook
lngMode = 0
hWndMonitor = FindWindow("XLMAIN", Application.Caption)
EnumDisplayMonitors ByVal 0&, ByVal 0&, AddressOf MonitorEnumProc, ByVal 0&
'Check the VBE
lngMode = 1
hWndMonitor = FindWindow("wndclass_desked_gsk", Application.VBE.MainWindow.Caption)
EnumDisplayMonitors ByVal 0&, ByVal 0&, AddressOf MonitorEnumProc, ByVal 0&
MonitorsAreTheSame = CBool(hActiveWorkbook = hVBE)
End If
End Function
Private Function MonitorEnumProc(ByVal hMonitor As Long, ByVal hdcMonitor As Long, lprcMonitor As RECT, ByVal dwData As Long) As Long
If MonitorFromWindow(hWndMonitor, MONITOR_DEFAULTTONEAREST) = hMonitor Then
Select Case lngMode
Case 0
hActiveWorkbook = CStr(hMonitor)
Case 1
hVBE = CStr(hMonitor)
End Select
End If
MonitorEnumProc = MonitorCount
End Function
Sub Test()
Dim wbkTest As Workbook
Set wbkTest = Workbooks.Add
Call ActivateWorkbook(wbkTest)
Set wbkTest = Nothing
End Sub
Sub ActivateWorkbook(wbkResults As Workbook)
Dim objWindow As Window
With Application
If MonitorsAreTheSame = True Then
.VBE.MainWindow.WindowState = vbext_ws_Minimize
For Each objWindow In .Windows
With objWindow
If .Left = Application.VBE.MainWindow.Left Then
If .Caption <> wbkResults.Name Then .WindowState = xlMinimized
End If
End With
Next objWindow
Else
For Each objWindow In .Windows
With objWindow
If .Left <> Application.VBE.MainWindow.Left Then
If .Caption <> wbkResults.Name Then .WindowState = xlMinimized
End If
End With
Next objWindow
End If
.Windows(wbkResults.Name).WindowState = xlMaximized
AppActivate (.Caption)
End With
End Sub
this should be sufficient - no second sub for activation needed. These should show the new workbook in the foreground, no other windows changed.
Sub ExampleCode()
Dim wbXXX As Workbook
Set wbXXX = Workbooks.Add
With wbXXX
'Main code here
End With
wbXXX.Activate
Set wbXXX = Nothing
End Sub

Excel.. Get the cell contents with a single click and call vba function Problem

I use the following code to pass a variable to an external program. The code works fine with a single click passing the found data to the immediate window See Debug.print statement. (As long as the call to sub spark is not uncommented) IE 'Call Spark
If the call is uncommented a double click is required. IE Call Spark. From a user point of view very confusing and clumsy.
I have tried not using the Sub Spark() and running the code from within the
Sub Worksheet_SelectionChange
That makes no difference I need a double click.
Excel VBA is not my strong point, It's got me beat....
All that is needed is to grab the data with a single click and move on. The external call displays a stock chart. I do not need to edit the cell.
Regards
John
Option Explicit
Public stAppName As String
Public stockcode As String
Private Type POINTAPI
x As Long
y As Long
End Type
Private Type MSG
hwnd As Long
Message As Long
wParam As Long
lParam As Long
time As Long
pt As POINTAPI
End Type
Private Declare Function PeekMessage Lib "user32" _
Alias "PeekMessageA" _
(ByRef lpMsg As MSG, ByVal hwnd As Long, _
ByVal wMsgFilterMin As Long, _
ByVal wMsgFilterMax As Long, _
ByVal wRemoveMsg As Long) As Long
Private Const PM_NOREMOVE = &H0
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim Message As MSG
'check for left-mouse button clicks.
PeekMessage Message, 0, 0, 0, PM_NOREMOVE
If Message.Message = 512 Then
Debug.Print "You clicked cell: " & Selection.Address, Selection.Value
End If
stockcode = Selection.Value
'Call Spark
End Sub
Sub Spark()
Debug.Print "Spark: " & Selection.Address, Selection.Value
stAppName = "C:\Users\JCM\Desktop\AUTOIT\Spark test 10 first working.exe " & stockcode
Call Shell(stAppName, 1)
End Sub

Detecting Lost Focus in Excel Application, Workbook or Worksheet

Switching to another application via the system ALT-Tab hotkey, while working in MS Excel on MS-Windows causes Excel to lose the keyboard focus. How to detect this?
The Deactivate or WindowDeactivate events for the objects: Application or Workbook or Worksheet objects do not fire when MS Excel loses focus this way (of course, because losing the focus is not synonymous with Deactivating the window)
Try this code, please. I found it somewhere to the internet, three years ago and only adapted to serve my needs. For instance, it could not be stopped because of a wrong declaration of UnhookWinEvent API. Take care to not monitor the focus lost or got by using a MsgBox. In this way, pressing 'OK' the focus will be received again and you will be in an infinite loop. The focus status will be returned in the active sheet, range "A1" (received focus), respectively, "A2" (lost focus):
Copy the next code on top of a module (in the declarations area):
Option Explicit
Private Const EVENT_SYSTEM_FOREGROUND = &H3&
Private Const WINEVENT_OUTOFCONTEXT = 0
Private Declare PtrSafe Function SetWinEventHook Lib "user32.dll" (ByVal eventMin As Long, _
ByVal eventMax As Long, ByVal hmodWinEventProc As LongLong, ByVal pfnWinEventProc As LongLong, _
ByVal idProcess As Long, ByVal idThread As Long, ByVal dwFlags As Long) As Long
Private Declare PtrSafe Function GetCurrentProcessId Lib "kernel32" () As Long
Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare PtrSafe Function UnhookWinEvent Lib "user32.dll" (ByVal hWinEventHook As Long) As Long
Private handlColl As Collection
Copy the next code inside the module:
Public Sub StartMonitoring() 'it can be called from a Workbook/Worksheet event
StartFocusMonitoring
End Sub
Public Function StartFocusMonitoring() As Long
If handlColl Is Nothing Then Set handlColl = New Collection
StartFocusMonitoring = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, 0&, _
AddressOf WinEventFunc, 0, 0, WINEVENT_OUTOFCONTEXT)
handlColl.aDD StartFocusMonitoring
End Function
Public Sub StopEventHook(lHook As Long)
Dim LRet As Long
If lHook = 0 Then Exit Sub`
LRet = UnhookWinEvent(lHook)
End Sub
Public Sub StopMonitoring() 'it must be called manualy or by an event when need to stop monitoring...
'it did not work until I changed the StopEventHook declaration, using ByVal instead of ByRef
Dim vHook As Variant, lHook As Long
For Each vHook In handlColl
lHook = vHook
StopEventHook lHook
Next vHook
End Sub
Public Function WinEventFunc(ByVal HookHandle As Long, ByVal LEvent As Long, _
ByVal hWnd As Long, ByVal idObject As Long, ByVal idChild As Long, _
ByVal idEventThread As Long, ByVal dwmsEventTime As Long) As Long
'In case of an error the application will crush. So, bypassing the error is good to be done...`
On Error Resume Next
Dim thePID As Long`
If LEvent = EVENT_SYSTEM_FOREGROUND Then
GetWindowThreadProcessId hWnd, thePID
If thePID = GetCurrentProcessId Then
'Do not use here a MsgBox, because after pressing OK Excel application
'will receive focus and you will stay in an infinite loop...
Application.OnTime Now, "Event_GotFocus"
Else
Application.OnTime Now, "Event_LostFocus"
End If
End If
On Error GoTo 0
End Function
Public Sub Event_GotFocus()
Range("a1").value = "Received Focus"
Range("a2").value = ""
End Sub
Public Sub Event_LostFocus()
Range("a2").value = "Lost focus"
Range("a1").value = ""
End Sub
You must start monitoring from StartMonitoring Sub which can be called directly or through an event (Workbook_Open, for instance).
The monitoring can be stopped calling StopMonitoring Sub...

userform loop for hiding and unhiding through multiple sequences

So i have this string of code... It is in a userform and is all vba based (IE not pulling data from a spreadsheet.)
Private Sub CHECK1_Click()
If CHECK1.value = False Then
COMBO1.visible = False
Else
COMBO1.visible = True
End If
End Sub
It works for perfectly for exactly one checkbox and combobox pair, I need it to work on all 61 on of them, individually... Being new to this I looked at case select possability but it looks like i would have to spell in out.
the userform is called "ORDER1"
All of the check boxes are named "CHECK1" THROUGH "CHECK61"
They all correspond to the combobox' aptly named "COMBO1" THROUGH "COMBO61"
(CHECK1=COMBO1 throguh the entire form.)
How can I make this work without putting 61 'click' events into the code?
oh and I'm on excel 2010
In the comments there's already a "control array" with WithEvents as a possible solution, below I'll show another solution without the WithEvents:
Copy this code to Notepad and save it as CatchEvents.cls
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "CatchEvents"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
#If VBA7 And Win64 Then
Private Declare PtrSafe Function ConnectToConnectionPoint Lib "shlwapi" Alias "#168" (ByVal punk As stdole.IUnknown, _
ByRef riidEvent As GUID, ByVal fConnect As Long, ByVal punkTarget As stdole.IUnknown, ByRef pdwCookie As Long, _
Optional ByVal ppcpOut As LongPtr) As Long
#Else
Private Declare Function ConnectToConnectionPoint Lib "shlwapi" Alias "#168" (ByVal punk As stdole.IUnknown, ByRef riidEvent As GUID, _
ByVal fConnect As Long, ByVal punkTarget As stdole.IUnknown, ByRef pdwCookie As Long, Optional ByVal ppcpOut As Long) As Long
#End If
'All Other Control-Events also possible
'No need to use WithEvents
'No need to put every Type of control in seperate collection or array, each event will fire no matter which control,
'so in the eventcode controls can be separated from others
'you can give your controls additional properties
'Arguments as Cancel, KeyCode, KeyAscii , Button , x and Y still can be used
Private EventGuide As GUID
Private Ck As Long
Private ctl As Object
Private CustomProp As String
Public Sub MyListClick()
Attribute MyListClick.VB_UserMemId = -610
If TypeName(ctl) = "CheckBox" Then
ctl.Parent.Controls(Replace(ctl.Name, "CHECK", "COMBO")).Visible = ctl.Value
End If
End Sub
Public Sub ConnectAllEvents(ByVal Connect As Boolean)
With EventGuide
.Data1 = &H20400
.Data4(0) = &HC0
.Data4(7) = &H46
End With
ConnectToConnectionPoint Me, EventGuide, Connect, ctl, Ck, 0&
End Sub
Public Property Let Item(Ctrl As Object)
Set ctl = Ctrl
Call ConnectAllEvents(True)
End Property
Public Sub Clear()
If (Ck <> 0) Then Call ConnectAllEvents(False)
Set ctl = Nothing
End Sub
In the VBA-editor right click somewhere on your Project and choose Import file, a Class named CatchEvents will now be in your Class Modules.
Finally paste code below behind your Userform:
Private AllControls() As New CatchEvents
Private Sub UserForm_Initialize()
Dim j As Long
ReDim AllControls(Controls.Count - 1)
For j = 0 To Controls.Count - 1
AllControls(j).Item = Controls(j)
Next
End Sub
Private Sub UserForm_Terminate()
Dim j As Long
For j = LBound(AllControls) To UBound(AllControls)
AllControls(j).Clear
Next j
Erase AllControls
End Sub

Using timer to get Excel title

I have following code to get title of current opened excel file this code working fine. I use timer to every 10 seconds if title change then add new title in list1.
So question is there any method or event to detect if title change then my code work otherwise it not work not check. timer check every 10 seconds my pc work slow if I run this code
Private Const GW_HWNDNEXT = 2
Private Declare Function GetWindow Lib "user32" (ByVal hWnd As Long, _
ByVal wCmd As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
(ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Sub ListWins(Optional Title = "*", Optional Class = "*")
Dim hWndThis As Long
hWndThis = FindWindow(vbNullString, vbNullString)
While hWndThis
Dim sTitle As String, sClass As String
sTitle = Space$(255)
sTitle = Left$(sTitle, GetWindowText(hWndThis, sTitle, Len(sTitle)))
sClass = Space$(255)
sClass = Left$(sClass, GetClassName(hWndThis, sClass, Len(sClass)))
If sTitle Like Title And sClass Like Class Then
Debug.Print sTitle, sClass
List1.AddItem (sTitle)
End If
hWndThis = GetWindow(hWndThis, GW_HWNDNEXT)
Wend
End Sub
Private Sub Timer1_Timer()
ListWins "*.xls*"
End Sub
The answer is No. AFAIK, No there is no event as such in vb6 which will trap the title change in Excel or any other window. Also unfortunately 10 second timer might not be good. What happens if the title changes every 2 seconds? It will not retrieve all the titles
However try this alternative which does not use the Timer Control. See if your pc is still slow...
Sub Sample()
'
' ~~> Rest of your code
'
Wait 2 '<~~ Wait for 2 seconds
'
' ~~> Rest of your code
'
End Sub
Private Sub Wait(ByVal nSec As Long)
nSec = nSec + Timer
While nSec > Timer
DoEvents
Wend
End Sub
You can use the Excel COM API to do this. Unfortunately, there is no way of getting the Excel window title - but you could easily manufacture it by appending " - Microsoft Excel". Use the FullName property if you want the complete path.
Option Explicit
Private WithEvents m_oApplication As Excel.Application
Private Sub Command_Click()
' Get a reference to the FIRST instance of the Excel application.
Set m_oApplication = GetObject(, "Excel.Application")
End Sub
Private Sub m_oApplication_NewWorkbook(ByVal Wb As Excel.Workbook)
List1.AddItem Wb.Name
End Sub
Private Sub m_oApplication_WorkbookAfterSave(ByVal Wb As Excel.Workbook, ByVal Success As Boolean)
'List1.AddItem "WorkbookAfterSave: " & Wb.FullName
List1.AddItem Wb.Name
End Sub
Private Sub m_oApplication_WorkbookOpen(ByVal Wb As Excel.Workbook)
List1.AddItem Wb.Name
End Sub

Resources