Resize application window

L

Ltexeira

Greetings,
After looking through the various psots, I was able to patch together the
required APIs to convert an 'instance' to a handle, then use the handle to
resize an applications screen using MoveWindow or SetWindowPos from the
"Users32" lib.

This is handy when I "Shell" the application and need to size the window.
This works great for notepad.exe ( as in the examples I found posted ), but
does not work with AcroRd32.exe ( The Adobe Acrobat reader ).

The routines appear to return the proper handle, but the resizing routines
mentioned above have no effect on the window.

The code is generic and straightforward, important bits below.

hInst = Shell("C:\Program Files\Adobe\Reader 8.0\Reader\AcroRd32.exe
""C:\test.pdf""", vbNormalFocus)
hWndApp = GetWinHandle(hInst)
cX = GetSystemMetrics(SM_CXSCREEN)
cY = GetSystemMetrics(SM_CYSCREEN)
cY = cY - 200

RetVal = MoveWindow(hWndApp, 0, 0, cX, cY, True)
RetVal = SetWindowPos(hWndApp, HWND_TOP, 0, 0, cX, cY, SWP_NOZORDER)

pick one of above, neither works with AcroRd32, either works with notepad.

the subroutine code is in other posts and is generic. If it would help I'll
post it, but I'm hoping this is something specific to the adobe product, or
there is a better way to tackle this.

Been reading here for a while, it's a great resource.
 
L

Ltexeira

It seems that there were several handles, and the sub was returning only the
first
one found.

If I MoveWindow on every handle it finds a match for the process id, then it
works.

So the question now becomes : how can I identify the one out of several
handles
associated with the instance is the window itself so I can resize it?

Or .. is it okay to just go ahead an attempt to resize each handle that
matches the
process id? ( It works, but seems like a poor way to do this. )

I'm an older VB programmer getting back into gear after a long time away.
I appreciate your patience.
 
K

Karl E. Peterson

Ltexeira said:
So the question now becomes : how can I identify the one out of several
handles
associated with the instance is the window itself so I can resize it?

This routine will find the "top-level" window associated with any given hWnd:

Private Declare Function GetParent Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function IsWindowVisible Lib "user32" (ByVal hWnd As Long) As
Long

Public Function GetTopLevel(ByVal hChild As Long) As Long
Dim hWnd As Long

' Read parent chain up to highest visible.
hWnd = hChild
Do While IsWindowVisible(GetParent(hWnd))
hWnd = GetParent(hChild)
hChild = hWnd
Loop
GetTopLevel = hWnd
End Function
 
L

Ltexeira

Thank you for the quick response.

I have incorporated that code and have the following problem :

For the instance ID of the 'Shell'ed AcroRd32 there are several 'handles'.
For each of these handles, the function GetTopLevel returns the same number as
it is given.

Snippet follows :

Function GetWinHandle(hInstance As Long) As Long
Dim tempHwnd, tophnd As Long
tempHwnd = FindWindow(vbNullString, vbNullString)
Do Until tempHwnd = 0
If GetParent(tempHwnd) = 0 Then
If hInstance = ProcIDFromWnd(tempHwnd) Then
GetWinHandle = tempHwnd
tophnd = GetTopLevel(tempHwnd)
MsgBox "Found " & hInstance & " Handle " & tempHwnd & " Top : "
& tophnd
'Exit Do would normally exit, but want to see all found
End If
End If
tempHwnd = GetWindow(tempHwnd, GW_HWNDNEXT)
Loop
End Function

this produces several handles for the single instance number, with the top
level
always being the same number as the handle the function is given, example
of a single run produces :

Instance Handle TopHandle
3008 394434 394434
3008 394426 394426
. . .
. . .
3008 1377336 1377336

for a total of 11 different handles (in this case).

Please advise, and thanks again for your attention to this problem.

As a side note, can you direct me to a good reference for the Windows APIs as
they pertain to VBA? I don't mind buying books!
 
K

Karl E. Peterson

Ltexeira said:
Thank you for the quick response.

I have incorporated that code and have the following problem :

For the instance ID of the 'Shell'ed AcroRd32 there are several 'handles'.
For each of these handles, the function GetTopLevel returns the same number as
it is given.

It's a little hard to follow your code there, but the standard advice has always
been to avoid GetWindow loops when possible, which has been the case since VB5
introduced the AddressOf operator. I'd recommend using an EnumWindows callback
instead. Take a look at http://vb.mvps.org/samples/Shell32 for some code I wrote to
do this (specifically, the hWndShell function in Shell32.bas).

As to why GetTopLevel returning the same value passed, that's because you've already
ascertained that outcome with this test:
If GetParent(tempHwnd) = 0 Then

Which is to say, you're only passing top-level windows to it.
 
L

Ltexeira

I thought so (passing top levels to it).

Why are there so many top level handles for this one instance id?

One of them must be the 'one' I'm looking for!

I will check the link as suggested and see if that will resolve this
situation.

Thanks again.
 
L

Ltexeira

The code you refer to is the same code as the code I posted.

The differences are minor.

Please compare

Function GetWinHandle(hInstance As Long) As Long
Dim tempHwnd, tophnd As Long
Dim retval As Long
tempHwnd = FindWindow(vbNullString, vbNullString)
Do Until tempHwnd = 0
If GetParent(tempHwnd) = 0 Then
If hInstance = ProcIDFromWnd(tempHwnd) Then
GetWinHandle = tempHwnd
'Exit Do
End If
End If
tempHwnd = GetWindow(tempHwnd, GW_HWNDNEXT)
Loop
End Function

with

hWndJob = FindWindow(vbNullString, vbNullString)
Do While hWndJob <> 0
If GetParent(hWndJob) = 0 Then
Call GetWindowThreadProcessId(hWndJob, PID)
If PID = ProcessID Then
hWndShell = hWndJob
Exit Do
End If
End If
hWndJob = GetWindow(hWndJob, GW_HWNDNEXT)
Loop

and you'll see what I mean.

It's possible I got my code from an example posted by someone using yours
as a template.

..:., problem persists.

However, I can just go ahead and 'resize' the window (whether it exists
or not) of every handle I can associate with the instance ID.

That seems to work okay, it's just not as elegant as I'd like!
 
K

Karl E. Peterson

Ltexeira said:
The code you refer to is the same code as the code I posted.

Nope, the code I refered to uses EnumWindows rather than a GetWindow loop.
 
K

Karl E. Peterson

Ltexeira said:
I thought so (passing top levels to it).

Why are there so many top level handles for this one instance id?

One of them must be the 'one' I'm looking for!

I will check the link as suggested and see if that will resolve this
situation.

Are you familiar with Spy++? That's an extremely handy utility for this sort of
thing. Let's you find, immediately, any given window.
 
L

Ltexeira

Your link takes me to download Shell32.zip, which contains the following code
in the hWndShell function. ( Taken directly from the downloaded file )

Perhaps you are referring to a newer version of yours that is not posted for
download.

Public Function hWndShell(ByVal JobToDo As String, Optional ExecMode) As Long
'
' Shells a new process and returns the hWnd
' of its main window.
'
Dim ProcessID As Long
Dim PID As Long
Dim hProcess As Long
Dim hWndJob As Long

If IsMissing(ExecMode) Then
ExecMode = vbMinimizedNoFocus
Else
If ExecMode < vbHide Or ExecMode > vbMinimizedNoFocus Then
ExecMode = vbMinimizedNoFocus
End If
End If

On Error Resume Next
ProcessID = Shell(JobToDo, CLng(ExecMode))
If Err Then
hWndShell = 0
Exit Function
End If
On Error GoTo 0

hWndJob = FindWindow(vbNullString, vbNullString)
Do While hWndJob <> 0
If GetParent(hWndJob) = 0 Then
Call GetWindowThreadProcessId(hWndJob, PID)
If PID = ProcessID Then
hWndShell = hWndJob
Exit Do
End If
End If
hWndJob = GetWindow(hWndJob, GW_HWNDNEXT)
Loop
End Function


If you have a newer version that enumerates, please direct me to it.

Thanks.
 
K

Karl E. Peterson

Ltexeira said:
Your link takes me to download Shell32.zip, which contains the following code
in the hWndShell function. ( Taken directly from the downloaded file )

I am so sorry about that! That truly is ancient. I thought I'd updated that eons
ago.
Perhaps you are referring to a newer version of yours that is not posted for
download.
If you have a newer version that enumerates, please direct me to it.

Here ya go!

Private Type EnumWindowsData
ProcessID As Long
hWnd As Long
End Type

Public Function hWndShell(ByVal Job As String, Optional WindowStyle As
VbAppWinStyle = vbMinimizedNoFocus) As Long
Dim ProcessID As Long
' *************************************************************************
' Shells a new process and returns the hWnd of its main window.
' *************************************************************************

' Test WindowStyle for reasonableness
If (WindowStyle < vbHide) Or (WindowStyle > vbMinimizedNoFocus) Then
WindowStyle = vbMinimizedNoFocus
End If

' Launch process in requested mode.
On Error Resume Next
ProcessID = Shell(Job, WindowStyle)
On Error GoTo 0

' Determine main window handle for new process.
If ProcessID Then
hWndShell = hWndProcess(ProcessID)
End If
End Function

Public Function hWndProcess(ByVal ProcessID As Long) As Long
Dim ewd As EnumWindowsData
' *************************************************************************
' Fires off enumeration of all windows in system, seeking to return
' toplevel hWnd from requested process.
' *************************************************************************
ewd.ProcessID = ProcessID
Call EnumWindows(AddressOf EnumWindowsProc, VarPtr(ewd))
hWndProcess = ewd.hWnd
End Function

' ***********************************
' Private Methods
' ***********************************
Private Function EnumWindowsProc(ByVal hWnd As Long, lParam As EnumWindowsData)
As Long
Dim PID As Long

' Make sure this is a top-level window.
If GetParent(hWnd) = 0 Then
' Check what process it belongs to
Call GetWindowThreadProcessId(hWnd, PID)
If PID = lParam.ProcessID Then
lParam.hWnd = hWnd
End If
End If

' Return True to continue enumeration if we haven't
' found what we're looking for.
EnumWindowsProc = (lParam.hWnd = 0)
End Function

I'll try to get the update code out there shortly.

Thanks... Karl
 
L

Ltexeira

I'll download the updated zip, check it out and apply as directed!

Quite a long thread for this little glitch, eh?

Thanks for keeping up with it, your time is appreciated.

I will also examine spy++ as suggested.

Keep up the good work.
 

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