Solved

exe as Mdi Child!

Posted on 2000-02-18
18
571 Views
Last Modified: 2012-06-27
I want to create an applicaton that is composed by many modules.
These modules are compiled-stand-alone visual basic's programs.
The main application can call all the other modules (without data swapping),
but the modules have to be like they were mdi child forms.
I have seen C++ programs that do that, but how can I do this using Vb?
0
Comment
Question by:domenico
  • 8
  • 3
  • 2
  • +4
18 Comments
 
LVL 10

Expert Comment

by:caraf_g
ID: 2534093
The short answer: NO

The slightly longer answer: You can make something behave to some extent like an MDI child, but it won't be perfect, and you won't be able to do some of the standard MDI stuff.
0
 

Author Comment

by:domenico
ID: 2534204
..and if i want to do "something behave to some extent like an MDI child"
?
0
 
LVL 1

Expert Comment

by:macu
ID: 2534205
I've got some code to allow you to use ActiveX Dll forms as MDI forms, but I can't find the URL that I got it from. I can mail it to you if you like.
0
 
LVL 10

Expert Comment

by:caraf_g
ID: 2534227
and if i want to do ...

1 - you'll need to find the window handle of the child window area of your MDI form. That can be done as follows...

Option Explicit
Private Declare Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As Long, ByVal wFlag As Long) As Long
Private Const GW_CHILD = 5
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long
Private Sub MDIForm_Load()

Dim hwndC As Long

hwndC = GetNextWindow(Me.hwnd, GW_CHILD)

SetParent Form1.hwnd, hwndC

Form1.Show

End Sub



(More to come)

0
 
LVL 10

Expert Comment

by:caraf_g
ID: 2534235
2 - You'll need to use the SetParent API to make the window a child window of your MDI form.

Check out this URL
http://www.experts-exchange.com/jsp/qShow.jsp?ta=visualbasic&qid=10165031

Which explains how to do it and how to get around the problems you might face.

Hope this helps!

Pino
0
 
LVL 10

Expert Comment

by:caraf_g
ID: 2534237
Some extracts from above URL, this might be enough to get you going (save 10 points <G>)

Option Explicit
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent 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 Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Const GWL_STYLE = (-16)
Private Const WS_CHILD = &H40000000

Private Sub Command1_Click()
Dim m_oldstyle As Long
    Load Form2
    SetParent Form2.hwnd, Me.hwnd
    m_oldstyle = GetWindowLong(Form2.hwnd, GWL_STYLE)
    Call SetWindowLong(Form2.hwnd, GWL_STYLE, (m_oldstyle Or WS_CHILD))
    Form2.Show vbModeless
    Form2.Move 0, 0
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Unload Form2
End Sub



0
 
LVL 10

Expert Comment

by:caraf_g
ID: 2534251
- to stop irritating "jumping" behaviour, use WS_POPUP:

Option Explicit
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent 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 Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Const GWL_STYLE = (-16)

Private Const WS_POPUP = &H80000000

'The following constants are no longer used, but I'll leave them here for reference _
 purposes
Private Const GWL_EXSTYLE = (-20)
Private Const WS_EX_NOPARENTNOTIFY = &H4&
Private Const GWL_HWNDPARENT = (-8)


Private Const WS_MAXIMIZEBOX = &H10000 'Enables/Disables maximise button
Private Const WS_MINIMIZEBOX = &H20000 'Enables/Disables minimise button
'If both are switched "off", both minimise and maximise buttons disappear.

Private Const WS_THICKFRAME = &H40000
'Enables/Disabled sizing

Private Const WS_SYSMENU = &H80000
'Shows/Removes control box

Private Const WS_HSCROLL = &H100000
'Shows a horizontal scroll bar

Private Const WS_VSCROLL = &H200000
'shows a vertical scroll bar

 Private Const WS_BORDER = &H800000
Private Const WS_CAPTION = &HC00000
'Both constants seem to be based on the value &H800000. It's not clear how they work. _
 when either &H400000 or &H800000 are removed, the form's caption disappears when _
 resizing.

Private Const WS_VISIBLE = &H10000000
Private Sub Command1_Click()

Dim m_oldstyle As Long
Load Form2
SetParent Form2.hwnd, Me.hwnd
m_oldstyle = GetWindowLong(Form2.hwnd, GWL_STYLE)
Call SetWindowLong(Form2.hwnd, GWL_STYLE, (m_oldstyle Or WS_POPUP))
Form2.Show

End Sub
Private Sub Form_Unload(Cancel As Integer)

Unload Form2

End Sub



0
 
LVL 1

Expert Comment

by:rammeri
ID: 2534253
Anyway ... I really wanted to do this in one of my apps - but it doesn't work 100% like a VB MDI-Child.

i.e. it seemed to me that the Menus of the MDIParent-Form aren't accessible
0
 
LVL 10

Expert Comment

by:caraf_g
ID: 2534254
Another observation by ameba:

' Here is code for child form - when focus goes to child form, main form title bar will change color to 'inactive' without this
' credits: vbpj
' Form2 code
Option Explicit
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_NCACTIVATE = &H86

Private Sub Form_Activate()
    Call SendMessage(Form1.hWnd, WM_NCACTIVATE, 1, ByVal 0&)
End Sub

(Thanks)

0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 1

Expert Comment

by:rammeri
ID: 2534255
to refine my comment ... they aren't accessible using ALT+<accelerator>
0
 
LVL 10

Expert Comment

by:caraf_g
ID: 2534258
"i.e. it seemed to me that the Menus of the MDIParent-Form aren't accessible"

Exactly. That's the problem with this. But if you're not too worried about the menus, it could be acceptable.

Please ensure that you SetParent back to 0 for all "captured" windows from other applications **before** you end the program. Otherwise you'll cause all sorts of nasty crashes and things...
0
 
LVL 1

Expert Comment

by:rammeri
ID: 2534287
caraf_g

after all ... it would seem more "vb-ically correct" to create activeX-controls to achieve the original intend (seperating parts of the app, even parts of the gui).

(the rest is just theory .. not tried ;))

If you'd integrate a WANTEDHEIGHT, WANTEDWITH and WANTEDCAPTION property in the activeX controls you would just add ONE MDI-Child-Form to your apps (say we call it "frmShow".

the code (of frmShow) should be more or less like the following:

dim mControlclass as string

public property get ControlClass() as string
   controlclass = mControlclass
end property

Sub ShowAs(byval Controlclass as string)
   ' controlclass should be the progid i think ("project1.control1")
   mcontrolclass = controlclass
   dim mCtl as object
   set mctl = me.controls.add(controlclass)
   mctl.left = 0
   mctl.top = 0
   me.width = ctl.wantedwidth
   me.height = ctl.wantedheight
   me.caption = ctl.wantedcaption
end sub

You should then be able to add  functions (in a module) like the following.

public function ShowANewForm(byval Controlclass as string) as object
   dim myF as frmShow
   set myf = new frmshow
   myf.showas (controlclass)
   set showaform = myF
end function

public function ShowExistingFormOrCreate(byval Controlclass as string) as object
on error resume next
    dim myF as object
    set myf = getloadedformoftype(controlclass)
    if err.number = vbobjecterror + 1500 then
           set myF = showAform(controlclass)
   end if
   set showExisitingFormOrCreate = myF
end function


public function getLoadedFormOfType(byval Controlclass as string) as object
   on error resume next
   dim myF as object
   dim Found as object
   for each myF in forms
      if myf.controlclass = controlclass then
          set found = myf
      end if
   next
   if found is nothing then
         err.raise vbobjecterr + 1500,, "There was no Form of Type [" & controlclass & "] loaded".
   end if
   set getLoadedFormOfType = found
end function



btw. ... I didn't try the code ... but I think it could work like this ...
0
 
LVL 15

Expert Comment

by:ameba
ID: 2534288
0
 
LVL 27

Expert Comment

by:Ark
ID: 2534289
Hi
If you know hWnd of child window (if you not, you can use FindWindow API for this), you can use

Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long. But for complete MDI solution (negotiate menus and other) you have to do much much more. For complete solution take a look at
http://www.codearchive.com/vbasic//kidnap.zip

Cheers
0
 
LVL 27

Expert Comment

by:Ark
ID: 2537474
Hi domenico
Here is the easy way (without  subclassing)
Option Explicit

Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
End Type
Private Const GW_HWNDNEXT = 2

Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Long, ByVal lpWindowName As Long) As Long
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long
Private Declare Function MoveWindow Lib "user32" (ByVal hwnd As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Const GWL_STYLE = (-16)
Const GWL_EXSTYLE = (-20)
Const GW_CHILD = 5
Const WS_CHILD = &H40000000
Const WS_CLIPSIBLINGS = &H4000000
Const WS_CLIPCHILDREN = &H2000000
Const WS_EX_MDICHILD = &H40&
Const WS_EX_WINDOWEDGE = &H100&
Const WM_MDISETMENU = &H230
Const WM_MDIREFRESHMENU = &H234
Private old_parent As Long
Private ChildhWnd As Long

Private Sub StartCalc_Click()
  Dim child_menu As Long
  Dim old_ParentMenu As Long
  Dim pid As Long
  Dim rc As RECT
  Dim MDIClienthwnd As Long
  pid = Shell("calc.exe", vbNormalFocus)
  ChildhWnd = InstanceToWnd(pid)
  MDIClienthwnd = GetWindow(Me.hwnd, GW_CHILD)
  old_parent = SetParent(ChildhWnd, MDIClienthwnd)
  Call SetWindowLong(ChildhWnd, GWL_STYLE, WS_CHILD Or WS_CLIPSIBLINGS Or WS_CLIPCHILDREN)
  Call SetWindowLong(ChildhWnd, GWL_EXSTYLE, WS_EX_MDICHILD Or WS_EX_WINDOWEDGE)
  GetWindowRect ChildhWnd, rc
  MoveWindow ChildhWnd, 0&, 0&, rc.Right - rc.Left, rc.Bottom - rc.Top, -1&
  MoveWindow MDIClienthwnd, 0&, 0&, rc.Right - rc.Left, rc.Bottom - rc.Top, -1&
  Me.SetFocus
End Sub
Private Function InstanceToWnd(ByVal target_pid As Long) As Long
  Dim test_hwnd As Long
  Dim test_pid As Long
  Dim test_thread_id As Long
  test_hwnd = FindWindow(ByVal 0&, ByVal 0&)
  Do While test_hwnd <> 0
   If GetParent(test_hwnd) = 0 Then
      test_thread_id = GetWindowThreadProcessId(test_hwnd, test_pid)
      If test_pid = target_pid Then
         InstanceToWnd = test_hwnd
         Exit Do
      End If
   End If
   test_hwnd = GetWindow(test_hwnd, GW_HWNDNEXT)
  Loop
End Function

Make project with MDI form. Add menu item "StartCalc".
But this code don't support many MDI functions. You need to use subclassing to include this functions (Menu,Min/Max e.t.c.)

Cheers
0
 

Accepted Solution

by:
ptjii earned 200 total points
ID: 2546841
Very very easy if you are willing to spend a 69$. Go to http://www.devcomponents.com/
and download MDIExtender I believe this
will solve your problems completely.
0
 
LVL 10

Expert Comment

by:caraf_g
ID: 2546931
Nope. It claims to allow you to create ActiveX DLLs containing MDI Child forms, that's all.
0
 

Expert Comment

by:ptjii
ID: 2547027
That is exactly what domenico wants.
He wants to create a modular app
using MDI interface using
many separate VB projects.

Of course MDIExtender can not use
exe but you can use ActiveX DLL.
I can not perceive the difference in functionality if its concerning
UI creation between EXE and DLL.
If we talk about threading or
stability then there is a difference.

An ActiveX DLL will be more approriate
for User Interface creation.Also
it will be much faster. Domenico
says, "without data swapping"
Thats a characteristic of a DLL
the data/memory is shared.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

There are many ways to remove duplicate entries in an SQL or Access database. Most make you temporarily insert an ID field, make a temp table and copy data back and forth, and/or are slow. Here is an easy way in VB6 using ADO to remove duplicate row…
Introduction In a recent article (http://www.experts-exchange.com/A_7811-A-Better-Concatenate-Function.html) for the Excel community, I showed an improved version of the Excel Concatenate() function.  While writing that article I realized that no o…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

706 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