Link to home
Start Free TrialLog in
Avatar of RAFAAJ
RAFAAJ

asked on

Inter-related Windows !!

Hi all,

I want to have a NotePad application stick to my form so if I move the form, the Notepad app will move with it and if I minimise the form it will also minimise.

I am not sure what Window Style I should set for the notepad to behave like that.

I have tried WS_CHILD but didn't really work.

Anybody on this one.

Thank you.
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

It would be similar to the code here:
https://www.experts-exchange.com/questions/21205433/synchronized-window-move.html

But instead of moving Form2, you would move your NotePad window using the SetWindowPos() API.
Avatar of RAFAAJ
RAFAAJ

ASKER

Thanks Idle_Mind,

I can't seem to Subclass NotPad !! It's very strange !!

I can subclass other application windows but not NotePad !!!

Here is what I have in the Form_Load event. ( Notice the lPrevProc which returns 0 indicating that Subclassing has failed !)


'in the Form Module

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
    (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal msg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
   
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
    (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Private Const GWL_WNDPROC As Long = (-4)
Private Const WM_MOVING = &H216
Private Const WM_SIZING = &H214

Private lngHwnd As Long
Private lPrevProc As Long



Private Sub UserForm_Initialize()

    Shell "NOTEPAD.EXE", 1
   
    lngHwnd = FindWindow("NotePad", vbNullString)
   
    MsgBox lngHwnd   ' \\ this returns a valid Hwnd #
   
     lPrevProc = SetWindowLong(lngHwnd, GWL_WNDPROC, AddressOf HookProc)
   
    MsgBox lPrevProc   ' \\ this returns 0 !! meaning Subclassing failed !! Why ??!!!


End Sub


The HookProc resides in a Basic Module .


Can you spot what I might be doing wrong ?!! or are some applications impossible to subclass ?!

Thanks.
Don't subclass NotePad.  VB can't subclass forms in an external application.

Subclass the VB form instead.

Then when it receives the WM_MOVING or WM_SIZING msgs, move the NotePad window accordingly using SetWindowPos() or another window moving/positioning API.
Avatar of RAFAAJ

ASKER

Oops !  That is True ...I knew that but I somehow forgot !

Basically, what I need to do is prevent the NotePad application to be close by the user while the Form is open.

I thought about subclassing NotePad but as you said that Can't be done because it is in a foreign Process,

An alternative will probably be to change the relevant NotePad Window Styles so it can't be closed while the form is loaded  and restore it defaults upon closing the Form.

Can you think of a better alternative  for achieving the above ?

Thanks for your help.

ASKER CERTIFIED SOLUTION
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

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
Pretty sure you can't undo these changes though so you would need to close Notepad yourself using SendMessage():

Option Explicit

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
 
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Private Const WM_CLOSE = &H10

Private Sub Command1_Click()
    Dim noteWnd As Long
    noteWnd = FindWindow("Notepad", vbNullString)
    If noteWnd <> 0 Then
        SendMessage noteWnd, WM_CLOSE, 0, 0
    End If
End Sub

Avatar of RAFAAJ

ASKER

Thanks very much for following up.

Disabling the X Button and the File Exit is probably the way to go .

Again thanks for your patience with this.
Just to add to this...

You can add/remove the system menu-items via their IDs (system commands) such as SC_CLOSE for the "Close" item. To restore them, you can manually add the menu-item(s) back with the proper SC_* ID or just call GetSystemMenu() with bRevert as True to restore it.


Form1:
----------------
Option Explicit

Private Type MENUITEMINFO
    cbSize As Long
    fMask As Long
    fType As Long
    fState As Long
    wID As Long
    hSubMenu As Long
    hbmpChecked As Long
    hbmpUnchecked As Long
    dwItemData As Long
    dwTypeData As String
    cch As Long
End Type

Private Declare Function GetSystemMenu Lib "user32" (ByVal hWnd As Long, ByVal bRevert As Long) As Long
Private Declare Function InsertMenuItem Lib "user32" Alias "InsertMenuItemA" (ByVal hMenu As Long, ByVal un As Long, ByVal bool As Boolean, ByRef lpcMenuItemInfo As MENUITEMINFO) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function DeleteMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long

Private Const MF_BYCOMMAND = &H0&
Private Const MFT_SEPARATOR = &H800
Private Const MFT_STRING = &H0
Private Const MIIM_STATE = &H1
Private Const MIIM_ID = &H2
Private Const MIIM_STRING = &H40
Private Const MIIM_FTYPE = &H100
Private Const SC_CLOSE = &HF060&
Private Sub Form_Load()
    '
End Sub
Private Sub Command1_Click()
    Dim hMenu As Long
    hMenu = GetSystemMenu(Me.hWnd, False)
    If (DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND) <> 0) Then
        Call DrawMenuBar(Me.hWnd)
        Call MsgBox("Menu deleted.")
    End If
End Sub
Private Sub Command2_Click()
    Call GetSystemMenu(Me.hWnd, True)
    Call DrawMenuBar(Me.hWnd)
   
    'Manually add the menu item...
    '
    'Dim hMenu As Long
    'Dim tMII As MENUITEMINFO
    'hMenu = GetSystemMenu(Me.hWnd, False)
    'With tMII
    '    .cbSize = Len(tMII)
    '    .dwTypeData = "Close" & vbNullChar
    '    .cch = Len(tMII.dwTypeData)
    '    .fMask = MIIM_STATE Or MIIM_ID Or MIIM_STRING Or MIIM_FTYPE
    '    .fType = MFT_STRING
    '    .wID = SC_CLOSE
    'End With
    'If (InsertMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND, tMII) <> 0) Then
    '    Call DrawMenuBar(Me.hWnd)
    '    Call MsgBox("Menu added.")
    'End If
End Sub