|
Great post, thanks everybody.
I added a public property exeParametros and used it in the process start method to send the parameters. It works opening a file with the notepad.
p = System.Diagnostics.Process.Start(this.exeName, exeParametros);
I attach the modified code:
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ExeEmbedder
{
[
ToolboxBitmap(typeof(ApplicationControl), "AppControl.bmp"),
]
public class ApplicationControl : System.Windows.Forms.Panel
{
bool created = false;
IntPtr appWin;
private string exeName = "";
[
Category("Data"),
Description("Name of the executable to launch"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)
]
public string ExeName
{
get
{
return exeName;
}
set
{
exeName = value;
}
}
private string exeParametros = "";
[
Category("Data"),
Description("String para pasar al ejecutable"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)
]
public string ExeParametros
{
get
{
return exeParametros;
}
set
{
exeParametros = value;
}
}
public ApplicationControl()
{
}
[DllImport("user32.dll", EntryPoint="GetWindowThreadProcessId", SetLastError=true,
CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);
[DllImport("user32.dll", SetLastError=true)]
private static extern IntPtr FindWindow (string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError=true)]
private static extern long SetParent (IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", EntryPoint="GetWindowLongA", SetLastError=true)]
private static extern long GetWindowLong (IntPtr hwnd, int nIndex);
[DllImport("user32.dll", EntryPoint="SetWindowLongA", SetLastError=true)]
private static extern long SetWindowLong (IntPtr hwnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError=true)]
private static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);
[DllImport("user32.dll", SetLastError=true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll", EntryPoint="PostMessageA", SetLastError=true)]
private static extern bool PostMessage(IntPtr hwnd, uint Msg, long wParam, long lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWindowVisible(IntPtr hWnd);
private const int SWP_NOOWNERZORDER = 0x200;
private const int SWP_NOREDRAW = 0x8;
private const int SWP_NOZORDER = 0x4;
private const int SWP_SHOWWINDOW = 0x0040;
private const int WS_EX_MDICHILD = 0x40;
private const int SWP_FRAMECHANGED = 0x20;
private const int SWP_NOACTIVATE = 0x10;
private const int SWP_ASYNCWINDOWPOS = 0x4000;
private const int SWP_NOMOVE = 0x2;
private const int SWP_NOSIZE = 0x1;
private const int GWL_STYLE = (-16);
private const int WS_VISIBLE = 0x10000000;
private const int WM_CLOSE = 0x10;
private const int WS_CHILD = 0x40000000;
protected override void OnSizeChanged(EventArgs e)
{
this.Invalidate();
base.OnSizeChanged (e);
}
protected override void OnVisibleChanged(EventArgs e)
{
if (created == false)
{
created = true;
appWin = IntPtr.Zero;
Process p = null;
try
{
p = System.Diagnostics.Process.Start(this.exeName, exeParametros);
while (p.MainWindowHandle == IntPtr.Zero || !IsWindowVisible(p.MainWindowHandle))
{
System.Threading.Thread.Sleep(10);
p.Refresh();
}
p.WaitForInputIdle();
appWin = p.MainWindowHandle;
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "Error");
}
SetParent(appWin, this.Handle);
SetWindowLong(appWin, GWL_STYLE, WS_VISIBLE);
MoveWindow(appWin, 0, 0, this.Width, this.Height, true);
}
base.OnVisibleChanged (e);
}
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);
}
protected override void OnResize(EventArgs e)
{
if (this.appWin != IntPtr.Zero)
{
MoveWindow(appWin, 0, 0, this.Width, this.Height, true);
}
base.OnResize (e);
}
}
}
|
|
|
|
|
Can I get the code for AppControl dll
|
|
|
|
|
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
|
|
|
|
|
Hi Sheikko,
you can try to compile it with visual studio 2003,it will be O.K.
|
|
|
|
|
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
|
|
|
|
|
Yeah id like it to work for 2008
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
iexplore was started but not placed in the panel
p.mainwindowhandle did not work due to:
process performance counter disabled
do you have any ideas ?
i'm running xp sp2
thanks
jan
|
|
|
|
|
again me
it works now during debuggin.
else not
|
|
|
|
|
a "little" delay 500ms during after wait for idle
and the stuff works.
anyway another question:
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
|
|
|
|
|
This control fits the bill for a project I'm working on.
I've got it working fine for VC++ built apps, but I can't get any VB6 apps to play inside the control space. The VB6 exe gets kicked off, but is floating outside of the WinForm holding the AppControl. The control communicates with my VB6 window, (minimizing & shutdown work fine), but the resizing does not.
Has anyone had any luck using it for VB6 built apps or thoughts on what the problem might be?
Thanks in advance!
.. john ...
|
|
|
|
|
same problem with vb apps
running on windows xp sp2
dev environment is #develop
|
|
|
|
|
The problem is that the hWnd returned by the call to System.Diagnostics.Process.Start is the hidden top window that VB creates that own's all windows in the VB App. The class name of this form is ThunderFormRT6Main (where RT = Run Time and 6 the version of VB). This classname is different when run under the IDE debugger, btw.
What the control needs is the hWnd to the main VB form (classname ThunderRT6FormDC), so I ended up walking the window list looking for the window who's owner is the hWnd returned by the Process.Start call and then using that hWnd for the control. It works great.
Here's the routine I wrote to find my main VB form:
private IntPtr FindMainVBForm( IntPtr OwnerWindow )
{
IntPtr pCurWindow = GetWindow(OwnerWindow, GW_HWNDFIRST );
while( pCurWindow != IntPtr.Zero )
{
// Check
if( GetWindow( pCurWindow, GW_OWNER ) == OwnerWindow )
{
break;
}
pCurWindow = GetWindow(pCurWindow, GW_HWNDNEXT );
}
return pCurWindow;
}
Where OwnerWindow is the hWnd of the ThunderRT6FormMain return by Process.Start
Hope this helps...
|
|
|
|
|
yeah ! great all is working fine for me !
Thank's a lot !
Here is how i had proceded :
---------------------- Added property -----------------------------------
private bool isVBExe = false;
[
Category("Data"),
Description("Specify here if the exe is a VB executable"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)
]
public bool IsVBExe
{
get
{
return isVBExe;
}
set
{
isVBExe = value;
}
}
---------------------- /Added property -----------------------------------------
---------------------- Added to ApplicationControl class (declaration)----------
[DllImport("user32.dll", EntryPoint="GetWindow", SetLastError=true)]
private static extern IntPtr GetWindow (IntPtr hwnd , long wCmd);
private const int GW_HWNDFIRST = 0;
private const int GW_HWNDLAST = 1;
private const int GW_HWNDNEXT = 2;
private const int GW_HWNDPREV = 3;
private const int GW_OWNER = 4;
private const int GW_CHILD = 5;
---------------------- /Added to ApplicationControl -----------------------------
---------------------- Added private method -------------------------------------
private IntPtr FindMainVBForm( IntPtr OwnerWindow )
{
IntPtr pCurWindow = GetWindow(OwnerWindow, GW_HWNDFIRST );
while( pCurWindow != IntPtr.Zero )
{
// Check
if( GetWindow( pCurWindow, GW_OWNER ) == OwnerWindow )
{break;}
pCurWindow = GetWindow(pCurWindow, GW_HWNDNEXT );
}
return pCurWindow;
}
--------------------- Modified method activate ----------------------------------
private void activate(){
// Initialize handle value to invalid
appWin = IntPtr.Zero;
// Start the remote application
Process p = null;
try
{
// Start the process
p = System.Diagnostics.Process.Start(this.exeName);
// Wait for process to be created and enter idle condition
p.WaitForInputIdle();
// Get the main handle
appWin = p.MainWindowHandle;
///// HERE IS THE TRICK FOR VB EXECUTABLE
if (this.isVBExe){
appWin = this.FindMainVBForm(appWin);
}
///// HERE IS THE TRICK FOR VB EXECUTABLE
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "Error");
}
// Put it into this form
SetParent(appWin, this.Handle);
// Remove border and whatnot
SetWindowLong(appWin, GWL_STYLE, WS_VISIBLE);
// Move the window to overlay it on this window
MoveWindow(appWin, 0, 0, this.Width, this.Height, true);
}
--------------------- /Modified method activate ----------------------------------
That's all folks !
just specify the property isVBExe to true when you want to use a VB executable !;P
|
|
|
|
|
Does anybody knows how to implement the same in Visual C++?
|
|
|
|
|
me trying to embed console application,
but unable to remove the border and the caption bar,
is there any idea on this?
or is it possible to set embed application as MDi Child form?
thnx a lot
|
|
|
|
|
I am trying to embed an exe into my app, I tried the appcontrol, the iexplore worked fine, but the exe I need embed always run in a seperated window, I traced the code and found the MainWdinowHandler is 0, I think that could explain it. but why it is 0, how could I embed it in my app?
Thanks!
|
|
|
|
|
I will assume that your app does not have a graphical user interface or it is being run remotely. Probably the former. Look under the Process.MainWindowHandle documentation. It will return a 0 under those situations.
|
|
|
|
|
Thanks, its a nice control. It worked for me.
One thing, to get rid of the initial flashing of the external application may be:
1)Executing the external application using ShellExecute with last property as SW_HIDE
2)host grabs the external application
3)Calling ShowWindow with SW_SHOW parameter
|
|
|
|
|
Hi,
I could'n have the demo running properly.... it opens the extern application but outside de AppControl and a few seconds later it raises a message box saying "Couldn't get process information from remote machine".
I will test it under XP, I currently using Windows 2003 Server...
Thanks... this is a very good idea!!
Matías
|
|
|
|
|
I am running XP Pro SP2. I do not have a 2003 Server box I can test it on. Are you running the application remotely? Under a restricted access user account?
|
|
|
|
|
I'm not running remotly but I have a restricted user account. That should be a problem?
|
|
|
|
|
I did not have problems running under a restricted access account on Windows XP Pro. I will assume the issue is something with the OS you are running.
|
|
|
|
|
Looks good... I have tried the same with following apps.
Notepad (notepad starts somewhere and then comes to winform.)
Excel (some exceptions while closing form)
Word (works good)
DevEnv( Failed to load VS.NET inside the form...VS.NET runs seperately)
Sreejumon
www.sreesharp.com
|
|
|
|
|