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.
|