Originally Posted by
Daniil
Yes, the forums doesn't allow to attach a zip.
What about to post the code directly here wrapping in [CODE ] tags?
It is a WPF application and I have several files.
It would be easy for you to use the application if I send you the project it self.
Can I email it to you.
Any way I am having the following 7 files below.
App.xaml
<Application x:Class="SampleCDeskAppLauncher.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="CDeskAppLauncher.xaml">
<Application.Resources>
</Application.Resources>
</Application>
App.xaml.cs
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
namespace SampleCDeskAppLauncher
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
BrowserFrame.xaml
<Window x:Class="SampleCDeskAppLauncher.BrowserFrame"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Generic Browser Frame" Height="400" Width="800" Closing="Window_Closing" Loaded="Window_Loaded" Closed="Window_Closed">
<Grid>
</Grid>
</Window>
BrowserFrame.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
namespace SampleCDeskAppLauncher
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class BrowserFrame : Window
{
private static BrowserFrame thisGuy = null;
private static System.Windows.Controls.WebBrowser _wpfWebBrowser = null;
private static System.Windows.Forms.WebBrowser _winfWebBrowser = null;
public static readonly int BROWSER_TYPE_WPF = 0xabcd;
public static readonly int BROWSER_TYPE_WNF = 0xcdef;
private Grid _grid;
private BrowserFrame()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
private void Window_Closed(object sender, EventArgs e)
{
CleanUp();
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
//CleanUp();
}
public static void OpenURL(int browserType, string url) {
if (thisGuy != null) {
thisGuy.Close(); // clean up resources by via Window_Closed.
}
thisGuy = GetInstance();
if (browserType == BROWSER_TYPE_WPF) {
thisGuy.Title = "WPF WebBrowser";
_wpfWebBrowser = new System.Windows.Controls.WebBrowser();
thisGuy.GetNewContentGrid().Children.Add(_wpfWebBrowser);
Console.WriteLine("Opening url on WPF Web Browser.");
WebBrowserHelper.Navigate(_wpfWebBrowser, url);
thisGuy.Show();
} else if (browserType == BROWSER_TYPE_WNF) {
thisGuy.Title = "WinForm WebBrowser";
System.Windows.Forms.Integration.WindowsFormsHost host = new System.Windows.Forms.Integration.WindowsFormsHost();
_winfWebBrowser = new System.Windows.Forms.WebBrowser();
host.Child = _winfWebBrowser;
thisGuy.GetNewContentGrid().Children.Add(host);
Console.WriteLine("Opening url on WinForm Web Browser.");
_winfWebBrowser.Navigate(url);
thisGuy.Show();
}
}
private Grid GetNewContentGrid() {
//_grid = null;
_grid = new Grid();
thisGuy.Content = _grid;
return _grid;
}
public static BrowserFrame GetInstance() {
if (thisGuy == null) {
thisGuy = new BrowserFrame();
Console.WriteLine("Creating new Browser Frame.");
}
return thisGuy;
}
public static void CleanUp() {
if (_wpfWebBrowser != null) {
_wpfWebBrowser.Dispose();
_wpfWebBrowser = null;
Console.WriteLine("WPF browser instance was supposed to have been disposed off.");
}
if (_winfWebBrowser != null) {
_winfWebBrowser.Dispose();
_winfWebBrowser = null;
Console.WriteLine("WinForm browser instance was supposed to have been disposed off.");
}
if (thisGuy != null) {
thisGuy._grid = null; // redundant?
thisGuy = null;
Console.WriteLine("Browser housing frame instance was closed and marked as ready for GC.");
}
}
}
}
CDeskAppLauncher.xaml
<Window x:Class="SampleCDeskAppLauncher.CDeskAppLauncher"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CDesk App Launcher" Height="236" Width="367" Loaded="Window_Loaded" Closed ="Window_Closed" WindowStyle="SingleBorderWindow" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Visibility="Visible">
<Grid Height="196">
<Button Margin="12,55,12,81" Name="launchViaWPFBtn" Click="launchViaWPFBtn_Click">Launch on WPF Web Browser</Button>
<Button Margin="12,0,12,12" Name="launchViaWinFormBtn" Click="launchViaWinFormBtn_Click" Height="60" VerticalAlignment="Bottom">Launch on WinForm Web Browser</Button>
<TextBox Height="30" Margin="12,12,12,0" Name="urlTextBox" VerticalAlignment="Top" TextChanged="urlTextBox_TextChanged" VerticalContentAlignment="Center" Background="White" OpacityMask="BlueViolet" />
</Grid>
</Window>
CDeskAppLauncher.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
namespace SampleCDeskAppLauncher
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class CDeskAppLauncher : Window
{
private const string sampleURL = //"www.google.com";
//"http://dev.sencha.com/deploy/ext-4.0.0/examples/#sample-0";
//"http://dev.sencha.com/deploy/ext-4.0.0/examples/desktop/desktop.html";
"https://examples2.ext.net/#/Combination_Samples/Applications/Word_Wrench/";
public CDeskAppLauncher()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
urlTextBox.Text = sampleURL;
}
private void Window_Closed(object sender, EventArgs e)
{
BrowserFrame.CleanUp();
}
private void launchViaWPFBtn_Click(object sender, RoutedEventArgs e)
{
BrowserFrame.OpenURL(BrowserFrame.BROWSER_TYPE_WPF, urlTextBox.Text);
}
private void launchViaWinFormBtn_Click(object sender, RoutedEventArgs e)
{
BrowserFrame.OpenURL(BrowserFrame.BROWSER_TYPE_WNF, urlTextBox.Text);
}
private void urlTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
}
}
}
WebBrowserHelper.cs
using System;
using System.Runtime.InteropServices;
using System.Windows.Controls;
using System.Windows;
namespace SampleCDeskAppLauncher
{
#region enums
public enum OLECMDID
{
OLECMDID_OPEN = 1,
OLECMDID_NEW = 2,
OLECMDID_SAVE = 3,
OLECMDID_SAVEAS = 4,
OLECMDID_SAVECOPYAS = 5,
OLECMDID_PRINT = 6,
OLECMDID_PRINTPREVIEW = 7,
OLECMDID_PAGESETUP = 8,
OLECMDID_SPELL = 9,
OLECMDID_PROPERTIES = 10,
OLECMDID_CUT = 11,
OLECMDID_COPY = 12,
OLECMDID_PASTE = 13,
OLECMDID_PASTESPECIAL = 14,
OLECMDID_UNDO = 15,
OLECMDID_REDO = 16,
OLECMDID_SELECTALL = 17,
OLECMDID_CLEARSELECTION = 18,
OLECMDID_ZOOM = 19,
OLECMDID_GETZOOMRANGE = 20,
OLECMDID_UPDATECOMMANDS = 21,
OLECMDID_REFRESH = 22,
OLECMDID_STOP = 23,
OLECMDID_HIDETOOLBARS = 24,
OLECMDID_SETPROGRESSMAX = 25,
OLECMDID_SETPROGRESSPOS = 26,
OLECMDID_SETPROGRESSTEXT = 27,
OLECMDID_SETTITLE = 28,
OLECMDID_SETDOWNLOADSTATE = 29,
OLECMDID_STOPDOWNLOAD = 30,
OLECMDID_ONTOOLBARACTIVATED = 31,
OLECMDID_FIND = 32,
OLECMDID_DELETE = 33,
OLECMDID_HTTPEQUIV = 34,
OLECMDID_HTTPEQUIV_DONE = 35,
OLECMDID_ENABLE_INTERACTION = 36,
OLECMDID_ONUNLOAD = 37,
OLECMDID_PROPERTYBAG2 = 38,
OLECMDID_PREREFRESH = 39,
OLECMDID_SHOWSCRIPTERROR = 40,
OLECMDID_SHOWMESSAGE = 41,
OLECMDID_SHOWFIND = 42,
OLECMDID_SHOWPAGESETUP = 43,
OLECMDID_SHOWPRINT = 44,
OLECMDID_CLOSE = 45,
OLECMDID_ALLOWUILESSSAVEAS = 46,
OLECMDID_DONTDOWNLOADCSS = 47,
OLECMDID_UPDATEPAGESTATUS = 48,
OLECMDID_PRINT2 = 49,
OLECMDID_PRINTPREVIEW2 = 50,
OLECMDID_SETPRINTTEMPLATE = 51,
OLECMDID_GETPRINTTEMPLATE = 52,
OLECMDID_PAGEACTIONBLOCKED = 55,
OLECMDID_PAGEACTIONUIQUERY = 56,
OLECMDID_FOCUSVIEWCONTROLS = 57,
OLECMDID_FOCUSVIEWCONTROLSQUERY = 58,
OLECMDID_SHOWPAGEACTIONMENU = 59,
OLECMDID_ADDTRAVELENTRY = 60,
OLECMDID_UPDATETRAVELENTRY = 61,
OLECMDID_UPDATEBACKFORWARDSTATE = 62,
OLECMDID_OPTICAL_ZOOM = 63,
OLECMDID_OPTICAL_GETZOOMRANGE = 64,
OLECMDID_WINDOWSTATECHANGED = 65
}
public enum OLECMDEXECOPT
{
OLECMDEXECOPT_DODEFAULT,
OLECMDEXECOPT_PROMPTUSER,
OLECMDEXECOPT_DONTPROMPTUSER,
OLECMDEXECOPT_SHOWHELP
}
public enum OLECMDF
{
OLECMDF_DEFHIDEONCTXTMENU = 0x20,
OLECMDF_ENABLED = 2,
OLECMDF_INVISIBLE = 0x10,
OLECMDF_LATCHED = 4,
OLECMDF_NINCHED = 8,
OLECMDF_SUPPORTED = 1
}
#endregion
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct OLECMDTEXT
{
public uint cmdtextf;
public uint cwActual;
public uint cwBuf;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public char rgwz;
}
[StructLayout(LayoutKind.Sequential)]
public struct OLECMD
{
public uint cmdID;
public uint cmdf;
}
// Interop definition for IOleCommandTarget.
[ComImport,
Guid("b722bccb-4e68-101b-a2bc-00aa00404770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleCommandTarget
{
//IMPORTANT: The order of the methods is critical here. You
//perform early binding in most cases, so the order of the methods
//here MUST match the order of their vtable layout (which is determined
//by their layout in IDL). The interop calls key off the vtable ordering,
//not the symbolic names. Therefore, if you switched these method declarations
//and tried to call the Exec method on an IOleCommandTarget interface from your
//application, it would translate into a call to the QueryStatus method instead.
void QueryStatus(ref Guid pguidCmdGroup, UInt32 cCmds,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] OLECMD[] prgCmds, ref OLECMDTEXT CmdText);
void Exec(ref Guid pguidCmdGroup, uint nCmdId, uint nCmdExecOpt, ref object pvaIn, ref object pvaOut);
}
#region WebBrowser2
[ComImport, /*SuppressUnmanagedCodeSecurity,*/ TypeLibType(TypeLibTypeFlags.FOleAutomation | TypeLibTypeFlags.FDual | TypeLibTypeFlags.FHidden), Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")]
public interface WebBrowser2
{
[DispId(100)]
void GoBack();
[DispId(0x65)]
void GoForward();
[DispId(0x66)]
void GoHome();
[DispId(0x67)]
void GoSearch();
[DispId(0x68)]
void Navigate([In] string Url, [In] ref object flags, [In] ref object targetFrameName, [In] ref object postData, [In] ref object headers);
[DispId(-550)]
void Refresh();
[DispId(0x69)]
void Refresh2([In] ref object level);
[DispId(0x6a)]
void Stop();
[DispId(200)]
object Application { [return: MarshalAs(UnmanagedType.IDispatch)] get; }
[DispId(0xc9)]
object Parent { [return: MarshalAs(UnmanagedType.IDispatch)] get; }
[DispId(0xca)]
object Container { [return: MarshalAs(UnmanagedType.IDispatch)] get; }
[DispId(0xcb)]
object Document { [return: MarshalAs(UnmanagedType.IDispatch)] get; }
[DispId(0xcc)]
bool TopLevelContainer { get; }
[DispId(0xcd)]
string Type { get; }
[DispId(0xce)]
int Left { get; set; }
[DispId(0xcf)]
int Top { get; set; }
[DispId(0xd0)]
int Width { get; set; }
[DispId(0xd1)]
int Height { get; set; }
[DispId(210)]
string LocationName { get; }
[DispId(0xd3)]
string LocationURL { get; }
[DispId(0xd4)]
bool Busy { get; }
[DispId(300)]
void Quit();
[DispId(0x12d)]
void ClientToWindow(out int pcx, out int pcy);
[DispId(0x12e)]
void PutProperty([In] string property, [In] object vtValue);
[DispId(0x12f)]
object GetProperty([In] string property);
[DispId(0)]
string Name { get; }
[DispId(-515)]
int HWND { get; }
[DispId(400)]
string FullName { get; }
[DispId(0x191)]
string Path { get; }
[DispId(0x192)]
bool Visible { get; set; }
[DispId(0x193)]
bool StatusBar { get; set; }
[DispId(0x194)]
string StatusText { get; set; }
[DispId(0x195)]
int ToolBar { get; set; }
[DispId(0x196)]
bool MenuBar { get; set; }
[DispId(0x197)]
bool FullScreen { get; set; }
[DispId(500)]
void Navigate2([In] ref object URL, [In] ref object flags, [In] ref object targetFrameName, [In] ref object postData, [In] ref object headers);
[DispId(0x1f5)]
OLECMDF QueryStatusWB([In] OLECMDID cmdID);
[DispId(0x1f6)]
void ExecWB([In] OLECMDID cmdID, [In] OLECMDEXECOPT cmdexecopt, ref object pvaIn, IntPtr pvaOut);
[DispId(0x1f7)]
void ShowBrowserBar([In] ref object pvaClsid, [In] ref object pvarShow, [In] ref object pvarSize);
//[DispId(-525)]
//WebBrowserReadyState ReadyState { get; }
[DispId(550)]
bool Offline { get; set; }
[DispId(0x227)]
bool Silent { get; set; }
[DispId(0x228)]
bool RegisterAsBrowser { get; set; }
[DispId(0x229)]
bool RegisterAsDropTarget { get; set; }
[DispId(0x22a)]
bool TheaterMode { get; set; }
[DispId(0x22b)]
bool AddressBar { get; set; }
[DispId(0x22c)]
bool Resizable { get; set; }
}
#endregion
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
internal interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.IUnknown)]
object QueryService(ref Guid guidService, ref Guid riid);
}
/// <summary>
/// This helper class is design to trigger the web browser controls.
/// </summary>
public static class WebBrowserHelper
{
public static Uri URI_ABOUT_BLANK = new Uri("about:blank");
static readonly Guid SID_SWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
public static WebBrowser2 Convert(WebBrowser browser)
{
if (browser.Document == null)
{
browser.Navigate(URI_ABOUT_BLANK);
}
IServiceProvider serviceProvider = (IServiceProvider)browser.Document;
Guid serviceGuid = SID_SWebBrowserApp;
Guid iid = typeof(WebBrowser2).GUID;
if (serviceProvider != null)
{
return (WebBrowser2)serviceProvider.QueryService(ref serviceGuid, ref iid);
}
return null;
}
public static void Zoom(WebBrowser browser, double factor)
{
object pvaIn = ((int)(factor * 100)) as object;
try
{
WebBrowser2 webBrowser2 = Convert(browser);
if (webBrowser2 != null)
{
webBrowser2.ExecWB(OLECMDID.OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER, ref pvaIn, IntPtr.Zero);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
MessageBox.Show(ex.StackTrace);
}
}
public static void Navigate(WebBrowser browser, string url)
{
object flags = 0x04; //navNoReadFromCache
object targetFrameName = 0;
object postData = 0;
object headers = 0;
try
{
WebBrowser2 webBrowser2 = Convert(browser);
if (webBrowser2 != null)
{
webBrowser2.Navigate(url, ref flags, ref targetFrameName, ref postData, ref headers);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
MessageBox.Show(ex.StackTrace);
}
}
}
}
How we test
1. Build & launch the sample application. The entire source is included.
2. Click on button ?Launch on WPF Web Browser?.
3. A browser window will show up and display the web page as the url leads to. As can be seen, we specifically selected ext.net examples to be loaded.(you can test other sites by entering the url here)
4. It may take a minute or two to completely load the page. Once it?s fully loaded, observe the memory usage.
5. Click on the same button again. The existing browser window will be closed down, and hence the Dispose method is invoked. A new browser window will be created and show up to load the same url again.
6. Again, observe the memory usage.
7. Repeat the routine for like up to 10 times or more, it was observed that the memory resource is not dropping down despite disposing resources, instead the memory usage keeps on climbing. It even passes 1GB.
When we test with different web sites as
www.yahoo.com there is still memory leaks but it is very less(even as the percentage when considering the application size).
Our application having ext.net controls too behave the same way as "ext.net examples web site".