Getting the window handle of all the open workbooks

Jaafar Tribak

Well-known Member
Joined
Dec 5, 2002
Messages
9,625
Office Version
  1. 2016
Platform
  1. Windows
Dear experts,

I am trying to get the caption that is displayed on each window of all the open workbooks. I am using the code below to loop through all the workbook windows, get their handles and finally display their respective captions on a Msgbox.

I am having 2 problems:

1- The code loops only once instead of once for each open workbook !
2- The Msgbox displays an empty string instead of the workbook caption !

If I am not mistaken, problem 2 is due to the fact that the Class name"EXCEL7" used in the code refers to a worksheet and not to a workbook. The trouble is I can't figure out what a Workbook Class name is so that I can use it in the FindWindowEx Function :oops:


Code:


<font face=Courier New><SPAN style="color:#00007F">Private</SPAN> <SPAN style="color:#00007F">Declare</SPAN> <SPAN style="color:#00007F">Function</SPAN> FindWindowEx <SPAN style="color:#00007F">Lib</SPAN> "user32" Alias "FindWindowExA" _
(<SPAN style="color:#00007F">ByVal</SPAN> hWnd1 <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>, <SPAN style="color:#00007F">ByVal</SPAN> hWnd2 <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>, <SPAN style="color:#00007F">ByVal</SPAN> lpsz1 <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN>, <SPAN style="color:#00007F">ByVal</SPAN> lpsz2 <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN>) <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>

<SPAN style="color:#00007F">Private</SPAN> <SPAN style="color:#00007F">Declare</SPAN> <SPAN style="color:#00007F">Function</SPAN> GetWindowText <SPAN style="color:#00007F">Lib</SPAN> "user32" Alias "GetWindowTextA" _
(<SPAN style="color:#00007F">ByVal</SPAN> hwnd <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>, <SPAN style="color:#00007F">ByVal</SPAN> lpString <SPAN style="color:#00007F">As</SPAN> String, <SPAN style="color:#00007F">ByVal</SPAN> cch <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>) <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>


<SPAN style="color:#00007F">Private</SPAN> <SPAN style="color:#00007F">Sub</SPAN> CommandButton1_Click()
  <SPAN style="color:#00007F">Dim</SPAN> BookNameLenghth <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>
  <SPAN style="color:#00007F">Dim</SPAN> strBuffer <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN>
  <SPAN style="color:#00007F">Dim</SPAN> bBufferSize <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>
  <SPAN style="color:#00007F">Dim</SPAN> lParent <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>
  <SPAN style="color:#00007F">Dim</SPAN> lChild <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>

  lParent = Application.hwnd
  <SPAN style="color:#00007F">If</SPAN> lParent <SPAN style="color:#00007F">Then</SPAN>
    <SPAN style="color:#00007F">Do</SPAN>
      lChild = FindWindowEx(lParent, lChild, "EXCEL7", vbNullString)
      bBufferSize = 255
      strBuffer = <SPAN style="color:#00007F">String</SPAN>(bBufferSize, Chr(0))
      BookNameLenghth = GetWindowText(lChild, strBuffer, bBufferSize)
      MsgBox Left(strBuffer, BookNameLenghth)
    <SPAN style="color:#00007F">Loop</SPAN> <SPAN style="color:#00007F">While</SPAN> lChild
  <SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">If</SPAN>
<SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Sub</SPAN>
</FONT>


Obviously I could have used something like the code below but I wanted to get the workbook captions via their window handles:


<font face=Courier New><SPAN style="color:#00007F">Sub</SPAN> Test()
    <SPAN style="color:#00007F">Dim</SPAN> W <SPAN style="color:#00007F">As</SPAN> Workbook
    <SPAN style="color:#00007F">For</SPAN> <SPAN style="color:#00007F">Each</SPAN> W <SPAN style="color:#00007F">In</SPAN> Application.Workbooks
        MsgBox W.Windows(1).Caption
    <SPAN style="color:#00007F">Next</SPAN>
<SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Sub</SPAN>
</FONT>


Any help will be much appreciated.

Regards.
 

Excel Facts

How can you automate Excel?
Press Alt+F11 from Windows Excel to open the Visual Basic for Applications (VBA) editor.
With the help of WinSpy++, I have been able to find the Class name (I run Excel Version :10.0) of a Workbook which happens to be called : MS-SDIa . However the code above still doesn't work when I replace EXCEL7 with MS-SDIa

I tested the "MS-SDIa" Class name with the code below which displays the active workbook's window caption:


<font face=Courier New><SPAN style="color:#00007F">Private</SPAN> <SPAN style="color:#00007F">Declare</SPAN> <SPAN style="color:#00007F">Function</SPAN> GetWindowText <SPAN style="color:#00007F">Lib</SPAN> "user32" Alias "GetWindowTextA" _
(<SPAN style="color:#00007F">ByVal</SPAN> hwnd <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>, <SPAN style="color:#00007F">ByVal</SPAN> lpString <SPAN style="color:#00007F">As</SPAN> String, <SPAN style="color:#00007F">ByVal</SPAN> cch <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>) <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>

<SPAN style="color:#00007F">Private</SPAN> <SPAN style="color:#00007F">Declare</SPAN> <SPAN style="color:#00007F">Function</SPAN> GetParent <SPAN style="color:#00007F">Lib</SPAN> "user32" (<SPAN style="color:#00007F">ByVal</SPAN> hwnd <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>) <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>

<SPAN style="color:#00007F">Sub</SPAN> WkbkHndle_Test()
    <SPAN style="color:#00007F">Dim</SPAN> BookNameLenghth <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>
    <SPAN style="color:#00007F">Dim</SPAN> strBuffer <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN>
    <SPAN style="color:#00007F">Dim</SPAN> bBufferSize <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>
    <SPAN style="color:#00007F">Dim</SPAN> wkbkHwnd <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>
    
    wkbkHwnd = FindWindow("MS-SDIa", vbNullString)
    bBufferSize = 255
    strBuffer = <SPAN style="color:#00007F">String</SPAN>(bBufferSize, Chr(0))
    BookNameLenghth = GetWindowText(wkbkHwnd, strBuffer, bBufferSize)
    MsgBox Left(strBuffer, BookNameLenghth)
<SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Sub</SPAN>
</FONT>


If only I could find the parent of the workbook window using the GetParent API Function, I believe I could use the FindWindowEx in a loop to return all the open workbook handles .Unfortunately I have tried that but the GetParent function fails and retuns 0.


Any Ideas out there ? :p


Regards.
 
Upvote 0
Hello,

Windows API is pretty much out of my area of expertise, but I think you want to use EnumChildWindow or something like that.

For the current application, does this help?

Sub Test()
Dim win As Window
For Each win In Application.Windows
MsgBox win.Caption
Next win
Set win = Nothing
End Sub

Good Luck!
 
Upvote 0
This worked for me if I understand you correctly:

Sub Test1()
Dim w As Workbook, x As String
For Each w In Workbooks
w.Activate
x = x & Application.Caption & ", "
Next w
ThisWorkbook.Activate
MsgBox "The captions of all open workbooks in this instance of Excel are:" & vbCrLf & _
x, 64, "Open workbooks caption info..."
End Sub
 
Upvote 0
Thanks both of you guys.

Alas, it is not so much the caption of the open workbook windows that I want as to their handles.

I also wanted to get some practice with the FindWindowEx API function because it is much simpler than the EnumChildWindow and doesn't require a callback procedure.

Any other ideas most welcome.

Regards.
 
Upvote 0
Hello again,

(y) At last I found out what I was doing wrong : Contrary to what I thought, the Worbook window is not a child window of the excel application window.In fact it is a top level window and therefore its parent window is the Desktop.This means that the first argument of the FindWindowEx must be 0.

Below is the correct code that will return the window handle of each open workbook:

<font face=Courier New><SPAN style="color:#00007F">Private</SPAN> <SPAN style="color:#00007F">Declare</SPAN> <SPAN style="color:#00007F">Function</SPAN> GetWindowText <SPAN style="color:#00007F">Lib</SPAN> "user32" Alias "GetWindowTextA" _
(<SPAN style="color:#00007F">ByVal</SPAN> hwnd <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>, <SPAN style="color:#00007F">ByVal</SPAN> lpString <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN>, <SPAN style="color:#00007F">ByVal</SPAN> cch <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>) <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>

<SPAN style="color:#00007F">Private</SPAN> <SPAN style="color:#00007F">Declare</SPAN> <SPAN style="color:#00007F">Function</SPAN> FindWindowEx <SPAN style="color:#00007F">Lib</SPAN> "user32" Alias "FindWindowExA" _
(<SPAN style="color:#00007F">ByVal</SPAN> hWnd1 <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>, <SPAN style="color:#00007F">ByVal</SPAN> hWnd2 <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>, <SPAN style="color:#00007F">ByVal</SPAN> lpsz1 <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN>, <SPAN style="color:#00007F">ByVal</SPAN> lpsz2 <SPAN style="color:#00007F">As</SPAN> String) <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>

<SPAN style="color:#00007F">Private</SPAN> <SPAN style="color:#00007F">Sub</SPAN> CommandButton1_Click()

<SPAN style="color:#00007F">Dim</SPAN> lBookNameLenghth <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>
<SPAN style="color:#00007F">Dim</SPAN> strBuffer <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN>
<SPAN style="color:#00007F">Dim</SPAN> lChild <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Long</SPAN>
<SPAN style="color:#00007F">Const</SPAN> lBufferSize <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">Byte</SPAN> = 255
<SPAN style="color:#00007F">Const</SPAN> Msg1 <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN> = "This is the Caption Of workbook :  "
<SPAN style="color:#00007F">Const</SPAN> Msg2 <SPAN style="color:#00007F">As</SPAN> <SPAN style="color:#00007F">String</SPAN> = "Obtained by Using the FindWindowEx function "
strBuffer = <SPAN style="color:#00007F">String</SPAN>(lBufferSize, Chr(0))
<SPAN style="color:#00007F">Do</SPAN>
Counter = Counter + 1
    lChild = FindWindowEx(0, lChild, "MS-SDIa", vbNullString)
    <SPAN style="color:#00007F">If</SPAN> lChild = <SPAN style="color:#00007F">False</SPAN> <SPAN style="color:#00007F">Then</SPAN> <SPAN style="color:#00007F">Exit</SPAN> <SPAN style="color:#00007F">Do</SPAN>
    lBookNameLenghth = GetWindowText(lChild, strBuffer, lBufferSize)
    MsgBox Msg1 & Counter & vbNewLine & Msg2 & vbNewLine _
    & vbNewLine & vbNewLine & Left(strBuffer, lBookNameLenghth), vbInformation
<SPAN style="color:#00007F">Loop</SPAN> <SPAN style="color:#00007F">While</SPAN> lChild

<SPAN style="color:#00007F">End</SPAN> <SPAN style="color:#00007F">Sub</SPAN>
</FONT>


As you know, Excel doesn't provide a Handle property for the workbook object (or to any other object apart from the application for that matter), so I was thinking to add this property by combining the above technic and some class module coding.


Regards.
 
Upvote 0
You were on the right track with your first piece of code. The MS-SDIa window is purely a class to display the name in the task bar. It is a top level window if the option is set to show all windows in the taskbar otherwise it doesn't exist. However the Excel7 workbook windows are still created.

The problem you had is that they are children of XLMAIN. Instead they are children of XLDESK which is in turn a child of XLMAIN. You therefore need to add an extra layer to your code and it should work.

See:

http://www.markrowlinson.co.uk/apiwbopen.php

it should help I think.

:)
 
Upvote 0
mark007 said:
The problem you had is that they are children of XLMAIN.

Just to clarify the above should read:

"The problem you had is that they aren't children of XLMAIN."

Unfortunate typing....

:rolleyes:
 
Upvote 0
Thanks, Mark!

I just had a client call me this morning about a little custom piece I wrote for him hanging. He's pretty sharp and called me back later to say he had accidently opened it twice and he figured that was causing the problem.

I knew I would have to enumerate the windows somehow because I knew about the GetObject limitation and I also knew that you can open multiple instances of Excel. You just saved me a few hours of work as I am not that proficient when it comes to using the API. THANK YOU AGAIN!
 
Upvote 0

Forum statistics

Threads
1,215,644
Messages
6,125,991
Members
449,278
Latest member
MOMOBI

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top