Dim pinfo As New ProcessStartInfo("cmd")
Dim p As Process = System.Diagnostics.Process.Start(pinfo)
MsgBox(p.MainWindowHandle)
Nothing to crazy right. Well if I just run it I get 0 for the MainWindowHandle, however if I step through it I actually get a value. What's the deal? Running .NET 2005.
The shell window is a little different, not sure if it works that way, unless possibly starting on a new thread, because it will be up until you close it... once closed, it has no window handle, process is closed, thus erroring out when trying to display
***EDIT - No, it was just the handle needed to be converted to a string... so it worked for me
Last edited by gigemboy; Feb 8th, 2006 at 07:12 PM.
Tested it on 2005, seems to be some sort of timing issue, if I sleep the thread for a second, it displays, but if you don't sleep it, you get 0...
VB Code:
Dim pinfo As New ProcessStartInfo("cmd")
Dim p As Process = System.Diagnostics.Process.Start(pinfo)
System.Threading.Thread.Sleep(1000)
MsgBox(p.MainWindowHandle.ToString)
Usually you can use the .WaitForInputIdle method in order to wait for the process to startup all the way, then execution goes on once it starts up, however, in this case, since it is a command window, it has no graphical interface, and no message loop, so you can't do that...
Do Until p.WaitForInputIdle()
Application.DoEvents()
Loop
I'm assuming that's how you use it. Works great for user interface programs. So basically this would work for all Window Forms created with .NET right? Creating programs using .NET where would this not work? When using Sub Main() as the starting point?
Basically I'm creating a suite of applications for work, since we have so many little VB apps this is a nice way to group all them, while still letting them be their own projects.
That doesnt make sense, I don't know how that code worked for you, it should throw an error on the .WaitForInputIdle line. It does for me since the cmd window has no graphical interface...
It did. I used notepad. I understand that cmd won't work with this process. Really, if I have a process with no message loop I would just have it run it's course before coming back. I was using cmd as just and example. In the real application, I will be starting VB 6 & .NET applications that I have created. So WaitForInputIdle will work fine.
There's no point using WaitForInputIdle in a loop like that because it waits indefinitely until the process is idle, so it should never return False if the process has a message loop. Accordiong to the help, WaitForInputIdle should return False immediately if the process has no message loop, not throw an exception. It seems that the help may be inaccurate in this case.
Now step 2. How to get it to act like a real MDI child. I have:
Code:
Dim pinfo As New ProcessStartInfo("notepad")
Dim p As Process = System.Diagnostics.Process.Start(pinfo)
p.EnableRaisingEvents = True
AddHandler p.Exited, AddressOf Me.ProcessExited
If p.WaitForInputIdle() = True Then
SetParent(p.MainWindowHandle, Me.Handle)
End If
Which is all fine, but when I maximize the process window goes over the MDI menu. Anyone have any ideas?
Here's some code I just quickly adapted from the API Guide VB6 example to VB 2005. Note that i set the IsMdiContainer property of the form to True in the designer.
VB Code:
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As Integer
Private Declare Function LockWindowUpdate Lib "user32" (ByVal hwndLock As Integer) As Integer
Private Declare Function GetDesktopWindow Lib "user32" () As Integer
Private Declare Function Putfocus Lib "user32" Alias "SetFocus" (ByVal hwnd As IntPtr) As Integer
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim mdiContainer As MdiClient = Nothing
For Each ctl As Control In Me.Controls
If TypeOf ctl Is MdiClient Then
mdiContainer = DirectCast(ctl, MdiClient)
Exit For
End If
Next
'Lock the window update
LockWindowUpdate(GetDesktopWindow)
'Execute notepad.Exe
Dim myProcess As Process = Process.Start("notepad")
For Each ctl As Control In Me.Controls
If TypeOf ctl Is MdiClient Then
mdiContainer = DirectCast(ctl, MdiClient)
Exit For
End If
Next
Why is MdiClient a control on the mdi form? Better yet what is MdiClient
[EDIT]
There are some strange resizing bugs with that. When resizing child windows and the MDI form, sometimes things get messed up, but I think most of this can be worked around.
When you create an MDI interface the parent form doesn't actually host the child forms itself. The grey body you see on the form when you set IsMdiContainer to True is actually an MdiClient control. It is placed on the parent form and then the child forms are placed on it. There is no direct reference to it because you aren't really supposed to use it directly. You can get a reference to it as I did though, then you can set it as the parent window for your external application.
lol I still don't see how that is working for you guys... I get an error every time in 2005, even with just using:
VB Code:
Dim pinfo As New ProcessStartInfo("cmd")
Dim p As Process = System.Diagnostics.Process.Start(pinfo)
p.WaitForInputIdle()
breaks out on the error in the picture I had shown in my above post, in both 2003 and 2005. It had always been this way, as I had tried that ages ago... with the same results.. thats why I can't seem to fathom how that is working...
I guess this seems to work for 2003 no problem.
Please try 2005.
Dim pinfo As New ProcessStartInfo("cmd")
Dim p As Process = System.Diagnostics.Process.Start(pinfo)
If p.Responding = True Then
MessageBox.Show(p.MainWindowTitle.ToString())
End If
hehe yeah, I know that, and had started getting in a good habit of using it (typing in the extra letters), but I had pasted his code to test.. thats where it started hehehe so I blame him
When you create an MDI interface the parent form doesn't actually host the child forms itself. The grey body you see on the form when you set IsMdiContainer to True is actually an MdiClient control. It is placed on the parent form and then the child forms are placed on it. There is no direct reference to it because you aren't really supposed to use it directly. You can get a reference to it as I did though, then you can set it as the parent window for your external application.
I suppose I will have to put some code in the resize because if the MDI form is not maximized, and I minimize the children programs they act right by going down in the left hand corner. But then if I maximize the MDI form, the children programs stay in the actual same screen position instead of moving down. Then I can't do anything with the. It's kind of messed up. I don't see why I should be able to make a true child form from an external program.
What makes the forms in the MDI project "true" mdi children? On the API side I mean. I should be able to duplicate that using some API calls.