Solved

Non modal common dialog

Posted on 2001-06-18
22
529 Views
Last Modified: 2007-12-19
Anyone know how to invoke the common dialog in such a way that it doesn't block events?  Would still like it to be "on top."  Is there an API solution, or must I build my own dialog?

Have an application which is receiving asynchronous events in the background from various devices.  These are being blocked by the common dialog.

Additionally, they are blocked by an ado "open recordset."  Need to eliminate that blockage too, but I'll ask that as a separate question later.
0
Comment
Question by:john_price
  • 7
  • 5
  • 4
  • +3
22 Comments
 

Expert Comment

by:spg01
ID: 6202774
create your own common dialog box and use the following code to keep the form ontop.

(I got this code from PeteWest)

     Option Explicit
     Public Const SWP_NOMOVE = 2
     Public Const SWP_NOSIZE = 1
     Public Const FLAGS = SWP_NOMOVE Or SWP_NOSIZE
     Public Const HWND_TOPMOST = -1
     Public Const HWND_NOTOPMOST = -2


     Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hwnd As Long, ByVal hWndInsertAfter
As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long
 ) As Long

     Public Function SetTopMostWindow(hwnd As Long, Topmost As Boolean) As Long

        If Topmost = True Then 'Make the window topmost
           SetTopMostWindow = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, FLAGS)
        Else
           SetTopMostWindow = SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,FLAGS)
           SetTopMostWindow = False
        End If
     End Function


To use this function just put the following in the Form_Load event of the form you want on top:

       Dim lRetVal as Long
       lRetVal = SetTopMostWindow(Me.Hwnd,True)

And then - in the Form_Unload event put:

       Dim lRetVal as Long
       lRetVal = SetTopMostWindow(Me.Hwnd,False)

This just stops it from being the topmost window.
0
 
LVL 142

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 6202867
I agree on the "Create your own Dialog form", but i disagree on the API calls. I use the
frmDialog.Show vbModeless, frmMain
code to display a form as topmost for my project, but not in front of everything!

Cheers
0
 

Expert Comment

by:spg01
ID: 6202940
fare comment, but if focus switches to another form then you dialog box will get lost behind the form that takes focus. Depends on the needs of the application I suppose.
0
 

Expert Comment

by:spg01
ID: 6203006
fare comment, but if focus switches to another form then you dialog box will get lost behind the form that takes focus. Depends on the needs of the application I suppose.
0
 

Author Comment

by:john_price
ID: 6203250
I know how to do the "on top" bit, thanks.  Was really asking about how to invoke the dialog modeless.  Guess you both agree that you can't.  Let me wait a day or two to see if anyone else has a suggestion.  I know you can invoke the dialog via API.  Wondering if there is a sendmessage or handle or thread management api that allows it to be non-blocking.
0
 

Author Comment

by:john_price
ID: 6203251
I know how to do the "on top" bit, thanks.  Was really asking about how to invoke the dialog modeless.  Guess you both agree that you can't.  Let me wait a day or two to see if anyone else has a suggestion.  I know you can invoke the dialog via API.  Wondering if there is a sendmessage or handle or thread management api that allows it to be non-blocking.
0
 

Author Comment

by:john_price
ID: 6203277
Further comment about creating my own dialog.  The file dialog is fairly complicated and includes some nice features users have gotten used to, such as "new folder."  I'd rather not reinvent all those wheels in order to get a modeless dialog if at all possible.
0
 
LVL 22

Expert Comment

by:rspahitz
ID: 6204203
How about opening a new modeless window which invokes the common dialog box.  If you build it as a separate thread, it will become an independent structure that has the CDL box modal only for that thread, then YOUR app can keep going.
0
 
LVL 15

Expert Comment

by:ameba
ID: 6204348
rspahitz is right. You can use another thread to show CommonDialog without blocking your application. Create ActiveX Exe, use 'Thread per Object' threading model ...
0
 
LVL 15

Accepted Solution

by:
ameba earned 150 total points
ID: 6204374
' ActiveX EXE Project ProjCD (has one class, form and module),
'     in Project properties select 'Thread per Object'
'     Compile and make ProjCD.exe
'
' class clsCD ---------------------------------------------
Option Explicit
Public Event FileSelected(ByVal Filename As String)
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, _
    ByVal hWndNewParent As Long) As Long

Public Sub ShowCD(frmHwnd As Long)
    Load frmCD
    frmCD.Move 100, -500, 100, 100
    SetParent frmCD.hWnd, frmHwnd
    frmCD.Show
End Sub

Private Sub Class_Initialize()
    Set ClassDialog = Me
End Sub

Public Property Let Filename(ByVal Filename As String)
    RaiseEvent FileSelected(Filename)
End Property


' Module1  ---------------------------------------
Option Explicit
Public ClassDialog As clsCD


' Form frmCD, add common dialog  ----------------
Option Explicit

Private Sub Form_Activate()
    Me.Hide
    CommonDialog1.ShowOpen
    ClassDialog.Filename = CommonDialog1.Filename
    Unload Me
End Sub


'---------------------------------------------------------------------
' Standard Exe Project (has only one form), add reference to ProjCD.exe
'
' Form1, add 2 buttons
Option Explicit
Private WithEvents CD As ProjCD.clsCD

' receive event when file is selected
Private Sub CD_FileSelected(ByVal Filename As String)
    Me.SetFocus
    MsgBox Filename
    Command1.Enabled = True
End Sub

' show common dialog
Private Sub Command1_Click()
    Command1.Enabled = False
    Set CD = New clsCD
    CD.ShowCD Me.hWnd
End Sub

' test multiple instances (this wont work in IDE, so compile ProjCD)
Private Sub Command2_Click()
    Dim x As Form1
   
    Set x = New Form1
    x.Left = Left + 1500
    x.Show
End Sub

Private Sub Form_Load()
    Command1.Caption = "Show CD"
    Command2.Caption = "New Form"
End Sub

Private Sub Form_Unload(Cancel As Integer)
    ' do not unload this form if file selection is in progress
    If Command1.Enabled = False Then Cancel = True
End Sub
0
 

Author Comment

by:john_price
ID: 6206554
Now, that's an idea.  I'll give that a try.  Have used the idea to provide a non-blocking activity, such as running a background animation to indicate a "busy" condition, but never thought of it for this.

Any way to split the points?  rspahitz gave the first answer, and ameba took the time to write and submit some code.  
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 15

Expert Comment

by:ameba
ID: 6206624
>Any way to split the points?
 
You can ask a 0 point question "Please, split points" in Community Support topic area
http://www.experts-exchange.com/jsp/qList.jsp?ta=commspt

Make sure you give A grade! If you think my comment is not for A grade, just ignore it.
0
 
LVL 22

Expert Comment

by:rspahitz
ID: 6206749
If it's too much of a hassle to split the points, then just award the points to ameba (A-grade!) since he gave you the answer.  I was actually impressed that he took the time to follow through that far!!! :)
0
 

Author Comment

by:john_price
ID: 6206930
I've posted a question as you suggest requesting these points be split.  If they can't, I'm asking that an additional 50 points be awarded to rspahitz.  Thanks.
-- John
0
 
LVL 22

Expert Comment

by:rspahitz
ID: 6207036
Thanks.  It appears to me that your split question (http://www.experts-exchange.com/jsp/qShow.jsp?ta=commspt&qid=20138002) properly addressed this issue.  These are usually be addressed within a week.
0
 
LVL 1

Expert Comment

by:Moondancer
ID: 6207720
All adjustments have been made.

Points for rspahitz here, please comment co finalize:

http://www.experts-exchange.com/jsp/qManageQuestion.jsp?qid=20138152

Moondancer
Community Support Moderator @ Experts Exchange
0
 
LVL 1

Expert Comment

by:Moondancer
ID: 6207749
CORRECTION ... Points for rspahitz here, please comment to finalize (problems posting Qs this morning, apologies):

http://www.experts-exchange.com/jsp/qManageQuestion.jsp?qid=20138156

Moondancer
Community Support Moderator @ Experts Exchange
0
 
LVL 22

Expert Comment

by:rspahitz
ID: 6207946
Thanks, john_price.
0
 

Author Comment

by:john_price
ID: 6208581
Thanks.  Have spent a good part of the day enhancing this code.  I want to be able to send in the dialogtitle, filter, etc, and get back the filename and filetitle.  Just about there...

Thanks guys.
0
 
LVL 15

Expert Comment

by:ameba
ID: 6208643
Thanks for the points.

I know my code is just a start-point.

Instead of Form_Activate, maybe you can use a timer and avoid showing the frmCD completely.

Maybe you can also implement Left and Top properties - position of common dialog depends on frmCD's position.

Note that everything must be handled/passed the async way - programming this is not as simple as it is with 'normal' sync common dialog.  But it is simpler than hacking/ hooking commondialog via APIs.
0
 

Author Comment

by:john_price
ID: 6210565
Form_Activate is fine.  The Hide statement works before it even paints, so I don't even see a flicker.  Besides, I made the form very small so that even if it did flicker, it would be unnoticable.  Tried invoking a form procedure, ShowDialog from the class which in turn showed the dialog, but that was enough to cause blocking.
By going through the several layers I've been able to make it *almost* like the regular dialog.  for example:

With cNMDialog
  .DialogTitle="Get File"
  .Filter-"Text Files|*.txt|All Files|*.*"
  .FilterIndex=1
  .InitDir="c:\Test"
  .FileName="TestStartFile.txt"
  .ShowOpen me.hwnd
End With

Private Sub cNMDialog_FileSelected(FileName As String, FileTitle As String)

debug.print FileName
debug.print FileTitle

End Sub



To code the use of the dialog in a simulated synchronous way, yet not block other events:
With cNMDialog
 ... invoke dialog like above
 Do Until m_blnFileSelected
  doevents
 Loop
 m_blnFileSelected = false ' reset for next time.
 debug.print .filename
 debug.print .filetitle
End With

Private Sub cNMDialog_FileSelected(FileName As String, FileTitle As String)
 m_blnFileSelected=True ' modular boolean variable
End sub

Thanks, ameba.  Sometimes solving a tough one can be fun.


0
 
LVL 15

Expert Comment

by:ameba
ID: 6214815
Yes, nice idea, doevents loop will make client code nicer.
Good job!
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now