I wanna use AxWebBrowser on console application, but it give me following exception:
Exception of type 'System.Windows.Forms.AxHost+InvalidActiveXStateException' was thrown.
anybody please help me on this by any sample code for using AxWebBrowser in console application c# without any exeption ...
Yes, the [STAThread] attribute is required on your Main() method so that COM is initialized properly to make the main thread a Single Threaded Apartment. That's not all though, you will also need to pump a message loop. That's a requirement for an STA. Without one, WebBrowser cannot update its state or run its event handlers, you'll never get the DocumentCompleted event for example. You can get a message loop with Application.Run().
Your console application is now indistinguishable from a Windows Forms application. It is actually easier to get everything right by starting a new project with the Windows Forms application project template, then Project + Properties, Output type = Console Application. Edit the Application.Run() call in Program.cs so it doesn't create a form. It won't make dealing with Application.Run() any easier, consider a Timer to run code.
Add the STAThread attribute to your Main method.
However, you should not be using the "raw" ActiveX control.
Instead, add a reference to System.Windows.Forms.dll and use the WebBrowser class. (Yes, you can do that in a Console app)
Also, automating IE is not ideal. You should consider using the WebCLient class.
My class is as below but in the run time it gives me System.Windows.Forms.AxHost+InvalidActiveXStateException:
public class Browse
{
private static AxWebBrowser wBrowser;
public static Result StartBrowse(string url)
{
var validUri = (url.Contains("http://") ? url : "http://" + url);
wBrowser = new AxWebBrowser();
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(AxWebBrowser));
((ISupportInitialize) (wBrowser)).BeginInit();
wBrowser.OcxState = ((AxHost.State)(resources.GetObject("wBrowser.OcxState")));
wBrowser.NewWindow2 += wBrowser_NewWindow2;
wBrowser.NewWindow3 += wBrowser_NewWindow3;
wBrowser.DocumentComplete += wBrowser_DocumentComplete;
wBrowser.DownloadComplete += wBrowser_DownloadComplete;
if (string.IsNullOrEmpty(html) || validUri != url)
{
object empty = System.Reflection.Missing.Value;
wBrowser.Silent = true;
wBrowser.Navigate(validUri, ref empty, ref empty, ref empty, ref empty);
}
return null;
}
static void wBrowser_DownloadComplete(object sender, EventArgs e)
{
doAlgorithm();
}
static void wBrowser_DocumentComplete(object sender, DWebBrowserEvents2_DocumentCompleteEvent e)
{
doAlgorithm();
}
static void wBrowser_NewWindow3(object sender, DWebBrowserEvents2_NewWindow3Event e)
{
e.cancel = true;
}
static void wBrowser_NewWindow2(object sender, DWebBrowserEvents2_NewWindow2Event e)
{
e.cancel = true;
}
}
First, the thread in which the control is hosted must be in single-threaded apartment, you can either put the STAThread in your Main method, or create a separated Thread like this:
var thread = new Thread(() =>
{
//My code
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join(); //Wait for thread termination
Second, you must start a message loop:
while (true) //Put some exit condition
System.Windows.Forms.Application.DoEvents();
Third the control must be hosted in a visible form. The form must be visible just once, so to avoid "flickering", you can write this code:
var browser = new AxWebBrowser();
var hostForm = new Form();
//Set form 0 size, without any control box / title / icon
hostForm.Width = 0;
hostForm.Height = 0;
hostForm.ShowInTaskbar = false;
hostForm.ControlBox = false;
hostForm.ShowIcon = false;
hostForm.MinimizeBox = false;
hostForm.MaximizeBox = false;
//Add browser control
hostForm.Controls.Add(browser);
//Show and immediately hide
hostForm.Show();
hostForm.Hide();
Finally you might want to disable the "click" sound (How to disable click sound in WebBrowser Control)
The final code:
class Program
{
[STAThread]
static void Main(string[] args)
{
URLSecurityZoneAPI.InternetSetFeatureEnabled(URLSecurityZoneAPI.InternetFeaturelist.DISABLE_NAVIGATION_SOUNDS, URLSecurityZoneAPI.SetFeatureOn.PROCESS, true);
var browser = new AxWebBrowser();
var hostForm = new Form();
hostForm.Width = 0;
hostForm.Height = 0;
hostForm.ShowInTaskbar = false;
hostForm.ControlBox = false;
hostForm.ShowIcon = false;
hostForm.MinimizeBox = false;
hostForm.MaximizeBox = false;
hostForm.Controls.Add(browser);
hostForm.Show();
hostForm.Hide();
browser.DocumentComplete += delegate(object sender, DWebBrowserEvents2_DocumentCompleteEvent e)
{
var doc = (IHTMLDocument3)browser.Document;
Console.WriteLine(doc.documentElement.innerHTML);
};
browser.Navigate("www.google.com");
while (true)
System.Windows.Forms.Application.DoEvents();
}
}
Related
i m trying to suppot an app, that uses cefsharp(v79.1.360).
There are list of things I need to implement:
1) ChromiumWebBrowser in WPF (using CefSharp.Wpf minimum example)
2) This browser can go offscreen(with collapsing window or closing it)
3) Work with JavaScriptObjectRepository, and launch some code, that will be do work with web pages(click buttons, change text of elements). Pages may use frameworks, websockets, Http requests and the other stuff
web pages usually do.
After pages work is done, i send results to C# by calling Methods of object, i bounded in jsObjectRepository/
Expectations:
Offscreen prefomance(time delay) should be as well as With opened window/
Reality:
Offscreen perfomance sometimes is really bad, it take time to do work up to 10 seconds(when wpf is only 1-5).
My code:
Initialization
CefSharpSettings.LegacyJavascriptBindingEnabled = true;
CefSharpSettings.WcfEnabled = true;
CefSettings cefSettings = new CefSettings
{
LocalesDirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "locales"),
Locale = appsettings.CurrentChromeLanguage.ToLocal(),
AcceptLanguageList = appsettings.CurrentChromeLanguage.ToAcceptList(),
};
if (!cefSettings.CefCommandLineArgs.ContainsKey("disable-gpu"))
{
cefSettings.CefCommandLineArgs.Add("disable-gpu", "1");
}
if (cefSettings.CefCommandLineArgs.ContainsKey("enable-system-flash"))
{
cefSettings.CefCommandLineArgs.Remove("enable-system-flash");
}
if (cefSettings.CefCommandLineArgs.ContainsKey("enable-media-stream"))
{
cefSettings.CefCommandLineArgs.Remove("enable-media-stream");
}
cefSettings.CefCommandLineArgs.Add("enable-begin-frame-scheduling", "1");
cefSettings.CefCommandLineArgs.Add("disable-gpu-vsync", "1");
cefSettings.CefCommandLineArgs.Add("mute-audio", "true");
cefSettings.CefCommandLineArgs.Add("enable-media-stream", "0");
cefSettings.CefCommandLineArgs.Add("disable-3d-apis", "1");
cefSettings.CefCommandLineArgs.Add("renderer-process-limit", "10");
cefSettings.CefCommandLineArgs.Add("js-flags", "--lite_mode");
if (!appsettings.IsLoadImage)
{
cefSettings.CefCommandLineArgs.Add("disable-image-loading", "1");
}
cefSettings.LogFile = Path.Combine(ClientConfig.ChromeDataPath, "Log.txt");
cefSettings.LogSeverity = LogSeverity.Error;
cefSettings.IgnoreCertificateErrors = true;
cefSettings.SetOffScreenRenderingBestPerformanceArgs();
Browser creating and usage:
ChromiumWebBrowser browser = new ChromiumWebBrowser();
//xaml window with <ContentControl> with browser
//need hide means when window is closing, we cancel it, and using Hide()
NewBrowserView view = new NewBrowserView(new ChromeTabViewModel(browser));
view.Closing += BrowserView_Closing;
Browser.FrameLoadStart += _browser_FrameLoadStart;
var options = new BindingOptions { CamelCaseJavascriptNames = false };
browser.JavascriptObjectRepository.Register("resultController", this, false, options);
//we can just hide window
void BrowserView_Closing(object sender, CancelEventArgs e)
{
if (_needHide)
{
e.Cancel = true;
Hide();
}
}
//on page load
void _browser_FrameLoadStart(object sender, FrameLoadStartEventArgs e) {
string code = "";
code += "(async function(){ " +
"await CefSharp.BindObjectAsync('resultController'); " +
code += TestJsCode;
code += " })();";//AddWorker
e.Frame.ExecuteJavaScriptAsync(code, $"about:blank/myCode");
Consol.WriteLine(DateTime.Now);
}
public void OnGoodResult()
{
Consol.WriteLine(DateTime.Now);
}
public void OnBadResult()
{
Consol.WriteLine(DateTime.Now);
}
//then i just go by differnet pages and await results
As i mentioned before, when i hide wnd, its taking too long time to print result
I really depended on Layouts and other visuals, so i figured this out. I should just set this code, when window is collapsing:
GetBrowser().GetHost().WasHidden(false);
I have a console application which either invokes a class and runs as a console application or triggers a windows form. The windows form inturn sends parameters and invokes the same operation done otherwise.
Invocation point:
static void Main(string[] args)
{
if(AppSettingsHelper.GetValue<bool>("EnableWindowsForm"))
{
System.Console.WriteLine("EnableWindowsForm is set to true - Running Windows form");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1(0));
//First Time
var form = new ReportGeneratorForm();
Application.Run(form);
}
else
{
System.Console.WriteLine("EnableWindowsForm is set to false - Running direct program in console");
PortalMonitoring monitoring = new PortalMonitoring();
monitoring.Process();
}
}
Now In Click of Button the Same Class is triggered
private void button1_Click(object sender, EventArgs e)
{
PortalMonitoring monitoring = new PortalMonitoring();
monitoring.Process(DateTime.Now); //Date as paramater- Default is null
}
If i trigger the console app, it works well.
However if i click the button the code is stuck at point of async web api call -below code
int reportID = GetReportIDAsync().Result;
private static async System.Threading.Tasks.Task<int> GetReportIDAsync()
{
var reportName = "Portal name";
var reportID = await ops.GetReportId(reportName);
LogAndWriteToConsole("Report ID Feched : " + reportID.ToString());
return reportID;
}
Kindly help me here, i think windows form doesnt seem to allow multi threads by defauly. How to fix this ?
You don't show the complete path from monitoring.Process() to GetReportIDAsync() but it needs to be async/await all the way.
The top level should look like this:
private async void button1_Click(object sender, EventArgs e)
{
// probably add a try/catch here
PortalMonitoring monitoring = new PortalMonitoring();
await monitoring.Process(DateTime.Now); //Date as paramater- Default is null
}
Your no-winforms branch shoud then use monitoring.Process().Wait()
I want to get a console window within my form. Basically when you click button1, it runs a batch script(test.exe). I don't want a separate batch window but instead I want it to show up within my form.
I figure there are probably two ways of doing this, either 1, somehow embedding the console within my form, or 2, set StartInfo.CreateNoWindow = true; when you click button1 and get the output to funnel into a listbox to simulate a console within my form.
I am just a little stuck because I have found methods for doing both but my own testing with the various other methods people have suggested, nothing has worked. But either way, my user needs to be able to send input back to the console.
Which method would be simpler and how would I go about it?
I believe the best way to do this is to redirect output. Basically things will still execute as you want, but you will get the output wherever you want/need.
using System;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;
namespace ConsoleOutput_test
{
public partial class Form1 : Form
{
Process sortProcess;
private static StringBuilder sortOutput = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
sortProcess = new Process();
sortProcess.StartInfo.FileName = "C:\\Windows\\System32\\cmd.exe";
// Set UseShellExecute to false for redirection.
sortProcess.StartInfo.CreateNoWindow = true;
sortProcess.StartInfo.UseShellExecute = false;
// Redirect the standard output of the sort command.
// This stream is read asynchronously using an event handler.
sortProcess.StartInfo.RedirectStandardOutput = true;
sortProcess.StartInfo.RedirectStandardInput = true;
sortProcess.StartInfo.RedirectStandardError = true;
sortOutput = new StringBuilder("");
// Set our event handler to asynchronously read the sort output.
sortProcess.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
sortProcess.ErrorDataReceived += new DataReceivedEventHandler(SortErrorHandler);
// Redirect standard input as well. This stream
// is used synchronously.
sortProcess.StartInfo.RedirectStandardInput = true;
// Start the process.
sortProcess.Start();
// Start the asynchronous read of the sort output stream.
sortProcess.BeginOutputReadLine();
while (!sortProcess.HasExited)
{
Application.DoEvents(); // This keeps your form responsive by processing events
}
}
private void SortOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (txtConsole.InvokeRequired) { txtConsole.BeginInvoke(new DataReceivedEventHandler(SortOutputHandler), new[] { sendingProcess, outLine }); }
else
{
txtConsole.AppendText(Environment.NewLine + outLine.Data);
}
}
private void SortErrorHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (txtConsole.InvokeRequired) { txtConsole.BeginInvoke(new DataReceivedEventHandler(SortErrorHandler), new[] { sendingProcess, outLine }); }
else
{
txtConsole.AppendText(Environment.NewLine + outLine.Data);
}
}
private void button2_Click(object sender, EventArgs e)
{
sortProcess.StandardInput.WriteLine(txtOutput.Text);
txtOutput.Text = "";
}
}
}
I have a Winforms Application with a TabStrip Control. During runtime, UserControls are to be loaded into different tabs dynamically.
I want to present a "User Control xyz is loading" message to the user (setting an existing label to visible and changing its text) before the UserControl is loaded and until the loading is completely finished.
My approaches so far:
Trying to load the User Control in a BackgroundWorker thread. This fails, because I have to access Gui-Controls during the load of the UserControl
Trying to show the message in a BackgroundWorker thread. This obviously fails because the BackgroundWorker thread is not the UI thread ;-)
Show the Message, call DoEvents(), load the UserControl. This leads to different behaviour (flickering, ...) everytime I load a UserControl, and I can not control when and how to set it to invisible again.
To sum it up, I have two questions:
How to ensure the message is visible directly, before loading the User control
How to ensure the message is set to invisible again, just in the moment the UserControl is completely loaded (including all DataBindings, grid formattings, etc.)
what we use is similar to this:
create a new form that has whatever you want to show the user,
implement a static method where you can call this form to be created inside itself, to prevent memory leaks
create a new thread within this form so that form is running in a seperated thread and stays responsive; we use an ajax control that shows a progress bar filling up.
within the method you use to start the thread set its properties to topmost true to ensure it stays on top.
for instance do this in your main form:
loadingForm.ShowLoadingScreen("usercontrollname");
//do something
loadingform.CloseLoadingScreen();
in the loading form class;
public LoadingScreen()
{
InitializeComponent();
}
public static void ShowLoadingScreen(string usercontrollname)
{
// do something with the usercontroll name if desired
if (_LoadingScreenThread == null)
{
_LoadingScreenThread = new Thread(new ThreadStart(DoShowLoadingScreen));
_LoadingScreenThread.IsBackground = true;
_LoadingScreenThread.Start();
}
}
public static void CloseLoadingScreen()
{
if (_ls.InvokeRequired)
{
_ls.Invoke(new MethodInvoker(CloseLoadingScreen));
}
else
{
Application.ExitThread();
_ls.Dispose();
_LoadingScreenThread = null;
}
}
private static void DoShowLoadingScreen()
{
_ls = new LoadingScreen();
_ls.FormBorderStyle = FormBorderStyle.None;
_ls.MinimizeBox = false;
_ls.ControlBox = false;
_ls.MaximizeBox = false;
_ls.TopMost = true;
_ls.StartPosition = FormStartPosition.CenterScreen;
Application.Run(_ls);
}
Try again your second approach:
Trying to show the message in a BackgroundWorker thread. This obviously fails because the BackgroundWorker thread is not the UI thread ;-)
But this time, use the following code in your background thread in order to update your label:
label.Invoke((MethodInvoker) delegate {
label.Text = "User Control xyz is loading";
label.Visible = true;
});
// Load your user control
// ...
label.Invoke((MethodInvoker) delegate {
label.Visible = false;
});
Invoke allows you to update your UI in another thread.
Working from #wterbeek's example, I modified the class for my own purposes:
center it over the loading form
modification of its opacity
sizing it to the parent size
show it as a dialog and block all user interaction
I was required to show a throbber
I received a null error on line:
if (_ls.InvokeRequired)
so I added a _shown condition (if the action completes so fast that the _LoadingScreenThread thread is not even run) to check if the form exists or not.
Also, if the _LoadingScreenThread is not started, Application.Exit will close the main thread.
I thought to post it for it may help someone else. Comments in the code will explain more.
public partial class LoadingScreen : Form {
private static Thread _LoadingScreenThread;
private static LoadingScreen _ls;
//condition required to check if the form has been loaded
private static bool _shown = false;
private static Form _parent;
public LoadingScreen() {
InitializeComponent();
}
//added the parent to the initializer
//CHECKS FOR NULL HAVE NOT BEEN IMPLEMENTED
public static void ShowLoadingScreen(string usercontrollname, Form parent) {
// do something with the usercontroll name if desired
_parent = parent;
if (_LoadingScreenThread == null) {
_LoadingScreenThread = new Thread(new ThreadStart(DoShowLoadingScreen));
_LoadingScreenThread.SetApartmentState(ApartmentState.STA);
_LoadingScreenThread.IsBackground = true;
_LoadingScreenThread.Start();
}
}
public static void CloseLoadingScreen() {
//if the operation is too short, the _ls is not correctly initialized and it throws
//a null error
if (_ls!=null && _ls.InvokeRequired) {
_ls.Invoke(new MethodInvoker(CloseLoadingScreen));
} else {
if (_shown)
{
//if the operation is too short and the thread is not started
//this would close the main thread
_shown = false;
Application.ExitThread();
}
if (_LoadingScreenThread != null)
_LoadingScreenThread.Interrupt();
//this check prevents the appearance of the loader
//or its closing/disposing if shown
//have not found the answer
//if (_ls !=null)
//{
_ls.Close();
_ls.Dispose();
//}
_LoadingScreenThread = null;
}
}
private static void DoShowLoadingScreen() {
_ls = new LoadingScreen();
_ls.FormBorderStyle = FormBorderStyle.None;
_ls.MinimizeBox = false;
_ls.ControlBox = false;
_ls.MaximizeBox = false;
_ls.TopMost = true;
//get the parent size
_ls.Size = _parent.Size;
//get the location of the parent in order to show the form over the
//target form
_ls.Location = _parent.Location;
//in order to use the size and the location specified above
//we need to set the start position to "Manual"
_ls.StartPosition =FormStartPosition.Manual;
//set the opacity
_ls.Opacity = 0.5;
_shown = true;
//Replaced Application.Run with ShowDialog to show as dialog
//Application.Run(_ls);
_ls.ShowDialog();
}
}
I've got a .Net 3.5 C# Winforms app. It's got no GUI as such, just a NotifyIcon with a ContextMenu.
I've tried to set the NotifyIcon to visible=false and dispose of it in the Application_Exit event, as follows:
if (notifyIcon != null)
{
notifyIcon.Visible = false;
notifyIcon.Dispose();
}
The app gets to the code inside the brackets, but throws a null ref exception when it tries to set Visible = false.
I've read in a few places to put it in the form closing event, but that code never gets hit (maybe as I don't have a form showing as such?).
Where can I put this code so it actually works? If I don't put it in, I get the annoying lingering icon in the tray until you move the mouse over it.
Cheers.
EDIT
Just something extra I've noticed...........
I'm using ClickOnce in the app.........if I just exit the app via the ContextMenu on the NotifyIcon, no exception is logged.
Just when the Application_Exit event is fired after the applicaiton has checked for an upgrade here..
private void CheckForUpdate()
{
EventLogger.Instance.LogEvent("Checking for Update");
if (ApplicationDeployment.IsNetworkDeployed && ApplicationDeployment.CurrentDeployment.CheckForUpdate())
{
EventLogger.Instance.LogEvent("Update available - updating");
ApplicationDeployment.CurrentDeployment.Update();
Application.Restart();
}
}
Does this help?
On Windows 7, I had to also set the Icon property to null. Otherwise, the icon remained in the tray's "hidden icons" popup after the application had closed. HTH somebody.
// put this inside the window's class constructor
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);
private void OnApplicationExit(object sender, EventArgs e)
{
try
{
if (trayIcon != null)
{
trayIcon.Visible = false;
trayIcon.Icon = null; // required to make icon disappear
trayIcon.Dispose();
trayIcon = null;
}
}
catch (Exception ex)
{
// handle the error
}
}
This code works for me, but I don't know how you are keeping your application alive, so... without further ado:
using System;
using System.Drawing;
using System.Windows.Forms;
static class Program
{
static System.Threading.Timer test =
new System.Threading.Timer(Ticked, null, 5000, 0);
[STAThread]
static void Main(string[] args)
{
NotifyIcon ni = new NotifyIcon();
ni.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
ni.Visible = true;
Application.Run();
ni.Visible = false;
}
static void Ticked(object o) {
Application.Exit();
}
}
This is what I'm doing in WPF.
I am using this in conjunction to David Anson's Minimize to tray sample app, which lets you hook up a tray icon to a window (you may have multiple windows open).
Just added this code to the constructor for MinimizeToTrayInstance.
_window.Closed += (s, e) =>
{
if (_notifyIcon != null)
{
_notifyIcon.Visible = false;
_notifyIcon.Dispose();
_notifyIcon = null;
}
};
Sometimes Application_Exit event can be raised several times
Just put notifyIcon = null; in the end
if (notifyIcon != null)
{
notifyIcon.Visible = false;
notifyIcon.Dispose();
notifyIcon = null;
}
This code worked for me
this.Closed += (a, b) =>
{
if (notifyIcon1 != null)
{
notifyIcon1.Dispose();
notifyIcon1.Icon = null;
notifyIcon1.Visible = false;
}
};
Have you overridden the dispose method of the object where you've initialised the notifyIcon to also dispose the notifyIcon?
protected override void Dispose(bool disposing)
{
if (disposing)
{
notifyIcon.Dispose();
notifyIcon = null;
}
base.Dispose(disposing);
}
before im sorry for my bad english.
if u use "end" for exit program. then dont close notify icon.
before u will close notifyicon later close form.
u need to use me.close() for run form closing
example
its work...
notifyIcon1.Icon = Nothing
notifyIcon1.Visible = False
notifyIcon1.Dispose()
Me.Close()
but its not work
End
or only
Me.Close()