C # Use WinAPI to modify the power settings. temporarily disable sleep when the notebook is closed.

Source: Internet
Author: User

The C # preparation process is included in the small software that blocks automatic sleep of the system, providing a tool to prevent System sleep. Then, we immediately discovered a new demand: in order to protect the environment (save money), the system settings will automatically sleep when the lid is closed. If you need to temporarily disable sleep for download and other reasons, you are too lazy to change the settings. You have to change the settings again next time. So it's not a problem, so I studied how to implement it with software.

 

The initial idea is to Hook to cut off sleep messages. But there is a way to find it.

Then it is found that when the system goes to sleep, a message will be broadcast, and each software will have two seconds (xp and 03 can be up to 20 seconds) to complete the aftermath (PBT_APMSUSPEND event ). Although the System Wake-up Events can be used to Wake up a sleep computer, there is no way to cancel the sleep.

Finally, when I solve the problem, I temporarily modify the power supply settings to close the lid settings, and then restore the original settings as needed.

 

Windows Power Management and Configuration tool powercfg

In Windows, the power management solution is like this. The largest dimension is the power supply configuration scheme. Each scheme includes a set of Power Supply settings. You can change the current active solution or change the value of each Power Supply setting.

Use Built-in System ToolsPowercfgView and change the Power Supply Configuration: The GUID value will be used later.

The GUID of the power supply scheme may vary depending on the activation scheme, and the GUID of the sub-group and the GUID of the power supply setting are the same in each scheme. You can use these two IDs to set them later. By the way, each setting hasDC and ACTwo items, indicating the use of notebook power and external power settings.

Now, you can close the work easily: Use the powercfg tool to set the power solution.

However, I choseUse APIs to configure the power supply Solution.

Sacrifice the APIs to be used.

PowerGetActiveScheme

PowerSetActiveScheme

PowerReadACValueIndex (a DC-related API is not listed, the same below)

PowerWriteACValueIndex

The general process is very simple. First, get the current settings and save them. Then, the system is set so that no operation is taken when the lid is closed. Finally, write back the original settings as needed. Note that you must call PowerSetActiveScheme once to modify the settings of the current active solution.

 

The following question becomes how to use APIs in C.

WinAPI basically only provides C interfaces, many of which are not encapsulated in C #, so you need to declare the corresponding function on your own. The following is a simple example.

using System.Runtime.InteropServices;[DllImport("kernel32.dll")]public static extern uint SetThreadExecutionState(uint esFlags);

Among them, the most painful thing is that you have to perform the parameter yourself.Type conversion. The biggest headache is that some APIs have to be passed to parameters.Level 2 pointerYou don't even know what to do.

 

For basic data types, refer to this table (copied on the Internet, and note that it is really for reference only ):

The statement in C # is as follows:

// Convert the return value DWORD to uint. Uint PowerReadACValueIndex (// The first parameter type HKEY, which is a dry pointer and can only be NULL in this API, it is simply declared as the IntPtr type, use IntPtr. zero. IntPtr RootPowerKey, // GUID corresponds to this Guid type in C. As for the first-level pointer, it depends on what the pointer is. If the pointer only points to a variable, it will be modified with ref. Actually, the pointer is passed. If the Pointer Points to the first address of an array, you must first allocate a piece of memory in C # And then transfer the address of the memory. Refer to the previous blog post. Ref Guid SchemeGuid, ref Guid SubGroupOfPowerSettingsGuid, ref Guid PowerSettingGuid, // The last parameter type LPDWORD. LP refers to long pointer. It seems that the current system does not matter the length of the pointer. Let's simply think of it as a pointer. LPDWORD is a pointer to DWORD. Corresponding to C # Is the ref uint. Ref uint AcValueIndex );

 

The world is still very simple.Level 2 pointer:

DWORD WINAPI PowerGetActiveScheme(  _In_opt_  HKEY UserRootPowerKey,  _Out_     GUID **ActivePolicyGuid);

The purpose of this operation is to pass in the address of the variable p_GUID pointing to the GUID *, and then use a new GUID as the result, then, the value of p_GUID is set to the address of the result. Call LocalFree to release the memory. Now we cannot use ref to save time, so we can honestly upload an IntPtr:

uint PowerGetActiveScheme(IntPtr UserRootPowerKey, ref IntPtr p_ActivePolicyGuid);

After the call, p_ActivePolicyGuid is a pointer to the GUID variable. Because the ref modifier is used, it isLevel 1 pointer. How can I explain what he points? C # hasMarshal:

Guid guid = (Guid)Marshal.PtrToStructure(p_ActivePolicyGuid, typeof(Guid));

The world is a little complicated, but still acceptable.

Until ......

You need to input a handle to the first parameter. This handle can be of two types: one is the window handle, and the other is complicated, involving services, and it is very troublesome. I do not know whether there is a simple method.

At this time, it was quite difficult, because at the beginning of the software writing, only one NotifyIcon control was run in the main thread, and the handle of this item was private, even if the handle is obtained through the following hack and the registration is successful, the thread will not receive the message. The hack code is as follows (copy this: a more BT NotifyIcon supports BalloonTip, which has not been understood yet ):

private IntPtr GetWindowHandle(NotifyIcon notifyIcon){    if ( notifyIcon == null )    {        return IntPtr.Zero;    }    Type type = notifyIcon.GetType();    BindingFlags bf = BindingFlags.Instance | BindingFlags.NonPublic;    FieldInfo fiWindow = type.GetField("window", bf);    object objWindow = fiWindow.GetValue(this.m_NotifyIcon);    type = objWindow.GetType().BaseType;    FieldInfo fiHandle = type.GetField("handle", bf);    IntPtr handle = (IntPtr)fiHandle.GetValue(objWindow);    return handle;}

In the end, a Form control is well-behaved. There is a problem:A thread already has a message queue. Can I register the handle of a thread where the form handle needs to be registered?

How can I use it after registration?

First, the message processing function of the reload form is as follows:

protected override void WndProc(ref Message m){if (m.Msg == Win32API.WM_POWERBROADCAST) {MessageBox.Show("Power mode Changed! wndproc");return; }base.WndProc(ref m);}

Second, use message filtering: IMessageFilter

After this interface is implemented, you can use Application. AddMessageFilter to add message filtering.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.