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.
Related
I am working with MS UIAutomation on windows 7 (64bit). I want to know if it is possible to make the UIAutomation element persist, if so what could be the starting point to do it.
The only thing I came up with is RuntimeID of an element, but the problem is that some elements may not have an id.
A simple scenario I want to achieve is that I find out the UIAutomation element of a control on the screen by using the AutomationElement.FromPoint(), now I want to persist it, so that next time I can easily access it by "Loading" it back to a UIAutomation Element.
No, you cannot persist the UIAutomation element from the automation client. You will need to store sufficient information about the element (the AutomationID and context are the best, if available) to find it again the next time.
The element is a reference to the object in (probably) some other process, and it can only live so long as that other process lets it. Elements are likely to go away when their windows close, the app closes, etc. Elements such as menus and flyouts are likely to be very short lived, and may no longer exist by the time the client receives a notification.
In an application I am making, I want to know when a user copies a file or clicks the start button. Those actions would be considered too trivial but they carry some importance in my application.
Yesterday, I received a comment Getting notified of any action taken by user on windows on a similar question so I am hesitating to switch the entire auditing infrastructure.
Going as per explanation of eventtriggers http://technet.microsoft.com/en-us/library/bb490901.aspx
Creates a new event trigger that monitors and acts upon the occurrence
of log events of given criteria.
I am not sure what the limits of eventtriggers and how it can help me achieve my goal without so much overhead. Can eventtriggers help me set a trigger that notifies me when the start button is clicked?.
Not possible, to my knowledge, unless you poll to find out the status. This example was already brought up in a previous question on SO:
How can I detect when the Windows 7 start menu opens
Theoretically you could write something that lives on a different thread that queries the start menu at given intervals. Then, if the start menu was detected as open you could trigger the code you want done. Just a thought...
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?
I wrote a small autohotkey script that removes the border, titlebar, and resize handles of a window, and centers it on the first monitor. This works for most applications and games, but some (bioshock 2, APB, etc) replace their window style instantly after removing it. Is there a way to block window style changes?
I would prefer to keep this in AHK, but the title has c# in it because I would like to convert my application to that down the road, and if it's only possible in c#/c++ then now would be a good time to start conversion.
I could be missing something, but I doubt this is going to be easy. The behavior you describe is one of an application which is either monitoring for changes in its window style, or just constantly redrawing them nonstop to prevent these changes. Of course you could just Loop through and fight against it where you remove, it replaces, you remove, it replaces, but that won't solve anything.
One way you could try is to create a .dll and inject it into the app's process, and then hook some API calls and simply return before anything gets redrawn. Google for 'detours hooking' for some examples. That might work, but would be out of the scope of AHK. And your simple 15 minute AHK script would turn into a much bigger project. =(
I have a windows form application which needs to be the TopMost. I've set my form to be the TopMost and my application works as I'd like it to except for in one case.
There is a 3rd party application (referred to as player.exe) that displays SWF movie files on a portion of the screen that popup on top of my application.
Using Process Monitor I determined that player.exe application calls
flash.exe <PositionX> <PositionY> <Width> <Height> <MovieFile>
in my case:
flash.exe 901 96 379 261 somemovie.swf
Since flash.exe is being spawned in a new process after my form has been set to the TopMost it is appearing on top of my application.
First thing I did was make my application minimize the player.exe main application window hoping that this would prevent the Flash from appearing also. But, unfortunately it doesn't... even with the window minimized whenever the flash movie starts it shows up at the pixel location (901,96). I then tried creating a timer to keep setting the form.TopMost property to true every 10ms. This sort of works but you still see a very quick blip of the swf file.
Is there some type of Windows API call which can be used to temporarily prevent player.exe from spawning child processes which are visible? I admit it sounds a little far fetched. But, curious if anyone else has had a similar problem.
Addendum:
This addendum is to provide a reply to some of the suggestions layed out in Mathew's post below.
For the emergency situation described in the comments, I would look at possible solutions along these lines:
1) How does the third party application normally get started and
stopped? Am I permitted to close it
the same way? If it is a service, the
Service Control Manager can stop it.
If it is a regular application,
sending an escape keystroke (with
SendInput() perhaps) or WM_CLOSE
message to its main window may work.
Easiest way to close the app is to CTRL-ALT-DEL, then kill process. -OR-
The proper way is to Hold ESC while clicking the left mouse button... then input your username and password, navigate some menu's to stop the player.
There is no PAUSE command... believe it or not.
I don't think using WM_CLOSE will help since minimizing the application doesn't. Would that kill the process also? If not, how do you reopen it.
2) If I can't close it nicely, am I permitted to kill it? If so,
TerminateProcess() should work.
I can't kill the process for two reasons. 1) Upon relaunch you need to supply username/password credentials... There may be a way to get around this since it doesn't prompt when the machine is rebooted but... 2) Whenever I kill the process in task manager it doesn't die gracefully and asks if you want to send an error report.
3) If I absolutely have to leave the other process running, I would try
to see if I can programmatically
invoke fast user switching to take me
to a different session (in which there
will be no competing topmost windows).
I don't know where in the API to start
with this one. (Peter Ruderman
suggests SwitchDesktop() for this
purpose in his answer.)
I got really excited by this idea... I found this article on CodeProject which provides a lot of the API Wrapper methods. I stopped implementing it because I think that in order for desktop's to work you must have explorer.exe running (which I do not).
EDIT2: On second thought... maybe explorer.exe isn't needed. I'll give it a try and report back.
Edit3: Was unable to get the code in that article working. Will have to put this on hold for a moment.
Answer Summary
As one might have expected, there is no simple answer to this problem. The best solution would be to problematically switch to a different desktop when you need to guarantee nothing will appear over it. I was unable to find a simple C# implementation of desktop switching that worked and I had a looming doubt that I would just be opening a whole new set of worms once it was implemented. Therefore, I decided not to implement the desktop switching. I did find a C++ Implementation that works well. Please post working C# virtual desktop implementations for others.
Setting the TopMost property (or adding the WS_EX_TOPMOST style to a window) does not make it unique in the system. Any number of topmost windows may be created by any number of applications; the only guarantee is that all topmost windows will be drawn 'above' all non-topmost windows. If there are two or more topmost windows, the Z-order still applies. From your description, I suspect that flash.exe is also creating a topmost window.
Aside from periodically forcing your window to the top of the Z-order, I think there is little you can do. Be warned, however, that this approach is dangerous: if two or more windows are simultaneously trying to force themselves to the top of the Z-order, the result will be a flickering mess that the user will likely have to use the task manager to escape.
I recommend that your program not attempt to meddle with other processes on the computer (unless that is its explicit purpose, e.g. a task manager clone). The computer belongs to the user, and he may not value your program more highly than all others.
Addendum:
For the emergency situation described in the comments, I would look at possible solutions along these lines:
How does the third party application normally get started and stopped? Am I permitted to close it the same way? If it is a service, the Service Control Manager can stop it. If it is a regular application, sending an escape keystroke (with SendInput() perhaps) or WM_CLOSE message to its main window may work.
If I can't close it nicely, am I permitted to kill it? If so, TerminateProcess() should work.
If I absolutely have to leave the other process running, I would try to see if I can programmatically invoke fast user switching to take me to a different session (in which there will be no competing topmost windows). I don't know where in the API to start with this one. (Peter Ruderman suggests SwitchDesktop() for this purpose in his answer.)
You can use the Process class to start flash.exe directly - and use an appropriate ProcessStartInfo settings to show the window in a hidden state - or with a WindowStyle of hidden or minimized.
You could also consider using the SetWindowsHookEx API to intercept the process start API calls, and when the process is flash.exe run some code to restore you window to top-most status.
Matthew's answer is excellent, but I suspect you may be asking the wrong question. Why does your application need to be topmost? If you're trying to create a kiosk or some such, then topmost is not the way to go.
Edit: After reading your response to Matthew's comment, I'd suggest creating a new desktop and switching to it before displaying your alert. (See CreateDesktop and SwitchDesktop in MSDN.)