|
Hey its working, thanks Erxin.
|
|
|
|
|
WoW, that's create!
|
|
|
|
|
Hi,
Do you think you can post the source for how you were able to get the Unity 3D game file to be embedded in WPF? I'm using Unity 5.0 and Unity launches in it's separate window. I copied the unity file into the bin Debug project folder, but not sure whats wrong. I thought it would be as easy as changing this line to the unity file:
appControl.ExeName = "unityNetwork.exe";
|
|
|
|
|
Keep unityNetwork.exe and the folder (unityNetwork_data) generated on compilation, in WINDOWS folder.
|
|
|
|
|
Hi, do you have another solution?
I tried to put myUnityGame.exe in the Debug folder and in the c:Windows folder but it didn't work.
|
|
|
|
|
I replaced "notepad.exe" with the full path to my Unity executable and it worked fine.
|
|
|
|
|
First great job! Thanks a lot..
I have a grid and I try to place 4 notepads, each in its own place.
All of them are placed on the top left corner of the main application.
Any idea?
Thanks,
Eibi
modified 18-Dec-14 9:47am.
|
|
|
|
|
Sorry for the late response due to busy working in these monthes. Here is one of the way to locate the control with X, Y coordinates.
I have found some code snippet about how to get screen point wish this helpful.
Code Snippet
// Get absolute location on screen of upper left corner of button
Point locationFromScreen = this.button1.PointToScreen(new Point(0, 0));
// Transform screen point to WPF device independent point
PresentationSource source = PresentationSource.FromVisual(this);
System.Windows.Point targetPoints = source.CompositionTarget.TransformFromDevice.Transform(locationFromScreen);
// Set coordinates
Window wpfWindow = new Window2();
wpfWindow.Top = targetPoints.Y;
wpfWindow.Left = targetPoints.X;
wpfWindow.Show();
The original link is http://social.msdn.microsoft.com/Forums/vstudio/it-IT/281a8cdd-69a9-4a4a-9fc3-c039119af8ed/absolute-screen-coordinates-of-wpf-user-control?forum=wpf[^]
Thank you.
Erxin
|
|
|
|
|
Sorry for the late response due to busy working in these monthes. Here is one of the way to locate the control with X, Y coordinates.
You could find the method from my previous replay at Quote: Re: Multiple Instances in ToolWindow Pin member Erxin 4-Jun-14 8:12
Thank you.
Erxin
|
|
|
|
|
|
Let me start out by saying this is a fantastic code.
I was able to integrate into my own WPF application. I had to play some funny tricks so it wouldn't close the main application window, but close the sub windows instead.
The issue that I am running into is that if I have an instance of Microsoft excel open on the desktop and I try to open a completely different excel workbook in your hosting control, the new file opens in the current app instead of creating a new window (Process).
Any Ideas?
|
|
|
|
|
First, thank you for your feedback. Let me guess, you have host excel into the control and open another workbook then the workbook displayed into wrong excel process? I think you should get the reference of the aim excel application first and add the specify workbook into the excel application. Then the workbook will be displayed in the right window.
Wish this helpful to you.
|
|
|
|
|
I was trying to do that with excel, but also with other applications like word and such. I was able to find a work around by modifying your code. The second issue that I ran into was when I closed the child window or hosted application, it would prompt the window closing event for the main window. I got around this by forcing a boolean that is only switched when the user closes the main window.
The main window hosts a document previewer which will "host" the application hosting that you created. The hosted application will maintain the size of content presenter that was used in the document previewer.
Declared Global Variables
Public DVHostedApplicationControl As New HostedApplicationViewer
Public CloseApplication As Boolean = False
Closing event on main Window.
Private Sub Window_Closing(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
If CloseApplication = False Then
e.Cancel = True
DVHostedApplicationControl.Dispose()
Else
...
End If
End Sub
Code for loading different files and applications
This code is used in a user control that is a document previewer of the file.
The user can select to edit the file which prompts the application to load in the sub window controller you created.
Private Sub Load_Application()
Me.DocumentViewer1 = Nothing
DVHostedApplicationControl = New HostedApplicationViewer(True)
DVHostedApplicationControl.FileName = _FilePath
If _FilePath.ToLower Like "*.doc*" Then
DVHostedApplicationControl.ExeName = "Word.exe"
ElseIf _FilePath.ToLower Like "*.xls*" Then
DVHostedApplicationControl.ExeName = "Excel.exe"
End If
HostController.Content = DVHostedApplicationControl
End Sub
Your Modified Code.
I added a file path instead of just the application so that it will load the a file into hosted application. When the hosted Window (application) closes (Disposes), it will also prompt the previewer to show a revised preview.
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Runtime.InteropServices
Imports System.Diagnostics
Imports System.Windows.Interop
Imports System.IO
Imports System.Threading
Public Class HostedApplicationViewer
Inherits UserControl
Implements IDisposable
<System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)> _
Public Structure HWND__
Public unused As Integer
End Structure
Public Sub New(Optional ByVal FromViewer As Boolean = False)
InitializeComponent()
AddHandler Me.SizeChanged, AddressOf OnSizeChanged
AddHandler Me.Loaded, AddressOf OnVisibleChanged
AddHandler Me.SizeChanged, AddressOf OnResize
_FromViewer = FromViewer
End Sub
Protected Overrides Sub Finalize()
Try
Me.Dispose()
Finally
MyBase.Finalize()
End Try
End Sub
Private Sub OnChangedInMainThread()
Dim D As DocViewer = Find_UserControl(Me._Parent)
If D IsNot Nothing Then
D.Load_File(Me.FileName, True)
Else
End If
End Sub
Private _iscreated As Boolean = False
Private _FromViewer As Boolean = False
Private _isdisposed As Boolean = False
Private _appWin As IntPtr
Private _childp As Process
Private _Parent As ContentPresenter
Private m_exeName As String = ""
Public Property ExeName() As String
Get
Return m_exeName
End Get
Set(value As String)
m_exeName = value.ToUpper
End Set
End Property
Private m_FileName As String = ""
Public Property FileName() As String
Get
Return m_FileName
End Get
Set(value As String)
m_FileName = value
End Set
End Property
<DllImport("user32.dll", EntryPoint:="GetWindowThreadProcessId", SetLastError:=True, CharSet:=CharSet.Unicode, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function GetWindowThreadProcessId(hWnd As Long, lpdwProcessId As Long) As Long
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function FindWindow(lpClassName As String, lpWindowName As String) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function SetParent(hWndChild As IntPtr, hWndNewParent As IntPtr) As Long
End Function
<DllImport("user32.dll", EntryPoint:="GetWindowLongA", SetLastError:=True)> _
Private Shared Function GetWindowLong(hwnd As IntPtr, nIndex As Integer) As Long
End Function
<DllImport("user32.dll", EntryPoint:="SetWindowLongA", SetLastError:=True)> _
Public Shared Function SetWindowLongA(<System.Runtime.InteropServices.InAttribute()> hWnd As System.IntPtr, nIndex As Integer, dwNewLong As Integer) As Integer
End Function
<DllImport("user32.dll", EntryPoint:="GetWindowLongA", SetLastError:=True)> _
Public Shared Function GetWindowLongA(<System.Runtime.InteropServices.InAttribute()> hWnd As System.IntPtr, nIndex As Integer) As Integer
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function SetWindowPos(hwnd As IntPtr, hWndInsertAfter As Long, x As Long, y As Long, cx As Long, cy As Long, wFlags As Long) As Long
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function MoveWindow(hwnd As IntPtr, x As Integer, y As Integer, cx As Integer, cy As Integer, repaint As Boolean) As Boolean
End Function
Private Const SWP_ASYNCWINDOWPOS As Integer = &H4000
Private Const SWP_FRAMECHANGED As Integer = &H20
Private Const SWP_NOACTIVATE As Integer = &H10
Private Const SWP_NOMOVE As Integer = &H2
Private Const SWP_NOOWNERZORDER As Integer = &H200
Private Const SWP_NOREDRAW As Integer = &H8
Private Const SWP_NOSIZE As Integer = &H1
Private Const SWP_NOZORDER As Integer = &H4
Private Const SWP_SHOWWINDOW As Integer = &H40
Private Const GWL_STYLE As Integer = (-16)
Private Const WS_EX_MDICHILD As Integer = &H40L
Private Const WS_CHILD As Integer = &H40000000
Private Const WS_VISIBLE As Integer = &H10000000L
Protected Sub OnSizeChanged(s As Object, e As SizeChangedEventArgs)
Me.InvalidateVisual()
End Sub
Protected Sub OnVisibleChanged(s As Object, e As RoutedEventArgs)
If _iscreated = False Then
_iscreated = True
_appWin = IntPtr.Zero
Try
Dim procInfo As New System.Diagnostics.ProcessStartInfo()
procInfo.FileName = m_exeName
procInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(Me.m_exeName)
procInfo.WindowStyle = ProcessWindowStyle.Hidden
procInfo.UseShellExecute = False
procInfo.CreateNoWindow = False
If Not m_FileName = "" Then
procInfo.Arguments = (Convert.ToString("""") & Me.m_FileName.ToString) + """"
Dim Str As String = Right(m_FileName, Len(m_FileName) - InStrRev(m_FileName, "."))
Dim fp As String = GetAssociatedProgram(Str)
procInfo.FileName = fp
procInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(fp)
End If
Try
_childp = New Process
_childp = Process.Start(procInfo)
_childp.WaitForInputIdle()
_appWin = _childp.MainWindowHandle
Me._Parent = TryCast(Me.VisualParent, ContentPresenter)
Dim helper = New WindowInteropHelper(Window.GetWindow(Me))
SetParent(_appWin, helper.Handle)
SetWindowLongA(_appWin, GWL_STYLE, WS_VISIBLE)
Catch
End Try
Catch ex As Exception
Debug.Print(ex.Message + "Error")
End Try
MoveWindow(_appWin, GetPosition(_Parent).X, GetPosition(_Parent).Y, CInt(Me.ActualWidth), CInt(Me.ActualHeight), True)
End If
End Sub
Protected Sub OnResize(s As Object, e As SizeChangedEventArgs)
If Me._appWin <> IntPtr.Zero Then
MoveWindow(_appWin, GetPosition(_Parent).X, GetPosition(_Parent).Y, CInt(Me.ActualWidth), CInt(Me.ActualHeight), True)
End If
End Sub
Protected Overridable Sub Dispose(disposing As Boolean)
If Not _isdisposed Then
If disposing Then
If _iscreated AndAlso _appWin <> IntPtr.Zero AndAlso Not _childp.HasExited Then
If _FromViewer Then
Try
Dim d As Windows.Threading.Dispatcher = Nothing
d = Application.Current.Dispatcher
If d.CheckAccess() Then
OnChangedInMainThread()
Else
d.BeginInvoke(DirectCast(AddressOf OnChangedInMainThread, Action))
End If
Catch
End Try
End If
_childp.Kill()
_childp.CloseMainWindow()
_childp.Close()
_appWin = IntPtr.Zero
If _childp IsNot Nothing Then
Dim F As New FileInfo(m_FileName)
For Each Proc As Process In Process.GetProcessesByName(Left(m_exeName, Len(m_exeName) - 4))
If SimilarText(50, Proc.MainWindowTitle, F.Name) And Not Proc.MainWindowTitle = "" And Not m_FileName = "" Then
Proc.Kill()
End If
Next
End If
End If
End If
_isdisposed = True
End If
End Sub
Public Sub Dispose() Implements System.IDisposable.Dispose
Me.Dispose(True)
GC.SuppressFinalize(Me)
Return
End Sub
End Class
There is still some strangeness with hosting the application. It seems to become an issue when I resize the main window or user control "hosting" the application. At the moment, it is not enough of a concern for me to work on.
Thanks again for your feedback and great code.
|
|
|
|
|
If i have another WPF Application i replace the notepad.exe to the WPF Application.exe filename even with Thread.Sleep(1000); it couldn't work it will pop up as another window. Do you know any way to solve this?
|
|
|
|
|
Sorry I haven't try to host another WPF app with this control. It is design for hosting legacy application. Why don't you try to merge two WPF applications from source code level? By the way, I have successfully used this control to host a python builted executable into a WPF application.
Thank you for your feedback.
|
|
|
|
|
Yeah i notice that part of the codes, anyway due to the nature of application controls, i could not dictate how the other WPF application could integrate with me also it was due to some requirement change that the other WPF Application needs to be embedded into the WPF Application I'm working on.
Hoping you could point a way i could wrap this WPF application up and embed it to mine WPF application.
|
|
|
|
|
You could use content presenter in the container wpf application to display the other wpf application in the GUI. If you use MVVM pattern, the embedded application will be wrapper as a single model for the content presenter control.
|
|
|
|
|
This works beautifully! Good job!
|
|
|
|
|
Thank you! Glad to see you like it.
|
|
|
|
|
ArgumentNullException: Value cannot be null.
Parameter name: window
at System.Windows.Interop.WindowInteropHelper..ctor(Window window)
at WpfAppControl.AppControl.OnVisibleChanged(Object s, RoutedEventArgs e)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
at System.Windows.BroadcastEventHelper.BroadcastEvent(DependencyObject root, RoutedEvent routedEvent)
at System.Windows.BroadcastEventHelper.BroadcastLoadedEvent(Object root)
at MS.Internal.LoadedOrUnloadedOperation.DoWork()
at System.Windows.Media.MediaContext.FireLoadedPendingCallbacks()
at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
I down.oad the example, i can run, but have this error,on designer screen so i cant open mainwindow.xaml
I runing visual studio 2013 and Windows 8.1
|
|
|
|
|
|
Hy Erxin,
great work and good help.
Maybe i dont undertsand something but don't go with inside other exe vb6?
I insert other old exe (for example hp help, diagnostic driver of pc, ecc) and all go but when i make for example a simple exe ("hello world") with vb6 don't go, because open a pop up (the same of last discussion with paint - i make sleep(10000))
So, i hope you help because for me is important
Thanks and best regards,
Andrea
|
|
|
|
|
|
Hi, using your method i can add an external application to my WPF project.
but for some reason, when the hosted exe app gets loaded, all the buttons in the loaded app are disabled.
i can see them change when i hover above them with the mouse, but i can't click them...
i tried to set the FocusManager.IsFocusScope of the WPF hosting element to "True", but it did nothing.
this does'nt happen in all applications... i'm trying to load a QT based application, maybe it has something to do with that ? any ideas as to why this can happen ?
Thanks
|
|
|
|
|
Hi. Sorry for the late response. I have a really busy working period during the previous month.
I haven't use it with a QT based application before, but it do work with WX based application. You could try to host your QT based application in a test application, just a simple WPF window, then check if it is works correctly. If it's not, you could use SPY++ to detect if there is a window handler for the QT application in side the WPF application.
You could also adjust the z-index of the WPF control, here is a link about how to change the z-index in WPF.
http://stackoverflow.com/questions/630006/bring-element-forward-z-index-in-silverlight-wpf[^]
Wish this helpful
Erxin.
|
|
|
|
|