|

Introduction
Though not a common task, recently I needed to take an existing executable application and embed it into an application I was building. Oddly enough, I did not need any interaction between my application and the existing EXE. As it ends up, this is not a difficult thing to do. To make it even easier, I created a custom C# control that allows you to specify the name of an executable you want embedded into your application. The control takes care of all the rest.
How does it work
In design time, the user can specify the name of the executable to embed. When the control is created in runtime, it launches the application as follows: Process p = null;
try
{
p = System.Diagnostics.Process.Start(this.exeName);
p.WaitForInputIdle();
appWin = p.MainWindowHandle;
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "Error");
}
After launching, the code must then set the parent of the executable's main window to the control handle. It does this as follows:
SetParent(appWin, this.Handle);
SetWindowLong(appWin, GWL_STYLE, WS_VISIBLE);
MoveWindow(appWin, 0, 0, this.Width, this.Height, true);
Any time the control is resized, it must also resize the executable window. To do so, it does this in the Resize function: protected override void OnResize(EventArgs e)
{
if (this.appWin != IntPtr.Zero)
{
MoveWindow(appWin, 0, 0, this.Width, this.Height, true);
}
base.OnResize (e);
}
Lastly, when the control is destroyed, it should shut down the executable. To do so, it does the following: protected override void OnHandleDestroyed(EventArgs e)
{
if (appWin != IntPtr.Zero)
{
PostMessage(appWin, WM_CLOSE, 0, 0);
System.Threading.Thread.Sleep(1000);
appWin = IntPtr.Zero;
}
base.OnHandleDestroyed (e);
}
History
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 47 (Total in Forum: 47) (Refresh) | FirstPrevNext |
|
 |
|
|
Could the control be rewritten so that it doesnt try to run the process from within the Designer and only during runtime?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
you mentiond it is possible to communicate to a method in the application hosted within control. any insight into that, can you shed?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi!
You know it's like you read my mind, Excellent control, Excellent Article, Just When I needed it!
Thanks!
MrWolfy 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
This is exactly what I was looking for.
Is there a way to keep the app in "exename" from starting in design mode? Not a problem, per se, but I only want to start the app at runtime.
Will this work in Vista?
Thanks for your great component. It has made my app much easier to use!
John Byrne 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
 |
|
|
I use this applicacion to host an exe (like notepad) in a form called 'form1'. My problem is that, when I call “form1.hide ();" or "form1.visible=false" , the .exe process contained in this form is destroyed. Method "handledestroyed" for this process is automatically called. However, I dont want to kill it. Only hide.
So, how can I hide the form maintaining the process associated with it?
Regards
putzol
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I've applied this to a figure window in matlab but it appears the the background does not get erased after resize or overlap of another window.
Any ideas? Greg
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Yes somehow, the PAINT messages don't get through the child window, Im trying to put PuTTy windows inside this one and i've to force the repaint, Also the window style does not get update and the caption bar is also draw.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
A call to PInvoke function 'AppControl!AppControl.ApplicationControl::SetWindowLong' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
How does this get a fix?
Steve
|
| Sign In·View Thread·PermaLink | 2.00/5 (2 votes) |
|
|
|
 |
|
|
 |
|
|
 |
|
|
 |
|
|
Hi, Not sure if it's still relevant, but in order to run it under VS2005 and to avoid this error, change the declartion of SetWindowLong to the following:
[DllImport("user32.dll", EntryPoint = "SetWindowLongA", SetLastError = true)] private static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
You would also need to change the call to the function so it will cast the const to IntPtr.
Sagy
|
| Sign In·View Thread·PermaLink | 1.50/5 (2 votes) |
|
|
|
 |
|
|
1.can't start programe that have login window. 2.How sart a progame with command line.
Thanks, Tsewang
caixrz
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hi, thank you for this example. I have tried to lunch it with visual cSgarp, but he doesn't work. He return me an error at this line:
this.Controls.Add(this.applicationControl1);
Can you help me?
I have also tried to insert your code in my application, but he return me n error at this code:
SetWindowLong(appWin, GWL_STYLE, WS_VISIBLE);
thank you
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
I get the same error in Visual studio 2005 is there any way to make it work in 2005. I dont have 2003 and have a large program in 2005 working already. ty
|
| Sign In·View Thread·PermaLink | 1.67/5 (3 votes) |
|
|
|
 |
|
|
 |
|
|
Here's the "translation" of the file "AppControl.cs" in VB.Net :
'********************************************************************** Imports System Imports System.Collections imports System.ComponentModel imports System.Diagnostics imports System.Drawing imports System.Data imports System.Windows.Forms imports System.Runtime.InteropServices
Public Class AppControl Inherits System.Windows.Forms.Panel
Private Shadows created As Boolean = False Private appWin As IntPtr Private sExeName As String = ""
Public Property ExeName() As String Get Return sExeName End Get Set(ByVal value As String) sExeName = value End Set End Property
#Region "External Definition + Constants" <DllImport("user32.dll", EntryPoint:="GetWindowThreadProcessId", SetLastError:=True, CharSet:=CharSet.Unicode, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> Private Shared Function GetWindowThreadProcessId(ByVal hWnd As Long, ByVal lpdwProcessId As Long) As Long End Function <DllImport("user32.dll", SetLastError:=True)> Private Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr End Function <DllImport("user32.dll", SetLastError:=True)> Private Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As Long End Function <DllImport("user32.dll", EntryPoint:="GetWindowLongA", SetLastError:=True)> Private Shared Function GetWindowLong(ByVal hwnd As IntPtr, ByVal nIndex As Integer) As Long End Function <DllImport("user32.dll", EntryPoint:="SetWindowLongA", SetLastError:=True)> Private Shared Function SetWindowLong(ByVal hwnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As IntPtr) As IntPtr End Function <DllImport("user32.dll", SetLastError:=True)> Private Shared Function SetWindowPos(ByVal hwnd As IntPtr, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long End Function <DllImport("user32.dll", SetLastError:=True)> Private Shared Function MoveWindow(ByVal hwnd As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal repaint As Boolean) As Boolean End Function <DllImport("user32.dll", EntryPoint:="PostMessageA", SetLastError:=True)> Private Shared Function PostMessage(ByVal hwnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer End Function
Private Const SWP_NOOWNERZORDER As Integer = 512 Private Const SWP_NOREDRAW As Integer = 8 Private Const SWP_NOZORDER As Integer = 4 Private Const SWP_SHOWWINDOW As Integer = 64 Private Const WS_EX_MDICHILD As Integer = 64 Private Const SWP_FRAMECHANGED As Integer = 32 Private Const SWP_NOACTIVATE As Integer = 16 Private Const SWP_ASYNCWINDOWPOS As Integer = 16384 Private Const SWP_NOMOVE As Integer = 2 Private Const SWP_NOSIZE As Integer = 1 Private Const GWL_STYLE As Integer = (-16) Private Const WS_VISIBLE As Integer = 268435456 Private Const WM_CLOSE As Integer = 16 Private Const WS_CHILD As Integer = 1073741824 #End Region
#Region "Overrides functions" Protected Overrides Sub OnSizeChanged(ByVal e As EventArgs) Me.Invalidate() MyBase.OnSizeChanged(e) End Sub
Protected Overrides Sub OnVisibleChanged(ByVal e As EventArgs) ''// If control needs to be initialized/created If (created = False) Then ''// Mark that control is created created = True
'// Initialize handle value to invalid appWin = IntPtr.Zero
'// Start the remote application Dim p As Process Try '// Start the process p = System.Diagnostics.Process.Start(Me.ExeName)
'// Wait for process to be created and enter idle condition p.WaitForInputIdle()
'// Get the main handle appWin = p.MainWindowHandle Catch ex As Exception MessageBox.Show(Me, ex.Message, "Error") End Try
'// Put it into this form SetParent(appWin, Me.Handle)
'// Remove border and whatnot SetWindowLong(appWin, GWL_STYLE, WS_VISIBLE)
'// Move the window to overlay it on this window MoveWindow(appWin, 0, 0, Me.Width, Me.Height, True) End If
MyBase.OnVisibleChanged(e) End Sub
Protected Overrides Sub OnHandleDestroyed(ByVal e As EventArgs) '// Stop the application If (appWin <> IntPtr.Zero) Then '// Post a close message PostMessage(appWin, WM_CLOSE, 0, 0)
'// Delay for it to get the message System.Threading.Thread.Sleep(1000)
'// Clear internal handle appWin = IntPtr.Zero End If
MyBase.OnHandleDestroyed(e) End Sub
Protected Overrides Sub OnResize(ByVal e As EventArgs) If (Me.appWin <> IntPtr.Zero) Then MoveWindow(appWin, 0, 0, Me.Width, Me.Height, True) End If
MyBase.OnResize(e) End Sub #End Region
End Class '**********************************************************************
Hope that can be help somebody
|
| Sign In·View Thread·PermaLink | 1.75/5 (3 votes) |
|
|
|
 |
|
|
i have now a form with multiple tabs on each tab is a iexplore. now my problem: how can i retrieve the current folder of each single iexplore instance ? cause as soon as i host them , they do not update their maintitle property.
thanx jj
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|