Modeless UserForm doesn't show on Alt+Tab.

J

Jim Luedke

I’m using Excel 2002 in Win 2000.

I'm using Stephen Bullen’s CFormChanger to beef up UserForm with
features like min/max buttons, sizeability, my own icon, etc.:

www.oaltd.co.uk

After tweaking, it works well, thanks to all you knights of the Net
(most recently Peter T.)

Now my problem is, I want it to show in the Alt+Tab dialog and it
doesn’t.

Yet at one point, it did appear there. So I might’ve broken it.

GetWindow(MyHWnd, GW_OWNER) confirms that Excel is the owner of my
UserForm. Is ownship an issue vis-a-vis Alt+Tab? (How could it be,
since an icon used to show in Alt+Tab?)

Do any other Windows properties affect Alt+Tab status?

(One wrinkle: When my icon did appear on Alt+Tab, it was not the one I
was loading (with WM_SETICON, ICON_BIG), but rather a duplicate Excel
icon. Don't know if that problem relates to my current one of no icon
showing at all.)

I don't think Excel’s “Windows in Taskbar” feature is relevant. When
you turn it on, every workbook appears on Alt+Tab, but with a
different icon--a workbook with tiny Excel ‘X’. So that looks like a
different animal.

I’ve scoured MSDN and cpearson.com, but am stuck.

Thanks much.

***
 
J

Jim Luedke

P.S.

- My UserForm shows on the Taskbar, at screen bottom, fine.

- Both UserForm and Taskbar button show my own ICON_SMALL.

***
 
J

Jim Luedke

P.P.S.:

Another test: I tried setting my icons to Excel’s own.

Getting Excel's icons is easy. (Interestingly, these return a
different number from each other):

hIcon = GetClassLong(g_ExcelHWnd, GCL_HICONSM)
hIcon = GetClassLong(g_ExcelHWnd, GCL_HICON)

Both values of hIcon work equally well in setting your small icon (my
UserForm's title bar and Taskbar button):

Call SendMessage(g_OurHWnd, WM_SETICON, ICON_SMALL, hIcon)

But once again, loading the big icon fails. Neither value of hIcon
adds (a second) Excel icon to Alt+Tab:

Call SendMessage(g_OurHWnd, WM_SETICON, ICON_BIG, hIcon)

***
 
P

Peter T

Try something along the following lines (not fully tested)

Private Sub UserForm_Resize()

If IsIconic(mFrmHwnd) Then
ShowWindow mFrmHwnd, SW_HIDE
SetWindowLong mFrmHwnd, GWL_HWNDPARENT, GetDesktopWindow
ShowWindow mFrmHwnd, SW_MINIMIZE
Else ' form being restored
If IsIconic(mAppHwnd) Then
' if XL is minimized restore it
ShowWindow mAppHwnd, SW_RESTORE
Else
' in case XL is not active window
AppActivate (Application.Caption)
End If

SetWindowLong mFrmHwnd, GWL_HWNDPARENT, mAppHwnd
End If

End Sub

' in the initialize event
mAppHwnd = FindWindow("XLMAIN", Application.Caption)

You didn't respond to my followup in your other thread, maybe you didn't see
it.

Regards,
Peter T


I’m using Excel 2002 in Win 2000.

I'm using Stephen Bullen’s CFormChanger to beef up UserForm with
features like min/max buttons, sizeability, my own icon, etc.:

www.oaltd.co.uk

After tweaking, it works well, thanks to all you knights of the Net
(most recently Peter T.)

Now my problem is, I want it to show in the Alt+Tab dialog and it
doesn’t.

Yet at one point, it did appear there. So I might’ve broken it.

GetWindow(MyHWnd, GW_OWNER) confirms that Excel is the owner of my
UserForm. Is ownship an issue vis-a-vis Alt+Tab? (How could it be,
since an icon used to show in Alt+Tab?)

Do any other Windows properties affect Alt+Tab status?

(One wrinkle: When my icon did appear on Alt+Tab, it was not the one I
was loading (with WM_SETICON, ICON_BIG), but rather a duplicate Excel
icon. Don't know if that problem relates to my current one of no icon
showing at all.)

I don't think Excel’s “Windows in Taskbar” feature is relevant. When
you turn it on, every workbook appears on Alt+Tab, but with a
different icon--a workbook with tiny Excel ‘X’. So that looks like a
different animal.

I’ve scoured MSDN and cpearson.com, but am stuck.

Thanks much.

***
 
J

Jim Luedke

Peter:

Is the other thread you mention the one where I was trying to hide the
minimized title bar of a Bullen-enhanced UserForm?

If so, I did take your advice, it works like a charm, and I did submit
my reply into that thread stating that in your code, SW_HIDE is the
thing that does the trick, but I had to comment out SW_MINIMIZE
because it un-hides the title bar again:

Private Sub UserForm_Resize()

If IsIconic(mFrmHwnd) Then
ShowWindow mFrmHwnd, SW_HIDE
' ShowWindow mFrmHwnd, SW_MINIMIZE
End If
End Sub

***

When I submitted that reply a couple days ago, it showed in the thread
fine. But looking at the thread now, you're right; I don't see my
reply.

I don't at all understand this Google interface, which is what I use.
It has a number of points of bone-headed logic. Is it their fault?

The thread has 7 entries by you & me, but the bodies of the last three
headings are suppressed. There seems to have no method to read those
messages, one of which I assume is my reply.

So big thanks for help on both.

Jim

***
 
J

Jim Luedke

Peter:

Aw, nix my last msg. I'm the one that's bone-headed, not Google.

I just discovered you *can* read the suppressed message (with link
'Individual message').

And, I now see that you're talking about your second reply, which I
indeed had not seen.

I will reply to that in that thread.

Thanks.

***
 
J

Jim Luedke

Peter:

Unbelievable. It works. Icon now shows on Alt+Tab.

***

And thanks to you, I learned a few things:

1. Window ownership (or whatever you call what GWL_HWNDPARENT sets)
seems to toggle Alt+Tab display. A window's parent may need to be the
Desktop.

2. Yep, I had to reinstate SW_MINIMIZE. Without it, the Alt+Tab icon
didn't show. That undoubtedly was the problem that started this
thread.

3. However, reinstating SW_MINIMIZE also reinstated that pesky
floating Win 3.1-style minimized title bar (if that’s the right
terminology--guess I was wrong calling it “MDI-style”). Which is what
I wanted to kill in the first place.

4. But happily, it went away again. I'm a little unsure about what
happened, but I surmise that, when Excel owned Me, it kept the
minimized title bar within its own space; whereas xferring my
parentage to Desktop invokes post-Win 3.1 behavior of hiding it at
3000,3000??

5. Finally, I really want the Alt+Tab icon to show at all times, not
just when minimized. All other apps do that, right? So I moved:

SetWindowLong(MyHWnd, GWL_HWNDPARENT, GetDesktopWindow)

amongst UserForm's startup stuff. (I actually put it in CFormChanger’s
class module.)

6. There is a residual problem:

The Alt+Tab icon isn't the icon I load (and which successfully
displays on the form and Taskbar button). It's the generic Windows
icon. If you have any ideas about that, I’d like to know. If not, I
can certainly live with it.

To summarize:

***

‘MODULE CFormChanger.
'Thanks to Steve Bullen.

‘Private Sub Class_Terminate()

‘By not xferring our parentage back to Excel on terminate, I feared we
'might be left in memory. But on exiting Excel (in fact, on just
exiting
'the workbook), we seem to be destroyed fine. So not necesary?:

‘Call SetWindowLong(MyHWnd, GWL_HWNDPARENT, ExcelHWnd)
‘End Sub

Public Property Set Form(oUserForm As Object)
‘This Bullen property--more of a method, really--is write-only.

‘(Apology: as a Delphi programmer, naked params w/out parens simply go
against God & country:)

Call SetWindowLong(MyHWnd, GWL_HWNDPARENT, GetDesktopWindow)
AddOtherGoodies ‘Min/max buttons, sizeability, etc.
End Property

Public Property Set ChangeIconTo(ByVal IconPath as String)

'Load and set ICON_SMALL and ICON_BIG.
'- ICON_SMALL displays on the U.L. corner of your window, and
' on the Taskbar button.
'- ICON_BIG displays on Alt+Tab. This has never worked for me.
End Property


‘MODULE UserForm.

Private FormChanger as CFormChanger

Private Sub UserForm_Initialize()

Set FormChanger = New CFormChanger
With FormChanger
If FindOurIcoFile(Path, ThisWorkbook.Path) Then
.ChangeIconTo = Path
End If
Set .Form = Me
'Etc.
End With
End Sub

Private Sub UserForm_Resize()
'Thanks to Peter T. in microsoft.public.excel.programming.

If IsIconic(MyHWnd) Then
Call ShowWindow(MyHWnd, SW_HIDE)
Call ShowWindow(MyHWnd, SW_MINIMIZE)
Else
If IsIconic(ExcelHWnd) Then
'If XL is minimized restore it
Call ShowWindow(ExcelHWnd, SW_RESTORE)
Else
' in case XL is not active window
Call AppActivate(Application.Caption)
End If
End If
End With
End Sub

Private Sub UserForm_Terminate()
Set FormChanger = Nothing
End Sub

'Or thereabouts.

***

So thanks again, Peter.

***
 
J

Jim Luedke

I just realized:

By changing UserForm's GWL_HWNDPARENT to the Desktop, it's the
Desktop's icon (the generic Windows icon) that shows on Alt+Tab.

It also explains why, when an icon appeared sporadically on Alt+Tab
before, it was a second Excel icon, since Excel was my parent window.

So maybe the Q is:

Can you show an icon other than your parent's, on Alt+Tab?

'Cause as I said, WM_SETICON displays ICON_SMALL just fine (form and
Taskbar), but fails to execute ICON_BIG (Alt+Tab).

***
 
P

Peter T

So maybe the Q is:
Can you show an icon other than your parent's, on Alt+Tab?

It's a good question. I'm guess it should be possible though I don't know
how. Keep tinkering, if/when you get it drop me a line!


Referring to your previous post -

Not sure why that was happening for you - you're not by any chance
re-showing an already loaded form, that could indeed cause your floating
window (I mean doing myForm.Show again while already loaded).

A hidden window's x:y is given a notional -32000:-32000. However you can't
simply move the hidden window (say with the MoveWindow API) back onto the
desktop to make visible.

Regards,
Peter T
 
P

Peter T

Can you show an icon other than your parent's, on Alt+Tab?

With thanks to Karl Peterson over in vb.general.discussion who suggested
instead of

SetWindowLong mFrmHwnd, GWL_HWNDPARENT, GetDesktopWindow
do
SetWindowLong mFrmHwnd, GWL_HWNDPARENT, 0&

I now see the form's custom icon in Alt-tab (when the form is minimized)

Regards,
Peter T
 
Joined
Sep 13, 2020
Messages
1
Reaction score
0
Try something along the following lines (not fully tested)
...
I just want to say how very grateful I am to you for your suggestion.
I wrote an Outlook macro which uses a Form but the user needs to browse while the Form is up so it has to be modeless. If the user clicks the bottom right hand corner of the screen to bring up the Desktop window, the Form disappears permanently, which is very frustrating. When you re-activate Outlook it does not display the Form.
I used your solution but had a further difficulty in establishing the handle of the window. Neither FindWindow nor a more complex process using EnumWindow (refer https://www.everythingaccess.com/tu...external-application-window-to-the-foreground) would return it. I suspect it may be due to the fact that a Form's class is generated (even though I omitted the Class parameter with 0& in the FindWindow call).
In the end I discovered I can just get the active window handle.
As the loss of modeless forms on going to desktop should be a common problem but I struggled to find anything on it, I'm returning the favour by including the summary below of what I learned on my journey. I hope this helps others as you have helped me. (Please forgive any bad code or descriptions, I am a 'noob' in VBA. :p )


Option Explicit

' Windows API Constant index to owner of window (incorrectly named as parent)
Private Const GWL_HWNDPARENT = -8

' Windows API Function to retrieve handle of active window.
' (Note using FindWindow or EnumWindows doesn't work -
' perhaps it's because a Form gets a generated class.
' Certainly the title of the window really is "Create Workflow", but it doesn't get found, even if you omit the Class parameter)
Private Declare Function GetActiveWindow Lib "USER32" () As Long

' Windows API Function to modify window attribute using window handle. (Needs to be defined differently for different versions, hence the Win64 compile constant.)
' Here used to change owner of Form to Desktop.
' Without this, when you click in the bottom right hand corner to see the Desktop, it brings the Desktop window to top, and of course Outlook and the Form window disappear.
' But when you re-activate to Outlook, Outlook doesn't know anything about the Form window!! Not does it appear in the Alt-Tab window list because Desktop is not an owner.
' Making Desktop the owner means that the Form appears in the Alt-Tab list.
' Note this is not recommended practice, but I can't find a better way.
#If VBA7 Then
#If Win64 Then
Private Declare PtrSafe Function SetWindowLongPtr Lib "USER32" Alias "SetWindowLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
#Else
Private Declare Function SetWindowLongPtr Lib "USER32" Alias "SetWindowLongA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
#End If
#Else
Private Declare Function SetWindowLong Lib "USER32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
#End If

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Sub WorkflowCreate()
'
' eMail bits

Dim olApp As Outlook.Application
Dim CurrItem As Object
Dim Email As MailItem
Dim SubjectEd, Ellipsis As String
Dim EmailSaved As Boolean
Dim hWnd As LongPtr

' Use the current email for information such as workflow title

Set olApp = Outlook.Application ' (Try With instead sometime)
On Error Resume Next
Select Case TypeName(olApp.ActiveWindow)
Case "Explorer" ' we are currently viewing Outlook main window
Set CurrItem = olApp.ActiveExplorer.Selection.Item(1)
Case "Inspector" ' we are currently viewing opened item window
Set CurrItem = olApp.ActiveInspector.CurrentItem
End Select
On Error GoTo 0
' Check if it is an email and save it
If Not CurrItem Is Nothing Then
If TypeOf CurrItem Is MailItem Then
Set Email = CurrItem
On Error GoTo Cont
Email.Subject = Replace(Email.Subject, "[Jira10]", "")
SubjectEd = Left(Email.Subject, 150)
If SubjectEd <> Email.Subject Then
Ellipsis = "..."
End If
SubjectEd = Replace(SubjectEd, ":", "")
SubjectEd = Replace(SubjectEd, "\", "-")
SubjectEd = Replace(SubjectEd, "/", "-")
SubjectEd = Replace(SubjectEd, ">", "-")
SubjectEd = Replace(SubjectEd, "<", "-")
SubjectEd = Replace(SubjectEd, "|", "-")
SubjectEd = Replace(SubjectEd, "?", "")
SubjectEd = Replace(SubjectEd, "*", "-")
SubjectEd = Replace(SubjectEd, """", "'")
SubjectEd = Replace(SubjectEd, "[", "")
SubjectEd = Replace(SubjectEd, "]", "")
SubjectEd = Replace(SubjectEd, "(", "")
SubjectEd = Replace(SubjectEd, ")", "")
SubjectEd = Trim(SubjectEd)
If MsgBox("Save email with subject " & SubjectEd & Ellipsis & "?", vbYesNo, "Create Workflow") = 6 Then
Email.SaveAs "H:\jpmDesk\Desktop\Temp\" & SubjectEd & ".msg", olMSG
EmailSaved = True
End If
Set Email = Nothing
Cont:
End If
End If

' Show the user the form - it will generate the email if they click OK
' Note
' To allow the user to browse Outlook during filling out the Form, it needs to be Modeless which means this sub continues and finishes.
' This means that the simplest approach is the form has to create the email as it knows when OK is clicked

Dim Form As WorkflowForm
Set Form = New WorkflowForm
If SubjectEd <> "" Then
Form.WorkflowTitle = SubjectEd
Else
Form.WorkflowTitle = "enter a title..."
End If
If Not EmailSaved Then
Form.AddlInfo = "None"
End If
Form.Show 'vbModeless commented out as form is now defined as ShowModal=False

' Give the Desktop ownership of the Form so it shows up in Alt-Tab
' (Note Outlook will still manage the life of the Form)

hWnd = GetActiveWindow()
SetWindowLongPtr hWnd, GWL_HWNDPARENT, 0& ' 0& = DesktopWindow


Set Form = Nothing
Set olApp = Nothing

End Sub ' WorkflowCreate
 

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