I have a WinForms application (I'm using VB) that can be minimized to the system tray. I used the "hackish" methods described in multiple posts utilizing a NotifyIcon and playing with the Form_Resize event.
This all works fine aesthetically, but the resources and memory used are unaffected. I want to be able to minimize resources when minimizing to system tray, just like Visual Studio does. If you are coding in Visual Studio, the memory usage can creep up (depending on project size) to above 500 MB, but when minimizing Visual Studio to the taskbar, the memory drastically decreases to (what I'm assuming) is the minimal amount.
Does anyone have any clue as to how to accomplish this?
Here's a short description of the application, if anyone finds it relevant: I have a windows form with a ListView that contains Work Orders for my IT department. The application has a "listener" that notifies when a new Work order is submitted. So, when the application is running in the system tray, all I really do is compare the count of items in the ListView to a count of rows in a SQL table every couple of minutes.
EDIT: To be more specific, a windows form intrinsically has threads and resources being used by means of the controls, when the form is invisible (in the system tray) these resources are still being used. What can I do to minimize these resources, short of killing all the controls and redrawing them when the form is restored.
Calling MiniMizeMemory() will do a garbage collection, trim the process working size, then compact the process' heap.
public static void MinimizeMemory()
{
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
SetProcessWorkingSetSize(
Process.GetCurrentProcess().Handle,
(UIntPtr)0xFFFFFFFF,
(UIntPtr)0xFFFFFFFF);
IntPtr heap = GetProcessHeap();
if (HeapLock(heap))
{
try
{
if (HeapCompact(heap, 0) == 0)
{
// error condition ignored
}
}
finally
{
HeapUnlock(heap);
}
}
}
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetProcessWorkingSetSize(
IntPtr process,
UIntPtr minimumWorkingSetSize,
UIntPtr maximumWorkingSetSize);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetProcessHeap();
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool HeapLock(IntPtr heap);
[DllImport("kernel32.dll")]
internal static extern uint HeapCompact(IntPtr heap, uint flags);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool HeapUnlock(IntPtr heap);
You're probably looking for this function call: SetProcessWorkingSetSize
If you execute the API call SetProcessWorkingSetSize with -1 as an argument, then Windows will trim the working set immediately.
However, if most of the memory is still being held by resources you haven't released minimizing the working set will do nothing. This combined with the suggestion of forcing Garbage Collection might be your best bet.
From your application description, you might want to also verify how much memory the ListView is consuming as well as the database access objects. I'm also not clear on how you're making those monitoring database calls. You might want to isolate that into a separate object and avoid touching any of the forms while minimized, otherwise the program will be forced to keep the controls loaded and accessible. You could start a separate thread for monitoring, and pass the ListView.Count as a parameter.
Some sources:
.NET Applications and the Working Set
How much memory does my .Net Application use?
To clean up unused memory, use GC.Collect()... though you should read up on why to do it and why its usually a bad idea to use it often.
If you mean other resources, you will need to be more specific.
While this is in C#, look at the source code, it will solve any issues you have:
http://www.codeproject.com/KB/cs/NotifyIconExample.aspx
Related
I wonder whether from .Net managed code, or maybe p/invoking the needed NT dll, if I could generate a BSOD (Blue Screen Of Death) with specific bugcheck-code reason.
I know this is possible from a kernel-mode driver by calling KeBugCheck or KeBugCheckEx methods, but I think there is no way to call those methods from user-mode applications.
Someone could clarify me things, and bring an alternative way (if exists) for managed code?.
I had some code that did exactly that
here we go:
you might just need ntdll.dll but I used it without installing anything...
though the bug check codes don't seem to be the normal types
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
namespace bsod
{
class Program
{
private static uint STATUS_ASSERTION_FAILURE = 0xC0000420;
// private static uint KMODE_EXEPTION_NOT_HANDLED=0x0000008E;
static void Main(string[] args) {
while (Console.ReadKey(true).Key == ConsoleKey.W)
{
crash();
}
}
static void crash()
{
bool previousValue=false;
// Console.WriteLine("Adjusting privileges");
RtlAdjustPrivilege(19, true, false, out previousValue);
// Console.WriteLine("Triggering BSOD");
uint oul = 0;
IntPtr sptr = Marshal.StringToHGlobalAnsi("");
NtRaiseHardError(STATUS_ASSERTION_FAILURE, 0, 0, IntPtr.Zero, 6, out oul);
}
[DllImport("ntdll.dll")]
private static extern uint RtlAdjustPrivilege(
int Privilege,
bool bEnablePrivilege,
bool IsThreadPrivilege,
out bool PreviousValue
);
[DllImport("ntdll.dll")]
private static extern uint NtRaiseHardError(
uint ErrorStatus,
uint NumberOfParameters,
uint UnicodeStringParameterMask,
IntPtr Parameters,
uint ValidResponseOption,
out uint Response
);
}
}
let me clarify that this can be very dangerous, as you are one step away from an infinite loop constantly crashing your computer...
You can kill the csrss process, pretty simple:
System.Diagnostics.Process.GetProcessesByName("csrss").Single().Kill();
Even if that requires administrator rights
I can't say for certain that the kernel does not provide some means of invoking KeBugCheck with arbitrary arguments from user mode, even if just for highly privileged processes, but I very much hope none does and I certainly sympathise with anyone who wonders why on earth you would want something like this to exist let alone to use it.
Of course, even if the kernel doesn't already expose it for calling from user mode, it is readily available in kernel mode, i.e., to be called by drivers. Even there, however, drivers are strongly discouraged from resorting to it in any code that's ever released. Though a driver could expose a user-mode interface, e.g., through Device I/O Control, for calling KeBugCheck on behalf of a user-mode client, even an unprivileged one, doing so would be incredibly irresponsible of a driver writer (except, perhaps, for private testing).
As for CSRSS, some of you may want to know as background (and perhaps know already) that the architecture has long allowed that CSRSS needn't be critical (in the sense that killing it kills Windows) and also that it needn't be the only one. There is an undocumented function RtlSetProcessIsCritical which programs such as CSRSS call to register themselves as being so vital that when the kernel sees them exit then the kernel should raise either of two particular bug checks.
Since I've try many ways to stop the multiple instance problem on handheld device which running on .net compact framework 3.5.
Currently , I got the solution by create "Mutex" and check if there is the same process is running. I put this statement in "Program.cs" which will executed at first time when program start.
But i think it's not shoot my problems cause I got request from user that they need to disable the "program icon" while it's running.
I understand the user's point that sometime they maybe "Open" the program multiple times or more within short period. So , If it still able to "Open". That mean the program will need to initial itself and maybe going fail finally. Is it possible to absolutely prevent the multiple instance ? or is there another way without programming like edit the registry on Windows CE ?
Here is my source code:
bool firstInstance;
NamedMutex mutex = new NamedMutex(false, "MyApp.exe", out firstInstance);
if (!firstInstance)
{
//DialogResult dialogResult = MessageBox.Show("Process is already running...");
Application.Exit();
}
NamedMutex is class from OpenNetCF.
Your code is almost fine. only missing thing is to remove the application exit and put in there the code needed to bring current running instance on top. i did this in the past so you do not need to disable or hide the icon you simply detect the already running instance and bring it on foreground.
Edit:
here some code snippet:
[DllImport("coredll.dll")]
private static extern IntPtr FindWindow(IntPtr className, string windowName);
[DllImport("coredll.dll")]
internal static extern int SetForegroundWindow(IntPtr hWnd);
[DllImport("coredll.dll")]
private static extern bool SetWindowPos(IntPtr hwnd, int hwnd2, int x,int y, int cx, int cy, int uFlags);
if (IsInstanceRunning())
{
IntPtr h = FindWindow(IntPtr.Zero, "Form1");
SetForegroundWindow(h);
SetWindowPos(h, 0, 0, 0, Screen.PrimaryScreen.Bounds.Width,Screen.PrimaryScreen.Bounds.Height, 0x0040);
return;
}
check these links for more info...
http://www.nesser.org/blog/archives/56 (including comments)
What is the best way to make a single instance application in Compact Framework?
In order to get the application name of the foreground Window (or the name of application file) I want to use GetActiveWindow with GetWindowModuleFileName.
I found a similar question relating to GetWindowText here
That implementation of GetWindowText works fine, but GetWindowModuleFileName only returns a value for visual studio (when I click inside the devenv) for all other applications it stays blank.
Any hint how I can find out what goes wrong? Might this have to do with permission/security of my application querying the applicationfilename of another process?
EDIT: http://support.microsoft.com/?id=228469 looks like this doesn't work under Win >=XP
Any alternatives how to get the application file name?
In order to get the application name of the foreground Window (or the name of application file) I want to use GetActiveWindow with GetWindowModuleFileName.
... querying the applicationfilename of another process ...
In my opinion your problem with use of GetActiveWindow() function. It is used for gathering information from the calling thread/process only. If calling thread is inactive GetActiveWindow return 0;
From MSDN:
GetActiveWindow Retrieves the window handle to the active window attached to the calling thread's message queue.
Try to use GetForegroundWindow() function instead of GetActiveWindow()
By chance do you have UAC turned off?
Starting with Vista, if your code touches an HWND in another process, your process needs to be run at the same privilege level.
In other words, if the window is hosted in a process running as administrator, your app must also run as administrator.
I found a workaround using this:
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
IntPtr handle = IntPtr.Zero;
handle = GetForegroundWindow();
uint processId;
if (GetWindowThreadProcessId(handle, out processId) > 0)
{
Console.WriteLine(Process.GetProcessById((int)processId).MainModule.FileName);
}
I have a desktop application in which I would like to know two things:
Is the user currently on the PC (more specifically, is he giving any input to the PC), so I can change his state to "away" if needed; and
Is the screensaver running right now, so I can perform more CPU intensive work during that time.
I'm using C#/.NET. How would you suggest to tackle these two tasks?
NOTE: WIN32 invocation will be just as good, as well as any unmanaged code solution.
http://dataerror.blogspot.com/2005/02/detect-windows-idle-time.html
^ Detect Windows Idle Time. :)
The enabler for this feature is the GetLastInputInfo() Win32 API and the LASTINPUTINFO Win32 structure.
Here is the code to detect if a screen saver is running. See this for more details
const int SPI_GETSCREENSAVERRUNNING = 114;
[DllImport( "user32.dll", CharSet = CharSet.Auto )]
private static extern bool SystemParametersInfo(
int uAction, int uParam, ref bool lpvParam,
int flags );
// Returns TRUE if the screen saver is actually running
public static bool GetScreenSaverRunning( )
{
bool isRunning = false;
SystemParametersInfo( SPI_GETSCREENSAVERRUNNING, 0,
ref isRunning, 0 );
return isRunning;
}
Rather than figuring out when to run more intensive work... Consider doing your "intensive work" as early as you can, but at a lower thread priority.
I don't think your questions have an answer in pure C#, unless you poll the mouse position and observe movements... Or something like that.
You could use a global keyboard/mouse hook and just reset your "counter" to 0 when you receive an event from either. When your counter reaches the idle time that you're looking for, perform your background actions.
There is some code here that allows you to easily do the hooking in .NET: http://www.codeproject.com/KB/cs/globalhook.aspx
How can I prevent the pocket PC device from shutting down from my application when the power button pressed? I am using C#.
You could use the Microsoft.WindowsCE.Form.MessageWindows class to intercept the Power Button event. This solution will not be portable, as the hardware key will be different in different machines.
I recommend however that you don't disable power down completely. Have a look at my answer in another question here. You could also use openetcf to easily create power down events handlers and register wake up events. You should implement the application logic based on what you are trying to achieve, for instance wake up every one minute to run a process.
You can try changing the power requirements for the device "BLK1:", which is the blacklight device. Be aware that the behavior may not be the same on all devices and version of the OS or Vendor specific Extensions.
To do this, you can write something like :
[DllImport("coredll")]
private extern static IntPtr SetPowerRequirement(string pvDevice, int deviceState,
int deviceFlags, IntPtr pvSystemState, int stateFlags);
[DllImport("coredll")]
private extern static int ReleasePowerRequirement(IntPtr handle);
and call it this way :
IntPtr handle = SetPowerRequirement("BLK1:", 0 /* D0, Full On */, 1, IntPtr.Zero, 0);
// Do something that requires the device to stay on ...
ReleasePowerRequirement(handle);
But this is generally not a good practice, leaving a device with the backlight on for extended periods might reduce dramatically its autonomy.