Link to home
Start Free TrialLog in
Avatar of brockway
brockway

asked on

Making a Form System Modal?

Making a Form System Modal?
From: Tim Brockway   Email: BROCKWAYJT&AOL.COM    (860) 242-3947

(VB 5,  Win 95)
.
I should like to display a vb5 Form in System Modal form thus preventing input anywhere but that form. I should also like to detect all attempts to click or type in another area and redirect that input to the modal form. (By example MS Bob does this when asking for, say, a password).

Now the knowledge base has an example of setting System modal but this does not apply to VB5 Win32. (The SetSysModalWindow api is deleted). Quoting the knowledge base :

 "The SetSysModalWindow function is obsolete. This function is provided only for compatibility with 16-bit versions of Windows. The new input model does not allow for System Modal windows."

Anybody know how System modal can be achieved using VB5 Win 95?

Additionally is there any way to detect mouse/keyboard clicks outside a regular modally halted window?  I messed around with SetCapture etc but can't seem to code a routine that works. Anybody have an example of preventing mouse clicks outside a modal display and redirecting them to the modal form?


All suggestions gratefully received.

TIM
Avatar of MikeP090797
MikeP090797

You can monitor events outside your window by using the SetWindowsHookEx function. You can simulate a system modal form by detecting when it looses focus, and then setting the focus back to it again.
Declare Function SetSysModalWindow Lib "User" (ByVal hwnd%) As Integer

At an appropriate place in your code, add the following:

   Success% = SetSysModalWindow(hwnd)
Avatar of brockway

ASKER

For MrMick
Oops. Thanks for the effort but check the question regarding SetSysModalWindow. Thanks again.
Tim

For MikeP.

Looks good let me check it out and I'll send in the points.

Thanks a million
Cordially
Tim

Oops, I didn't read it carefully...  Good job MikeP
Dear MikeP,

Regarding: SetWindowsHook.
This requires a CallBack to notify the VB proc when the message (event) occurs. So far as I can figure out even VB5 can't handle this. The AddressOf keyword will pass a call back procedures address to an api but I don't see how that procedure can work. (I get the principles here but I can't find a single example on the details What thread do I specify?, which message am I intercepting? how does my callback proc pick up the callback message? and so on?). So unless you know how this might be done it's a dead end.

Regarding: Detecting  Lost Focus using simple VB events.
This seems like an obvious choice I agree but the Form lostfocus event only triggers (essentially) if there are no controls on the form. I tried this before and its virtually useless for knowing when a form loses focus to another form or app.

Sorry to be so dumb but I don't quite following the advice. If we can solve this one I'll go to all 400 points I have and my herd of camels !!!

Many thanks

Tim.

I realy haven't tried doing this myself, but I think you should pass App.ThreadID as the thread Id. If you want to entersept the keyboard commands, i think WH_KEYBOARD hook will be just fine. If oyu want to intersept all messages, you need the WH_CALLWNDPROC hook. So your call should look something like this:

hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf KeyboardProc, vbNull, App.ThreadID)

Function KeyBoardProc(Code as integer, wParam as long, lParam as long)
'Catch the messahe here.
End Fucntion

Regarding the _LostFocus event:
You can create a flag, which will be set to false on every _LostFocus event on every control on the form, and set to True with the _GotFocus event on every control. Then, using a timer chech the value of the flag.

or

Call GetForegroundWindow inside a timer event, and compare it to form's hwnd property. if it's equal, your form is active. If not - make it active.

Hope it helps.
Here's some sample code I wrote for hooking the mouse messages.  The same can be used with minor changes for the keyboard.  Hook both by changing the hHook to hKeyHook and dim hMouseHook as long.  You'll have to keep them seperate.

To play with this, create a new project, add a module to the project and add the code below, and then place two command buttons on Form1, and then set captions to "Hook" and "UnHook".  Place in the click events calls to the respective procedure calls.  WARNING, do not exit or stop while running without clicking the unhook button!

Also, make sure your immediate window is visible so you can see the results as the mouse moves within the VB IDE workspace.

To Brockway: Don't up the points, save them for questions you'll want to ask in the future.  200 is very fair for questions of this difficulty.  If you have trouble with this code, comment and I'll respond.  PS: The below code must be in a basic module, can't be in the form module (rules of AddressOf statement).

To MikeP: Go ahead and click answer so brockway can give you points once this issue is closed.  Note: int and uint are LONG Integer Values in 32 bit API Programming.

mrmick



Public Const WH_KEYBOARD = 2
Public Const WH_MOUSE = 7

'These will be need to examine and use data returned in MouseProc
Type POINTAPI
        x As Long
        y As Long
End Type

Type MOUSEHOOKSTRUCT
        pt As POINTAPI
        hwnd As Long
        wHitTestCode As Long
        dwExtraInfo As Long
End Type

Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long

Dim hHook As Long

Public Sub Hook()

   hHook = SetWindowsHookEx(WH_MOUSE, AddressOf MouseProc, vbNull, 0)

End Sub
Public Sub UnHook()

   hHook = UnhookWindowsHookEx(hHook)

End Sub
Function MouseProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

   If nCode < 0 Then
      MouseProc = CallNextHookEx(hHook, nCode, wParam, lParam)
   Else
      'Setting MouseProc to non-zero effectively removes
      'it form further processing.  To handle yourself,
      'exit here and don't forward to CallNextHookEx

      'Testing
      Debug.Print nCode; wParam; lParam; Now

      'Just a demo, do you're own thing here.

      'Pass it on if you're not going to handle it.
      MouseProc = CallNextHookEx(hHook, nCode, wParam, lParam)
   End If

End Function


Thanks guys. Give me a while to integrate all this and i'll post back the final version.

I'll post the points asap. I'm not getting the "Scoring" screen come up with the answers so I'll have to email the admin to allocate the points.

Keep up the good work. I think we all learning here.

Thanks again

Tim

ASKER CERTIFIED SOLUTION
Avatar of mrmick
mrmick

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I have asked the admin folks to award you both 200 points. If they do not show up please let me know.

I am still struggling but you've set me off in the right direction.

One final point.

Where do I get the values for API contstants etc. For example I'm looking for the value of WM_Help and dozens of others.  The VB API text viewer only has a subset and my SDK (Ms Developer Network) cd refers to the constant names but not there values. (Unless I'm just missing it).

Hope you all had a nice holiday.

Cordially.
Tim
Tim, you can find these values in the Win32 SDK.  The SDK includes C language header files that contain the definitions.  Look in the include directory (sub-directory of MSTools).

The SDK has a quick info button associated with each API function.  The quick info button displays information about the function including what header file to refer to for constant and structure definitions.

Specifically, WM_Help is defined in winuser.h and has a value of 0x0053 which is 83 in decimal.

Bought This Question.
What does "Bought this question mean".?

Keep up the good work

TIM