Disable animation effects for windows with C# - 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));
}

Related

Sending scroll commands with SendInput on Windows10 UWP applications

I have code very similar to this question running in a windows tray application, even with this exact code from the question I get the same behavior. It all works well on classic windows applications, such as Firefox, Chrome, Windows Explorer etc. However when the mouse focus gets to a UWP app such as Edge or Calendar or Mail the scroll becomes jittery and after a few dozen scrolls performed my application hangs and can't even be terminated from task manager (permission denied), this behavior is very reproducible.
I'll paste the code from the question here:
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace EnableMacScrolling
{
class InterceptMouse
{
const int INPUT_MOUSE = 0;
const int MOUSEEVENTF_WHEEL = 0x0800;
const int WH_MOUSE_LL = 14;
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
if (_hookID == null)
{
MessageBox.Show("SetWindowsHookEx Failed");
return;
}
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_MOUSEWHEEL == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
Console.WriteLine(hookStruct.mouseData);
if (hookStruct.flags != -1) //prevents recursive call to self
{
INPUT input;
input = new INPUT();
input.type = INPUT_MOUSE;
input.mi.dx = 0;
input.mi.dy = 0;
input.mi.dwFlags = MOUSEEVENTF_WHEEL;
input.mi.time = 0;
input.mi.dwExtraInfo = 0;
input.mi.mouseData = -(hookStruct.mouseData >> 16);
try
{
SendInput(1, ref input, Marshal.SizeOf(input));
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
}
return (IntPtr)1;
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private enum MouseMessages
{
WM_MOUSEWHEEL = 0x020A
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public int mouseData;
public int flags;
public int time;
public IntPtr dwExtraInfo;
}
public struct INPUT
{
public int type;
public MOUSEINPUT mi;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public uint dwFlags;
public int time;
public int dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("User32.dll", SetLastError = true)]
public static extern int SendInput(int nInputs, ref INPUT pInputs, int cbSize);
} }
Is it possible that I'm dealing with a bug in windows here? Any pointers to how I can find out what's going on?
Update:
I have created a test Win32 application in C++ to more easily reproduce/demonstrate the problem. The issue is with the SendCommand which when executed while any classic application is in focus works fine. However when executed while a UWP application is in focus, or even the windows launch/start menu causes the calling application (my application) to hang and be stuck until windows is restarted.
An effective workaround/solution for this problem is to perform the SendCommand call on another thread from the thread handling the hook callback. Immediately launching the thread that executes SendCommand and returning from the hook callback produces the desired behavior and doesn't cause any problems.
if (hookStruct.flags != -1) //prevents recursive call to self
That's rather important, yes. But how the statement could possibly do its job is very unclear. The expected value of this field is 0, 1 or 3. Never -1. You perhaps got mislead by another mouse hook that is active on your machine.
Now it does matter whether a WinRT app is in the foreground. Because then the message broker is involved and the field value changes, the LLMHF_LOWER_IL_INJECTED bit is turned on. WinRT apps run in a sandbox that run at a lower integrity level. So the field will not be -1 and your SendInput() call triggers the mouse hook again. On and on it goes, show is over when it runs out of stack.
So first possible fix is to use the field as intended, change the statement to:
if ((hookStruct.flags & 1) == 0)
Won't work if that presumed wonky mouse hook is corrupting the field, then consider using a static bool field in your class to break the recursion. Set it to true before the SendInput() call, false afterwards.
But I think I know why you are doing this, I too have been a victim of a trackpad that got it backwards. There is a much easier way to do it, just modify the FlipFlopWheel setting.

Disable windows effect

I'm intrested in disabling the classic windows effect-such as the fade in effect when you open a window.. etc.
I've seen this, i've tried to call the SystemParametersInfo in order to disable the effect,tried the suggestion in the solution.. but still.. i dont see any change...
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SystemParametersInfo(
uint uiAction,
uint uiParam,
bool pvParam,
uint fWinIni
);
public const uint SPI_SETANIMATION = 0x73;
private unsafe void Form1_Load(object sender, EventArgs e)
{
bool enabled = false;
SystemParametersInfo(SPI_SETANIMATION, 0, enabled, 0);
}
I'm using windows 10.
I'll appreciate any incoming help.Thanks!

How to destroy ICONINFO?

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);

How Can I Check if a Window is an MDI Window?

I imagine there's some user32.dll call that I can use to verify if a window is an MDI window, like using DefMDIChildProc and seeing if it fails, but I wonder if there's any limitations to this, or if there's a better way to do this? Is checking for a Parent sufficient?
For simplicity's sake, what I'm ultimately hoping for is an IsMDI(IntPtr ptr) kind of call...
Thoughts? Suggestions?
I've figured it out (with the help of pinvoke.net) - you can find out based on the Extended Windows Styles:
public static bool IsMDI(IntPtr hwnd)
{
WINDOWINFO info = new WINDOWINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
GetWindowInfo(hwnd, ref info);
//0x00000040L is the style for WS_EX_MDICHILD
return (info.dwExStyle & 0x00000040L)==1;
}
[StructLayout(LayoutKind.Sequential)]
private struct WINDOWINFO
{
public uint cbSize;
public RECT rcWindow;
public RECT rcClient;
public uint dwStyle;
public uint dwExStyle;
public uint dwWindowStatus;
public uint cxWindowBorders;
public uint cyWindowBorders;
public ushort atomWindowType;
public ushort wCreatorVersion;
public WINDOWINFO(Boolean? filler)
: this() // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)".
{
cbSize = (UInt32)(Marshal.SizeOf(typeof(WINDOWINFO)));
}
}
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
private static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);
If the controls are in your own .NET application, the Form class has properties for working with MDI windows:
Form.IsMdiChild
Form.IsMdiContainer
Form.MdiParent
Form.MdiChildren

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!

Categories

Resources