How to destroy ICONINFO? - c#

I step through the code and look in Task Manager the number of GDI and user objects used by the process. Tracked the number of objects in the code I wrote in the comments. I noticed that after performing the following code remains one unreleased user object and one unreleased GDI object. Where I forgot to release them?
using System;
using System.Runtime.InteropServices;
namespace UnmanagedResourcesTest
{
class Program
{
static void Main(string[] args)//20 user objects; 27 GDI objects
{
CURSORINFO ci = new CURSORINFO();
ci.cbSize = Marshal.SizeOf(ci);
if (GetCursorInfo(out ci))
{
////21(+1) user objects; 27 GDI objects
if (ci.flags == CURSOR_SHOWING)
{
bool result;
IntPtr hicon = CopyIcon(ci.hCursor);//uo1/go1
////22(+1) user objects; 28(+1) GDI objects
ICONINFO icInfo;
if (GetIconInfo(hicon, out icInfo))//go1
{
////22 user objects; 29(+1) GDI objects
Console.WriteLine("ICONINFO gotten");
}
result = DestroyIcon(hicon);
////21(-1) user objects; 28(-1) GDI objects
Console.WriteLine("Is hicon destroyed? - " + result);
}
}
//leaves 21-20=1 not released user object and 28-27=1 not released GDI object
Console.ReadKey();
}
private const Int32 CURSOR_SHOWING = 0x00000001;
[DllImport("user32.dll", EntryPoint = "GetCursorInfo")]
private static extern bool GetCursorInfo(out CURSORINFO pci);
[DllImport("user32.dll", EntryPoint = "CopyIcon")]
private static extern IntPtr CopyIcon(IntPtr hIcon);
[DllImport("user32.dll", EntryPoint = "GetIconInfo")]
private static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo);
[DllImport("user32.dll", SetLastError = true)]
static extern bool DestroyIcon(IntPtr hIcon);
[StructLayout(LayoutKind.Sequential)]
private struct ICONINFO
{
public bool fIcon; // Specifies whether this structure defines an icon or a cursor. A value of TRUE specifies
public Int32 xHotspot; // Specifies the x-coordinate of a cursor's hot spot. If this structure defines an icon, the hot
public Int32 yHotspot; // Specifies the y-coordinate of the cursor's hot spot. If this structure defines an icon, the hot
public IntPtr hbmMask; // (HBITMAP) Specifies the icon bitmask bitmap. If this structure defines a black and white icon,
public IntPtr hbmColor; // (HBITMAP) Handle to the icon color bitmap. This member can be optional if this
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public Int32 x;
public Int32 y;
}
[StructLayout(LayoutKind.Sequential)]
private struct CURSORINFO
{
public Int32 cbSize; // Specifies the size, in bytes, of the structure.
public Int32 flags; // Specifies the cursor state. This parameter can be one of the following values:
public IntPtr hCursor; // Handle to the cursor.
public POINT ptScreenPos; // A POINT structure that receives the screen coordinates of the cursor.
}
}
}

I found the cause of the memory leak. Should call next line:
result = DeleteObject(icInfo.hbmMask);

Related

DwmGetWindowAttribute doesn't get the correct Rect size for MediaPlayer if it's in full screen mode

I am trying to get application size using this code :
[DllImport(#"dwmapi.dll")]
private static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out Rect pvAttribute, int cbAttribute);
[Serializable, StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public Rectangle ToRectangle()
{
return Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
}
private static bool DWMWA_EXTENDED_FRAME_BOUNDS(IntPtr handle, out Rectangle rectangle)
{
Rect rect;
var result = DwmGetWindowAttribute(handle, (int)Dwmwindowattribute.DwmwaExtendedFrameBounds,
out rect, Marshal.SizeOf(typeof(Rect)));
rectangle = rect.ToRectangle();
return result >= 0;
}
it's working fine for all running applications but if it's Media Player in fullscreen mode I didn't get the right Rect size.
Windows Media Player is weird in full screen mode such that the main window handle doesn't correspond to the full screen window displayed. The full screen window still has a handle but a little more work is needed to get to it.
First you'd need to declare some WinAPI functions and structs:
delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
[DllImport("User32.dll")]
static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("User32.dll")]
static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfo lpmi);
[DllImport("User32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("User32.dll")]
static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
[StructLayout(LayoutKind.Sequential)]
struct MonitorInfo
{
public uint Size;
public Rect Monitor;
public Rect Work;
public uint Flags;
}
// You seem to have this one already
[StructLayout(LayoutKind.Sequential)]
struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
From there, the method looks like this:
// Pass Windows Media Player's main window handle here.
static bool GetWmpFullScreenHandle(IntPtr mainHandle, out IntPtr fullScreenHandle)
{
IntPtr tempHandle = IntPtr.Zero;
// Getting WMP's PID from the main window handle.
GetWindowThreadProcessId(mainHandle, out uint wmpProcessId);
// Optionally, check if the PID resolves to a WMP process.
if (System.Diagnostics.Process.GetProcessById(wmpProcessId).ProcessName != "wmplayer")
{
fullScreenHandle = IntPtr.Zero;
return false;
}
// This iterates through all the open window handles on the machine
// and passes them to the callback below.
EnumWindows((hWnd, lParam) =>
{
// Getting the window handle's PID.
GetWindowThreadProcessId(hWnd, out uint windowProcessId);
// Checking if the window handle belongs to the WMP process.
if (windowProcessId == wmpProcessId)
{
var monitorInfo = new MonitorInfo
{
Size = Convert.ToUInt32(Marshal.SizeOf(typeof(MonitorInfo)))
};
// Getting the dimensions of the monitor the window is displayed on,
// as well as the window dimensions.
if (GetMonitorInfo(MonitorFromWindow(hWnd, 0), ref monitorInfo) &&
GetWindowRect(hWnd, out Rect windowRect))
{
Rect monitorRect = monitorInfo.Monitor;
// If the window dimensions are the same as its monitor's
// dimensions, then we found a hidden full-screen window!
if (windowRect.Left == monitorRect.Left &&
windowRect.Top == monitorRect.Top &&
windowRect.Right == monitorRect.Right &&
windowRect.Bottom == monitorRect.Bottom)
{
tempHandle = hWnd;
}
}
}
return true;
},
IntPtr.Zero);
fullScreenHandle = tempHandle;
// Returns true if the hidden full-screen handle was found, false otherwise.
return fullScreenHandle != IntPtr.Zero;
}
If found, you can then pass the resulting handle to DWMWA_EXTENDED_FRAME_BOUNDS to get the Rectangle.

Disable animation effects for windows with C#

I'm trying to disable the "fading" animation in windows which happens whenever you open or maximize/minimize a window.
Of course it can be done manually by unticking the checkbox of animate windows when minimizing and maximizing
I'm trying to do this through the SystemParametersInfo
This is my call:
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SystemParametersInfo(uint uiAction, uint uiParam, bool pvParam,uint fWinIni);
private static UInt32 SPIF_SENDCHANGE = 0x02;
private static UInt32 SPI_SETUIEFFECTS = 0x103F;
public static void Main()
{
bool res= SystemParametersInfo(SPI_SETUIEFFECTS, 0, false, SPIF_SENDCHANGE);
}
result value is always True , so I know the function was successfully called.
But I can't see any results...Windows still keep animating any window I resize.
I compile this as AnyCPU, running as adminstrator on Windows 10.
for #cody gray this is the code (added the ref keyword to the ai paramater and converted the Marshal.Sizeof(ai) to `uint).
[StructLayout(LayoutKind.Sequential)]
public struct ANIMATIONINFO
{
public uint cbSize;
public int iMinAnimate;
};
[DllImport("user32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SystemParametersInfo(uint uiAction,
uint uiParam,
ref ANIMATIONINFO pvParam,
uint fWinIni);
public static uint SPIF_SENDCHANGE = 0x02;
public static uint SPI_SETANIMATION = 0x0049;
public static void Main()
{
ANIMATIONINFO ai=new ANIMATIONINFO();
ai.cbSize = (uint)Marshal.SizeOf(ai);
ai.iMinAnimate = 0; // turn all animation off
SystemParametersInfo(SPI_SETANIMATION, 0, ref ai, SPIF_SENDCHANGE);
}
One last question-if i would like to get back to the original state-which means i want to activate the aniamtions again,what parameter should be changed in order to do this?
You are not setting the right option when you call SystemParametersInfo. The one that controls the minimize/maximize animation effect (labeled in the UI as "Animate windows when minimizing and maximizing") is SPI_SETANIMATION.
Using it is a bit more complicated, because the pvParam parameter must point to an ANIMATIONINFO structure. It is rather pointless, because the struct only has one meaningful member, but that's the way the API was designed. Presumably, the intent years ago was for this to be a toggle for all of the shell animation effects, but for whatever reason, that didn't end up happening, and separate SPI_* values were used for each of them. You unfortunately picked the wrong one. It is a long list.
Sample code in C#:
[StructLayout(LayoutKind.Sequential)]
public struct ANIMATIONINFO
{
public uint cbSize;
public int iMinAnimate;
};
[DllImport("user32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SystemParametersInfo(uint uiAction,
uint uiParam,
ref ANIMATIONINFO pvParam,
uint fWinIni);
public static uint SPIF_SENDCHANGE = 0x02;
public static uint SPI_SETANIMATION = 0x0049;
public static void Main()
{
ANIMATIONINFO ai;
ai.cbSize = Marshal.SizeOf(ai);
ai.iMinAnimate = 0; // turn all animation off
SystemParametersInfo(SPI_SETANIMATION, 0, ai, SPIF_SENDCHANGE);
}
Note that this is a global setting, affecting all applications. It is exceedingly rare that an application would ever need to toggle this switch, unless you were making a desktop customization utility. As such, you will require administrative privileges to change this setting.
There is also the DWMWA_TRANSITIONS_FORCEDISABLED flag that you can use with the DwmSetWindowAttribute function to disable transitions when a window is hidden or shown.
The advantage of this is that it is a local solution—you can change the setting only for a single window. But it won't do anything if you are not using DWM (on older versions of Windows), and the minimize/maximize transitions may still be visible. I haven't comprehensively tested the interaction between these two options.
Hans Passant linked you to one of his answers that contains an embedded example of how to call DwmSetWindowAttribute from C#. Here are the relevant bits:
const int DWMWA_TRANSITIONS_FORCEDISABLED = 3;
[DllImport("dwmapi", PreserveSig = true))]
static extern int DwmSetWindowAttribute(IntPtr hWnd, int attr, ref int value, int attrLen);
// in the form's constructor:
// (Note: in addition to checking the OS version for DWM support, you should also check
// that DWM composition is enabled---or at least gracefully handle the function's
// failure when it is not. Instead of S_OK, it will return DWM_E_COMPOSITIONDISABLED.)
if (Environment.OSVersion.Version.Major >= 6)
{
int value = 1; // TRUE to disable
DwmSetWindowAttribute(this.Handle,
DWMWA_TRANSITIONS_FORCEDISABLED,
ref value,
Marshal.SizeOf(value));
}

"Custom Cursor cannot be converted to String" Exception is thrown while converting the cursor to string

I am trying to change the cursor of my control on certain conditions. I have created my own custom cursor and assigned it to the Cursor.Current property. Everything working fine up-to this.
When I check whether the current control cursor and the new cursor is same or not based on their names by converting cursor using ToString() method, I get:
Custom Cursor cannot be converted to String
There is no problem in converting the System's default cursor and it raise only when converting custom cursor. Any one please tell me why this exception raised only on custom cursor?
this is the place where i got the error...
**if (m_cursorAction.ToString() != newCursor.ToString())
m_cursorAction = newCursor;**
Here is my cursor implementation code:
Bitmap bitmap = new Bitmap(140, 25);
Graphics g = Graphics.FromImage(bitmap);
using (Font f = new Font("SEGOE UI", 10))
g.DrawString("Node 30", f, System.Drawing.Brushes.Black, 0, 0);
Cursor.Current = MyCursor.CreateCursor(bitmap, 140, 25);
**if (m_cursorAction.ToString() != newCursor.ToString())**
m_cursorAction = newCursor;
public class MyCursor
{
#region Class members
private static IntPtr ptr;
public struct IconInfo
{
public bool bIcon;
public int xHotspot;
public int yHotspot;
public IntPtr hbmMask;
public IntPtr hbmColor;
}
#endregion
#region Class Public Methods
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern bool DestroyIcon(IntPtr handle);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr CreateIconIndirect([System.Runtime.InteropServices.In]ref IconInfo icon);
[System.Runtime.InteropServices.DllImport("gdi32")]
extern internal static bool DeleteObject(IntPtr hObject);
/// <summary>
/// Create a custom cursor with the given bitmap
/// </summary>
/// <param name="bmp">Bitmap for the cursor.</param>
/// <param name="xHotSpot">x hot spot to the cursor.</param>
/// <param name="yHotSpot">y hot spot to the cursor.</param>
public static System.Windows.Forms.Cursor CreateCursor(System.Drawing.Bitmap bmp, int xHotSpot, int yHotSpot)
{
IntPtr bmpPtr= bmp.GetHicon();
IconInfo icon = new IconInfo();
GetIconInfo(bmpPtr, ref icon);
icon.xHotspot = xHotSpot;
icon.yHotspot = yHotSpot;
icon.bIcon = false;
DestroyIcon(bmpPtr);
DeleteObject(bmpPtr);
ptr = CreateIconIndirect(ref icon);
System.Windows.Forms.Cursor cursor = new System.Windows.Forms.Cursor(ptr);
//delete the GDI objects and icon
DeleteObject(icon.hbmColor);
DeleteObject(icon.hbmMask);
DestroyIcon(icon.hbmColor);
DestroyIcon(icon.hbmMask);
return cursor;
}
/// <summary>
/// Destroy the custom cursor
/// </summary>
public static void Destroy()
{
DestroyIcon(ptr);
DeleteObject(ptr);
}
#endregion
}
Because it delegates to CursorConverter.ConvertTo, which is designed to throw that exception only for custom cursors.
Just don't use string comparison to test whether cursors are equal. Instead, use the Cursor.Equals method which is designed for comparing cursors.
One way, for custom Cursors, if you know what you're looking for, is to check the Handle:
// 65569 = Hand Pointer:
int handle = 65569;
if (handle == System.Windows.Forms.Cursor.Current.Handle.ToInt32())
MessageBox.Show("Hand Pointer Cursor");

How to measure system idle time in C#, excluding when watching movies, etc?

I am looking for a program that measures system idle time on Windows. I have found many codes that do this. For example,
http://www.codeproject.com/KB/cs/GetIdleTimeWithCS.aspx
However, I also want to take into account user watching movies, videos, etc. That time no input is given, but still the system is not idle.
Is there anyway to do this?
This function detects if a process is running in fullscreen in forground, and returns name of the process if found so:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
private static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
private static extern bool
GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
private struct POINTAPI
{
public int x;
public int y;
}
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
private struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
public POINTAPI ptMinPosition;
public POINTAPI ptMaxPosition;
public RECT rcNormalPosition;
}
public string FullscreenProcess()
{
IntPtr foreWindow = GetForegroundWindow();
// get the placement
WINDOWPLACEMENT forePlacement = new WINDOWPLACEMENT();
forePlacement.length = Marshal.SizeOf(forePlacement);
GetWindowPlacement(foreWindow, ref forePlacement);
if (forePlacement.rcNormalPosition.top == 0 && forePlacement.rcNormalPosition.left == 0 && forePlacement.rcNormalPosition.right == Screen.PrimaryScreen.Bounds.Width && forePlacement.rcNormalPosition.bottom == Screen.PrimaryScreen.Bounds.Height)
{
uint processID;
GetWindowThreadProcessId(foreWindow, out processID);
Process proc = Process.GetProcessById((int)processID);
return proc.ProcessName;
}
return null;
}
After this, we just need to match the returned process name with a set of popular media players or other processes.
Limitation is that we have assumed user plays in fullscreen.
You can get the idle time for computer using this, however your problem is how to know weather a movie is playing, you can check the processes that is currently running on the computer System.Diagnostics.Process.GetProcesses(), and then check if one of them is a known movie player. However I don't think this will achieve what you locking for either, because even if you find out that for example a Gom player is running, you still don't know if it running a video or audio or just opened without any thing actually playing...
In case you watch videos in fullscreen:
You could use code like this do determine if there is an app running in fullscreen:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int Left;
public int Top;
public int Width;
public int Height;
}
static bool IsBigWindowRunning()
{
foreach (Process proc in Process.GetProcesses())
{
RECT rect;
var success = GetWindowRect(proc.MainWindowHandle, out rect);
if(success && (r.Left + r.Width) >= Screen.PrimaryScreen.WorkingArea.Width)
{
return true;
}
}
return false;
}
I haven't tested it well and i would definetely play around with this line, add some limits:
if((r.Left + r.Width) >= Screen.PrimaryScreen.WorkingArea.Width)
Good luck!

Screen.AllScreen is not giving the correct monitor count

I am doing something like this in my program:
Int32 currentMonitorCount = Screen.AllScreens.Length;
if (currentMonitorCount < 2)
{
//Put app in single screen mode.
}
else
{
//Put app in dual screen mode.
}
It is VERY important my application recognizes how many monitors are currently connected.
However, after I plug/unplug the monitor a couple of times, Screen.AllScreens.Length always returns '2'.
My monitor knows it's not connected (it has entered 'power save' mode), and the control panel knows that it's not connected (it shows only one monitor).
So what am I missing? How do I figure out that there's only one monitor?
I had a look at the source (remember we can do that using the MS Symbol servers). AllScreens uses an unmanaged API to get the screens on the first access, then stores the result in a static variable for later use.
The consequence of this, is that if the number of monitors changes while your program is running; then Screen.AllScreens will not pick up the change.
The easiest way to get around this would probably be to call the unmanaged API directly.
(Or you could be evil, and use reflection to set the static screens field to null before asking. Don't do that).
Edit:
If you just need to know the count, check whether you can use System.Windows.Forms.SystemInformation.MonitorCount (as suggested in the comments) before going the P/Invoke route. This calls GetSystemMetrics directly, and it is probably correctly updated.
If you find you need to do it using P/Invoke, here is a complete example that demonstrates the usage of the unmanaged API from C#:
using System;
using System.Runtime.InteropServices;
class Program
{
public static void Main()
{
int monCount = 0;
Rect r = new Rect();
MonitorEnumProc callback = (IntPtr hDesktop, IntPtr hdc, ref Rect prect, int d) => ++monCount > 0;
if (EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, callback, 0))
Console.WriteLine("You have {0} monitors", monCount);
else
Console.WriteLine("An error occured while enumerating monitors");
}
[DllImport("user32")]
private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lpRect, MonitorEnumProc callback, int dwData);
private delegate bool MonitorEnumProc(IntPtr hDesktop, IntPtr hdc, ref Rect pRect, int dwData);
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int left;
public int top;
public int right;
public int bottom;
}
}
Building on the previous reply by driis, this is how I handled it. I should note that the following code lives in my Program.cs file.
First the links to external resources and data structures:
[DllImport("user32")]
private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lpRect, MonitorEnumProc callback, int dwData);
private delegate bool MonitorEnumProc(IntPtr hDesktop, IntPtr hdc, ref Rect pRect, int dwData);
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int left;
public int top;
public int right;
public int bottom;
}
Now create a simple object to contain monitor information:
public class MonitorInfo
{
public bool IsPrimary = false;
public Rectangle Bounds = new Rectangle();
}
And a container to hold these objects:
public static List<MonitorInfo> ActualScreens = new List<MonitorInfo>();
and a method to refresh the container:
public static void RefreshActualScreens()
{
ActualScreens.Clear();
MonitorEnumProc callback = (IntPtr hDesktop, IntPtr hdc, ref Rect prect, int d) =>
{
ActualScreens.Add(new MonitorInfo()
{
Bounds = new Rectangle()
{
X = prect.left,
Y = prect.top,
Width = prect.right - prect.left,
Height = prect.bottom - prect.top,
},
IsPrimary = (prect.left == 0) && (prect.top == 0),
});
return true;
};
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, callback, 0);
}
Then later on a Form, If I wanted to detect that a display had been added or removed ...
private const int WM_DISPLAYCHANGE = 0x007e;
protected override void WndProc(ref Message message)
{
base.WndProc(ref message);
if (message.Msg == WM_DISPLAYCHANGE)
{
Program.RefreshActualScreens();
// do something really interesting here
}
}
Might be a few typos in there, but that is the basic idea. Good luck!
I had a look at the code of the Screen class ( in here )
See line 120, Screen.AllScreens uses the field Screen.screens for cache.
In my solution, I use the reflection api to change the Screen class.
I clear Screens.screens before calling Screen.AllScreens.
// Code for clearing private field
typeof(Screen).GetField("screens", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).SetValue(null, null);

Categories

Resources