.NET Webbrowser Control and Dispose() - c#

I know this is a hot discussed topic with many questions and answers but I still do not find the solution for the following problem:
I have a multi-tab application. On every tab is a Webbrowser control.
As the webbrowsers take more an more memory for every new tab and they do not free this memory on tab-close, I decided to make a Webbrowser.Dispose() in the tab close event handler. This helped me concerning the memory leak. all the used RAM is now free after closing.
But this caused a new problem: After the first Dispose() it seems that the session is destroyed for all other Webbrowser objects.
Normally I only login in to the frist webbrowser. If I a add several tabs I am normally logged in automatically. After the first Dispose() this does not work anymore and I have to login on every new Tab.
I tried to keep the old cookies and send them again with the new webbrowser but this did not solve the problem. The seems to be destroyed.

This seems to be a GarbageCollector-Problem. You can try to use the dirty way of System.GC.Collect(), just calling the GarbageCollector to free memory, but this is not a good way to solve the problem.
Of what you told, this seems to be a Pointer-problem.
If you declared the Connection as a global variable, you have to detach the connection from the tab befor you can close/dispose the tab itselve. The event Me.Closing shuld help you to do so.
If the Pointer stays open, the tab as an object is still connected on the Connection and will (not realy shure if/when) not get cleaned by the GC.
If you can clarify your way of duplicating/referencing the connection, I could give a more detailed answer.
EDIT: after a while of research my worries became true - there is a problem with caching under IE (>5 as far as I know). http://social.msdn.microsoft.com/Forums/ie/en-US/88c21427-e765-46e8-833d-6021ef79e0c8/memory-leak-in-ie-webbrowser-control
Suggestions are:
calling GarbageCollector manually
limit MemUsage (can result in application-crashes and also just writes the pages to disk)
about:blanc to override cache-entries
calling C++ methods to override the cache (WinINet - all I have found resulted in some ProtectedMemory-Errors - maybe this C# WebBrowser control: Clearing cache without clearing cookies works)
using C++ and WinINet (I don't know any real .Net implementation and it may also have this memory leak)
using alternatives to IE like gecko (Mozilla) - https://bitbucket.org/geckofx/

All WebBrowser instances share the session on per-process basis. According to EricLaw's answer to a similar question, it appears to be impossible to separate sessions. I'd trust Eric's statement as he worked as IE program manager at Microsoft.
If however you'd still like to try some hacks, you may look at CoInternetGetSession. First, try saving and holding on to the returned reference to IInternetSession. Further, you could look at registering your own URL namespace (RegisterNameSpace) and implementing a pluggable protocol handler which may eventually allow to overrule this restriction.
Of course, it sounds like an overkill and most likely won't help at all. A clean solution might be to redesign the logic to get rid of cookies and pass the state via URLs.
EDITED: Another idea, try to navigate the WebBrowser instance to (say) "about:blank" and wait for DocumentComplete event, before actually disposing of it with Dispose().

Thanks for your answers. Here what I checked out:
Calling GC manually:
Does only help if I use Webbrowser.Dispose() in before.
But this is not a solution because of the session problem.
Limit Mem Usage:
Not a solution. This program should run a whole day with many opening and closing of tabs. If I can not clean the used memory, the memory usage will be too much after some hours..
about:blank:
I called about:blank on Closing the Tab. After DocumentLoaded occurs for this URL I disposed the Webbrowser. Same procedure as calling Dispose directly. Session breaks down.
Other components:
I need to have an IE control in every case because the (proprietary) internet application only supports IE 8 and higher.
"Using c++ and WinInet":
Can I use the C++ Browser in my .net program? I can not switch the whole program to C++. This wouldn't be a solution for me.
In summary:
My application works fine without Dispose but has the problem with the increasing memory usage. If we could find a solution for this (which seems to be impossible) it would be the best solution.
The only thing what would be an acceptable "workaround" for me is to reuse the "closed" webbrowsers. In detail: On every tab close I add the Webbrowser to a List instead of Dispose them. When I need a new tab I take the first out of the list an reuse it and Navigate to the new URL: I tried it out but it seems there is the same problem with the sessions. The sessions in the reused tabs seems to be new again. But I really do not understand why... An suggestions for this, too?
Another workaround would be to force every Webbrowser object to be a single instance. Is this possible?

Related

How do I make the WPF application pinned to the taskbar after the first launch?

I need help. I made a WPF application. Its functionality is that it launches the application when it is launched. But if it is pinned to the taskbar, then a JumpList appears. From which you can also call other applications. I ran into this problem: I do not know how to make the program automatically pinned to the taskbar after the first launch. Please help someone. I read on microsoft's website, but it's not suitable for wpf. Please help with this.
Maybe there is some kind of library? Maybe there is a way with the registry?
Don't ask for support for pinning, here is why.
Microsoft goes in great length to prevent applications altering user preferences. Why? Because otherwise, every application would do it. Giving access to user preferences via API means developers start exploiting it. It means applications fighting for screen space. You install compnay A product and it unpins company B product.
If such API existed, that is malware.
And an API for only the calling executable is not viable, it would mean that somewhere deep in the operating system the function call to do it for any executable exists. And then somebody finds it and calls it directly. Besides, it has been a big trouble for Microsoft to decouple the shell as it is.
Instead, explorer handles it.
Further reading Why is there no programmatic access to the Start menu pin list?.
Some application do manage to pin.
Regardless of what, it is a bad practice.
It is not guaranteed to work, much less in the next Windows update.
One way is to mimic user input. It is hard to consider all cases (what if the taskbar is hidden, what if it is not in the usual place, what if explorer is not running, etc.), but you can imagine setting the pointer position and sending keys.
Another way would be to write directly to the list. You might have found out that the pinned items are at:
%AppData%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar
And they are regular, good old, shortcuts. And you could add your own. And it would not work.
Thus, the answer is "Please don't do it".
For a more detailed explanation, you can try to refer here.

NotifyIcon Context Menu Slows Down

So, I have a [.NET] program that implements a NotifyIcon that persists in the Notification Tray in Windows for the entire time that the program runs. When I first execute the program, and for a small time afterwards, the NotifyIcon and associated ContextMenuStrip work an absolute charm.
However, after some time of the machine being in a lower power state or just idle for a few hours, when trying to access the Context Menu, it can take up to 2 seconds for the object to draw.
Is there some persistence need to define to get the menu to respond faster? Have I enabled an incorrect event that is firing a cleanup of resources?
Edit
It would seem that I have 3 options to see if I can get this to work:
1. Insert a SecureString object into the ContextMenuStrip object; this assumes that by having the SecureString inside the ContextMenuStrip, the whole object will be treated the same and will not be page swapped
2. Create a Timer that touches the ContextMenuStrip on interval in some manner to keep it in memory
3. Alter Process.MinWorkingSet when the app has completed initial launch to try (read: hope) that the ContextMenuStrip object is kept alive and not something else
I really am not a fan of items 2 or 3; 3 especially. I am going to try item 1 and see if it works.
Thanks for the responses so far!
From my testing it would appear that option 1 outlined in the questions edit has done the trick ... for the most part.
As has been stated, and of which I already understood, C# is a managed language; making memory management difficult.
However, by adding a new SecureString() object to one of the ContextMenuStrip menu items' Tag attributes, the menu object will persist in RAM.
There are, sadly, two primary caveats to this approach:
1. If the machines RAM gets hit HARD, the SecureString object is either forcibly discarded or decoupled from the encompassing object and the page fault/swap is performed. I am unsure as to whether it re-couples together again post scenario, but it seems to do ok.
2. If the machine is put to sleep or hibernate, the whole app gets page swapped and the SecureString is most definitely discarded. To aid in these situations, I have a SessionSwitchEventHandler that detects if the machine has been unlocked and creates a new SecureString() object in a menu items' Tag attribute and re-associates the ContextMenuStrip object to the NotifyIcon.ContextMenuStrip
Although it's not the best solution, it does work and is better then creating a timer to touch the menu [shudders] or, worse, playing with the Process.MinWorkerSet [takes a shower at the thought]
Thanks again to those who took part in the question and helped think further to find a solution.

Is Application.Restart bad?

I've got a .Net windows form application where a lot of variables are initialized in the Main_Load event and I have a situation where I want my DB re-queried and all vars set to null and re-initialized (basically the form 100% reloaded from the start), but I wrote my Main-Load in such a way (my fault) that it's not that easy to do...
I know I could get exactly what I want by simply calling Application.Restart and it does the trick beautifully, but I'm not sure if this is good programming practice or considered really bad.
Are there any problems that I'm likely to run into by using Application.Restart in this context?
Not friendly to debug, but there's nothing really wrong with it. It is the exact same as terminating the app and starting it again.
You can avoid it by simply creating a new instance of your main form and closing the old one. That however does require you to prevent the program from exiting. Code is here.
It's not that the method doesn't work; rather, many times programmers forget that they've put something in their code that would stop the application from automatically shutting down, or starting up.
Please follow this Thread
You can also do the job with
System.Diagnostics.Process.Start(Application.ExecutablePath);
Application.Exit();
To directly answer the question in the title, yes restarting an application to re-initialize variables is bad practice.
There are cases where restarting an application is usefull (in example self-update), but restarting to mimic a ReInitialize() method is bad in my opinion.
I had problems with this.
I really needed to restart a large Winforms Application, when a user logs off, to ensure all cached (my) data are purged.
Solved my problem by adding the Application.restart() into the Application Shutdown Event.
This works inside the VS environment and when running the EXE
If you want to find that event select your main project properties and from the Application (Side Tab) select View Application Events at the bottom.
My guess is that this works because it is very late on in the closing process. Hope this helps someone and, more importantly, it continues to work.

WebBrowser Control causes whole application to become unresponsive

I have a C# .NET 3.5 application with an embedded web browser. The browser is designed to point to remote sites (Rather than anything local). Everything works fine, but when the page is slow to respond this causes my entire application to become unresponsive until the page is loaded.
I don't mind the browser being unresponsive while it does its thing, but the application going too is far from ideal.
Is there a good way to prevent this? Would it be beneficial to run the WebBrowser on a seperate thread - that's a bit beyond my skillset right now and I don't think the WebBrowser control really likes multithreading? But I can learn if needs be.
See the answer #2 on this question for a solution on how to run it on a separate thread: BackgroundWorker and WebBrowser Control
You might as well read answer #1 too, it explain the behaviors you are seeing (WebBrowser control blocking UI thead).
As it happens I found that the root cause of this was my application running as administrator. Exactly the same issue was seen when using Internet Explorer - as such, I've simply rewritten the bits that required admin privileges so I'm now no longer seeing the original issue.
this happened only on win7;I use fiddler2 to Monitor HTTP/HTTPs traffic .I find embedded web browser to visit this web:http://ctldl.windowsupdate.com/msdownload/update/v3/static/trustedr/en/disallowedcertstl.cab?50ff94e72ac1a75c;the solution is follow:http://support.microsoft.com/kb/2730040/en (Method 2 or Method 3).you can try it.other u can use .net framework4.0,then u haven't this problem.

How do I stop MS Graph component popping up during Interop?

When using Office Interop in C#, if you insert a chart object into a MS Word document, the Grap application loads up very briefly and then goes away. Is there a way to prevent this from happening? I have tried setting the Visible property of the application instance to false to no effect.
EDIT: The Visible property does take effect when used against Word when interopping, and it does not pop up. I would expect there is a similar way to do this for MS Graph.
This is common behaviour for a lot of component hosted in an executable binary. The host application will startup and then do the job. I don't know if there is a surefire way to prevent that since you have no control over the component nor over the process until the application is started and is responding.
A hack I tried in the past (for something totally unrelated) was starting a process and constantly detecting if its main windows was created. As soon as it was created, I was hiding it. You could do this with the main module of the faulty application and hope it will be fast enough to hide the window before the user notices. Then you instanciate your component; the component will usually recycle an existing process, hopefuly the one with the hidden main window.
I can't garentee you this will work in your situation, but it's worth a try it the issue is that important, or if you don't find a better way of course.

Categories

Resources