StrataFrame Forum

Stuck on a programming issue

http://forum.strataframe.net/Topic5111.aspx

By Tim Dol - 12/7/2006

I'm wondering if someone could help me out with a programming problem I'm having. (VB.NET)

I am developing a 'outlook style' menu system which basically has a main menu bar, tool bar, navigation panel on the left side of the form and a mdi container consuming the rest of the form.  When the user clicks on one of the navigation buttons I want to launch the associated program within the mdi container.(I'm not committed to the mdi container, it's just something I was experimenting with and seemed to work okay). I have it working fine with forms within the actual menu assembly but I need to launch external applications, which could be VB6 or VB.NET exe's or .NET DLL's. 

I have experimented with 'Process.Start', which works fine, however it opens up the application in a new window. I really want to run the applications within a panel in the menu application, similar to the outlook inbox etc... I assume it's possible.

I'm open to any suggestions as I am still in the experimental stage. Any help would be appreciated.

Thanks,

Tim Dol

By Trent L. Taylor - 12/7/2006

This is basically what we have done in our medical software.  We still have a fair share of the medical software in a VFP EXE which is automatically launched and then seamlessly brought into the .NET MDI window.  This is just the first step in our case because we also needed the .NET menu to launch programs within the VFP EXE.  But that is for another post.  Here is what you need to do.  First launch the application:

Dim loStart As New System.Diagnostics.ProcessStartInfo("c:\yourapplication.exe")
Dim lnHandle As IntPtr

loStart.WindowStyle = Diagnostics.ProcessWindowStyle.Normal
loStart.WorkingDirectory = lcPath
System.Diagnostics.Process.Start(loStart)

Next you are going to want to obtain the window handle to your launched application

'-- Get the PS Window Handle
lnHandle = System.Diagnostics.Process.GetProcessesByName("yourapplication")(0).MainWindowHandle
'-- Stay here until we can get a handle on the application's main window
Do While lnHandle.ToInt32() = 0
     lnHandle = System.Diagnostics.Process.GetProcessesByName("yourapplication")(0).MainWindowHandle
Loop

After a handle has been obtained, you will then need to force the main window handle of the application into the .NET MDI environment.

'-- Set the parent window to the MDI client
WinAPI.SetParent(lnHandle, _MDI.Handle)

'-- Set the window styles
WinAPI.SetWindowLong(lnHandle.ToInt32(), -16, WinAPI.WS_CLIPCHILDREN Or WinAPI.WS_CLIPSIBLINGS Or WinAPI.WS_MAXIMIZE Or WinAPI.WS_OVERLAPPED Or WinAPI.WS_SYSMENU Or WinAPI.WS_VISIBLE)

'-- Set the window position
WinAPI.SetWindowPos(lnHandle.ToInt32(), 0, 0, 0, _MDI.Width, _MDI.Height, &H20)

The WINAPI reference above is just a shared class I created within the application that calls the Windows API methods.  It would look something like this:



Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices


Public NotInheritable Class WinAPI

Public Shared Const WS_OVERLAPPED As Integer = &H0
Public Shared Const WS_POPUP As Integer = &H80000000
Public Shared Const WS_CHILD As Integer = &H40000000
Public Shared Const WS_MINIMIZE As Integer = &H20000000
Public Shared Const WS_VISIBLE As Integer = &H10000000
Public Shared Const WS_DISABLED As Integer = &H8000000
Public Shared Const WS_CLIPSIBLINGS As Integer = &H4000000
Public Shared Const WS_CLIPCHILDREN As Integer = &H2000000
Public Shared Const WS_MAXIMIZE As Integer = &H1000000
Public Shared Const WS_CAPTION As Integer = &HC00000
Public Shared Const WS_BORDER As Integer = &H800000
Public Shared Const WS_DLGFRAME As Integer = &H400000
Public Shared Const WS_VSCROLL As Integer = &H200000
Public Shared Const WS_HSCROLL As Integer = &H100000
Public Shared Const WS_SYSMENU As Integer = &H80000
Public Shared Const WS_THICKFRAME As Integer = &H40000
Public Shared Const WS_GROUP As Integer = &H20000
Public Shared Const WS_TABSTOP As Integer = &H10000
Public Shared Const WS_EX_LAYERED As Integer = &H80000


<DllImport("user32.dll")> _
Public Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
End Function

<DllImport("user32.dll")> _
Public Shared Function SetWindowLong(ByVal WindowHandle As Integer, ByVal Index As Integer, ByVal Settings As Integer) As Integer
End Function

<DllImport("user32.dll")> _
Public Shared Function SetWindowPos(ByVal hWnd As Integer, ByVal hWndInsertAfter As Integer, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As Integer) As Boolean
End Function

End Class

You may not need the SetWindowLong and the SetWindowPos statements.  The SetParent is the API call that moves the parent window from being it's own main window handle into the .NET MDI.  The reference above to _MDI is an actual MDIClient control that is added to the main form rather than just setting the MDIContainer property.  This way you can change the backcolor of the control etc.  If you are just going to use the MDIContainer property, the you will just use the Handle property of the main form.