Best Practice for Obtaining hWnd

K

Karl E. Peterson

Hi Folks --

Is there any sort of agreed upon "best practice" for obtaining the hWnd of VBA
UserForms? Something that'll pretty much work wherever VBA may be found? I seem to
generally use some variation of this:

Option Explicit

Private Declare Function GetForegroundWindow Lib "user32" () As Long
Private hWnd As Long

Private Sub UserForm_Activate()
hWnd = GetForegroundWindow()
Debug.Print Hex$(hWnd)
End Sub

But I'm pretty much only working in either Word or Excel, and version 2003 at that.
Any reason to think that wouldn't work in PowerPoint, Access, 2007, 2000, elsewhere,
....? Is there a better (more universal) way?

Thanks... Karl
 
C

Clif McIrvin

Karl, I have limited experience with such matters, but I'll share my
observations and conclusions:

Some months ago I was attempting to manage position of the Assistant
Balloon in Access (2003).

After many hours of digging around API information I came to the sad
conclusion that with respect to Access, at any rate, I was pursuing a
hopeless cause as to the best of my ability to discover, all internal
Access position information was relative to the user area of the Access
window, *not* the Windows display area (as is hWnd). I believe that it
would be possible to develop routines that would be able to "travel
between the two worlds" but for my purposes it was not worth the effort.

I also understand that VBA UserForms and Access Forms are completely
different, and properties and methods effectively have no correlation
from one to the other.

I have also observed that the Excel and Access Application Objects
handle windows and screens very differently.

Not much to offer, but perhaps of some use to you.
 
R

Rick Rothstein

Hi Karl, what are you doing over here... slumming? <g>

I only do Excel (now), so I can't speak for the other Office products, but
you can find an Excel UserForm's hWnd using the FindWindow API. Here is a
working line from the UserForm's Initialize event from one of my previous
postings ...

hWnd = FindWindow("ThunderDFrame", Me.Caption)

I have no idea whether ThunderDFrame is usable elsewhere.
 
K

Karl E. Peterson

Hi Clif --

Well, okay, ya made me look. <g> I just tried the code I suggested, in Access 2003,
and it worked fine. (It appears Rick's FindWindow call would work, as well, given
the classname for the Access UserForm is the same as Word or Excel.) Note, I'm not
looking at the Access forms, but the VBA UserForms, here.

Thanks... Karl
 
K

Karl E. Peterson

Hi Rick --
Hi Karl, what are you doing over here... slumming? <g>

I actually lurk a lot, but don't have much reason to chime in because most of the
questions are about the object model(s). And, more importantly, VBA is the only
Road Forward for ClassicVB at this point. Gotta keep the brand alive!
I only do Excel (now), so I can't speak for the other Office products, but
you can find an Excel UserForm's hWnd using the FindWindow API. Here is a
working line from the UserForm's Initialize event from one of my previous
postings ...

hWnd = FindWindow("ThunderDFrame", Me.Caption)

I have no idea whether ThunderDFrame is usable elsewhere.

That seems to be a pretty common classname. I see it throughout Office 2003, but
was afraid it might change from version to version. (Anyone know how universal it
is?)

Your method has the advantage of being callable on demand, while the method I
suggested is only good when the form first fires up. So I would think FindWindow
might indeed be a better way to go, *if* the classname is stable.

Thanks... Karl
 
M

Manfred F

Hi Karl,

I'm not an API expert, but to get the handle for the word application window
GetActiveWindow Lib "user32" () As Long
works pretty fine : -)

Kind Regards,
Manfred
 
P

Peter T

Well hello again Karl!

As Rick says it's -
hWnd = FindWindow("ThunderDFrame", Me.Caption)

That's good for Excel 2000+ and AFAIK all Office 2000 or later with VBA6.

If you want to cater for anyone still using Office97 (most don't but I do) -

If Val(Application.Version) >= 9 Then
sClassName = "ThunderDFrame"
Else
sClassName = "ThunderXFrame"
End If

instead of checking the app version you could do
#If VBA6 ... #Else If ... #End IF
but will need a bit more for 2010/64bit

If there's any possibility a form with a similar caption could be showing
elsewhere, even in another instance, best to temporarily change the caption
to something unique.

Regards,
Peter T
 
K

Karl E. Peterson

Peter said:
Well hello again Karl!

As Rick says it's -
hWnd = FindWindow("ThunderDFrame", Me.Caption)

That's good for Excel 2000+ and AFAIK all Office 2000 or later with VBA6.

Good to know!
If you want to cater for anyone still using Office97 (most don't but I do) -

Ewww, no. Not anymore, thanks. :)
If Val(Application.Version) >= 9 Then
sClassName = "ThunderDFrame"
Else
sClassName = "ThunderXFrame"
End If

Still, a good nugget to have.
instead of checking the app version you could do
#If VBA6 ... #Else If ... #End IF
but will need a bit more for 2010/64bit

As I recall, and this is a very dim memory, that constant is predefined in VBA,
right? So I can use it in normal VB6 code, and it'll only come into play if the
code is sucked into VBA? I keep forgetting that. It's an incredibly useful tidbit!
If there's any possibility a form with a similar caption could be showing
elsewhere, even in another instance, best to temporarily change the caption
to something unique.

Yep. That's one of the reasons I tended against the FindWindow approach, as well.
But the GetActiveWindow approach is going to work pretty well, I think.
 
M

Manfred F

Hi Karl,

Karl E. Peterson said:

Thank You very much for this clarifying info.
I've only got a limited understanding of API functions, but - by occasion -
I was right then:
I use the GetActiveWindow to get "my" active word window and use
GetForegroundWindow to check whether word is in the foreground before I
display a userform or a messagebox. Eventually, I set "my" window to the
foreground before..

Regards,
Manfred
 
P

Peter T

As I recall, and this is a very dim memory, that constant is predefined in
VBA, right?

It exists in Office 2000+ VBA. It's main usage was to allow new VBA6 code to
compile in Office97

#If VBA6 then
use new method stuff which would bomb in Excel97
#Else
work around with old ways
#End If
So I can use it in normal VB6 code, and it'll only come into play if the
code is sucked into VBA?

Yes in the sense it doesn't exist in VB6, even with all the references to
VBA and object model.

#If VBA6 then
' this code module is being used in VBA
#Else
' this code module is in VB6 (but conceivably in say xl97)
#End if

IIRC this came up when discussing your SendKeys replacement.
Yep. That's one of the reasons I tended against the FindWindow approach,
as well. But the GetActiveWindow approach is going to work pretty well, I
think.

Typically want to get the form's hWnd in the Initialize event, I assume the
only time GetActiveWindow could be reliably used is in the form's Activate
event?

I'm curious though, what are the other reasons you tend against FindWindow,
even with a unique caption.

Regards,
Peter T
 
K

Karl E. Peterson

Peter said:
in message

Yes in the sense it doesn't exist in VB6, even with all the references to
VBA and object model.

#If VBA6 then
' this code module is being used in VBA
#Else
' this code module is in VB6 (but conceivably in say xl97)
#End if

IIRC this came up when discussing your SendKeys replacement.

Ahhh, right. I must burn this into my memory, because it's an incredibly useful way
to distinguish the slight differences in approach required between the two.
Typically want to get the form's hWnd in the Initialize event, I assume the
only time GetActiveWindow could be reliably used is in the form's Activate
event?

No, it oughta work anytime the user is interacting. But, hmmm, yeah if the form
were non-modal, it could conceivably return one of the main application windows as
well. Probably best to stick with caching the value at first activation.
I'm curious though, what are the other reasons you tend against FindWindow,
even with a unique caption.

Assuming the unique caption is one strike, for sure. But you also have no
"future-proofing" if they happen to change the classname. Those would be the bigger
drawbacks. But neither is so large as to be deal killers.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top