Use NativeWindow to disable screensaver - c#

I want to disable the screensaver and monitor power off. At this stage there's no windows form, which I could youse. Thus I wan't to use NativeWindow.
Here's my code
sealed class ObserverWindow : NativeWindow, IDisposable
{
internal ObserverWindow()
{
this.CreateHandle(new CreateParams()
{
Parent= IntPtr.Zero
});
}
public void Dispose()
{
DestroyHandle();
}
protected override void WndProc(ref Message msg)
{
if (msg.Msg == WM_SYSCOMMAND &&
((((long)msg.WParam & 0xFFF0) == SC_SCREENSAVE) ||
((long)msg.WParam & 0xFFF0) == SC_MONITORPOWER))
{
msg.Msg = 0;
msg.HWnd = IntPtr.Zero;
}
base.WndProc(ref msg);
}
}
The Problem is, that the WndProc is not called with WM_SYSCOMMAND. Actualy the WndProc is called 4 times. At the last call there's msg.Msg == WM_CREATE.
I think I'm missing some create parameter. Does anyone have advise?
Regards Michael
UPDATE
I was running the code in a non STA thread. Thus the window did not reveive any messages exept the initial ones. Now I'm receiving WM_SYSCOMMAND messages. But when the screensaver is activated, there's no message.
I also tried to overwrite a Form's WndProc with the same result. But this used to work in Windows XP. Is there a change in Windows 7?
OS: Windows 7 64bit.
SOLUTION
As a comment in this Question states, only the foreground window can cancel the screensaver. Thus the above code can't work. The NativeWindow is great for receiving messages, but not for canceling a screensaver. For latter I recommend the answer to this question.

The proper way to do this is by telling Windows that your thread needs to have the display active. Commonly used by video players. P/Invoke the SetThreadExecutionState() API function, pass ES_DISPLAY_REQUIRED. And ES_SYSTEM_REQUIRED to keep the machine from shutting down automatically. Visit pinvoke.net for the required declarations.

Disabling the screen saver is much easier, according to this KB article:
This can be done easily using:
SystemParametersInfo( SPI_SETSCREENSAVEACTIVE,
FALSE,
0,
SPIF_SENDWININICHANGE
);
[...]
If you need the screen saver to start up again, you'll need to reinitialize the time-out period. Do this by [c]alling SystemParametersInfo (SPI_SETSCREENSAVEACTIVE, TRUE, 0, SPIF_SENDWININICHANGE).

You could try overriding DefWndProc instead.
public override void DefWndProc(ref Message msg)
{
if (msg.Msg == WM_SYSCOMMAND &&
((((long)msg.WParam & 0xFFF0) == SC_SCREENSAVE) ||
((long)msg.WParam & 0xFFF0) == SC_MONITORPOWER))
{
msg.Msg = 0;
msg.HWnd = IntPtr.Zero;
}
base.DefWndProc(ref msg);
}
I'm not on a Windows box right now, so I cannot test this. Let me know if it works.

Related

Prevent Form resize on SW_MAXIMIZE

I want to simulate Aero Snap functionality by my own. And for stick Form to a screen's side I'm using solution from this question.
The problem is that after I call:
ShowWindow(Handle, SW_MAXIMIZE);
Form immediately maximizes and after call MoveWindow changes it's size to needed size. And this jump of the Form is visible and annoying. To prevent it I tried to disable handling of messages WM_GETMINMAXINFO, WM_SIZE, WM_MOVE, WM_NCCALCSIZE, WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED in WndProc. It helps but not completely. Is there any analog SuspendLayout()/ResumeLayout() for Form resizing?
Disabling message handling in WndProc helped me to reduce flickering (all except WM_NCPAINT):
bool ignoreMessages = false;
public void DockWindow()
{
ignoreMessages = true;
ShowWindow(handle, SW_MAXIMIZE);
ignoreMessages = false;
MoveWindow(handle, 0, 0, Screen.PrimaryScreen.WorkingArea.Width / 2, Screen.PrimaryScreen.WorkingArea.Height, true);
}
protected override void WndProc(ref Message message)
{
if (ignoreMessages &&
message.Msg != WM_NCPAINT)
return;
base.WndProc(ref message);
}

WndProc Overloading + Unmanaged DLL Wrapper: Better way?

(BTW this is C# .NET 4.5)
I have some unmanaged DLL that talks to some hardware. I wrap a bunch of code and get something simple, as a class object, that I can create in a WinForm.
private AvaSpec AS = new AvaSpec();
public AvaSpec_Form()
{
InitializeComponent();
AS.SpectrumMeasuredEvent += (se, ev) => { SpectrumMeasured(ev); };
AS.Init(this.Handle);
AS.Activate();
// configure as desired
// AS.l_PrepareMeasData.m_IntegrationDelay = 0;
if (AS.DeviceList.Count > 0)
{
AS.Start();
}
}
However, the DLL relies on receiving messages through WndProc. The best way I could figure out to do this is to overload the WndProc method on the Form:
protected override void WndProc(ref Message m)
{
// catch WndProc messages that AvaSpec defines as its own
if (m.Msg == AvaSpec.WM_MEAS_READY ||
m.Msg == AvaSpec.WM_APP ||
m.Msg == AvaSpec.WM_DBG_INFOAs ||
m.Msg == AvaSpec.WM_DEVICE_RESET )
{
AS.WndProcMessageReceived(ref m);
}
// else pass message on to default message handler
base.WndProc(ref m);
}
How can I hide this overload somehow in the class definition so that the overload method does not need to be added to the Form itself? There is some talk of the IMessageFilter interface, but it still looks to require some code in the form to add the filter. Any ideas on how to make this more elegant?
Ok I figured it out based on Colin Smith's hints.
You derive your class from NativeWindow:
https://msdn.microsoft.com/en-us/library/system.windows.forms.nativewindow(v=vs.110).aspx
Then assign the parent (form) Handle (that you pass by some initialization) to the Handle that NativeWindow provides to the class object. Then, you can overload the WndProc method directly in the object.
// object definition
public class AvaSpec : NativeWindow
{
protected override void WndProc(ref Message m)
{
// catch WndProc messages that AvaSpec defines as its own
if (m.Msg == AvaSpec.WM_MEAS_READY ||
m.Msg == AvaSpec.WM_APP ||
m.Msg == AvaSpec.WM_DBG_INFOAs ||
m.Msg == AvaSpec.WM_DEVICE_RESET)
{
WndProcMessageReceived(ref m);
}
// Call base WndProc for default handling
base.WndProc(ref m);
}
...(snip)
public void Init(IntPtr parentHandle)
{
this.AssignHandle(parentHandle);
...(snip)
and use it (pass handle pointer via some init) like so:
// WinForm definition
public partial class AvaSpec_X : Form
{
private AvaSpec AS = new AvaSpec();
public AvaSpec_X()
{
InitializeComponent();
AS.SpectrumMeasuredEvent += (se, ev) => { SpectrumMeasured(ev); };
AS.Init(this.Handle);
AS.Activate();
// configure as desired
//AS.l_PrepareMeasData.m_IntegrationDelay = 0;
if (AS.DeviceList.Count > 0)
{
AS.Start();
}
}
...(snip)
You could create a hidden modeless "form"/window and then use its .Handle in the call to 'AS.Init'.
By using a separate "window" rather than piggy-backing onto the main application window, it offers a bit better encapsulation.
For example, if in the future you needed to support the handling of multiple devices at the same time...then the "separate" windows would enable good separation of messages for different devices.
Your hardware/device handling code might use wParam or lParam to identify the "device id"...but it's more likely to be using them for something else, and relying on the "window destination" as the distinguisher.
Then let the main apps UI thread message pump...automatically dispatch messages to the windows you have created.
In your message handling code for that "window", you would handle messages, which would include the special privately registered messages such as WM_DBG_INFOAs, etc...which you then forward back to the AvaSpec via WndProcMessageReceived.
If that AvaSpec class is relying on you processing those messages in a timely fashion, then you might need to then explore creating multiple UI threads.
This might be needed if your main apps UI thread was getting overloaded, or was "busy" processing other messages e.g when resizing, moving window, etc.
By having a separate UI thread that is pumping the messages for your hidden "device" window, then it might provide a better response for your "device".
Note: multiple UI threads is an advanced topic, and there are some gotchas, but basically it involves creating a thread, telling it to use the STA (single-threaded apartment), creating your window form, and then usually use Application.Run with that form to cause message pumping.

SendKeys not stopping screensaver coming on [duplicate]

I want to disable the screensaver and monitor power off. At this stage there's no windows form, which I could youse. Thus I wan't to use NativeWindow.
Here's my code
sealed class ObserverWindow : NativeWindow, IDisposable
{
internal ObserverWindow()
{
this.CreateHandle(new CreateParams()
{
Parent= IntPtr.Zero
});
}
public void Dispose()
{
DestroyHandle();
}
protected override void WndProc(ref Message msg)
{
if (msg.Msg == WM_SYSCOMMAND &&
((((long)msg.WParam & 0xFFF0) == SC_SCREENSAVE) ||
((long)msg.WParam & 0xFFF0) == SC_MONITORPOWER))
{
msg.Msg = 0;
msg.HWnd = IntPtr.Zero;
}
base.WndProc(ref msg);
}
}
The Problem is, that the WndProc is not called with WM_SYSCOMMAND. Actualy the WndProc is called 4 times. At the last call there's msg.Msg == WM_CREATE.
I think I'm missing some create parameter. Does anyone have advise?
Regards Michael
UPDATE
I was running the code in a non STA thread. Thus the window did not reveive any messages exept the initial ones. Now I'm receiving WM_SYSCOMMAND messages. But when the screensaver is activated, there's no message.
I also tried to overwrite a Form's WndProc with the same result. But this used to work in Windows XP. Is there a change in Windows 7?
OS: Windows 7 64bit.
SOLUTION
As a comment in this Question states, only the foreground window can cancel the screensaver. Thus the above code can't work. The NativeWindow is great for receiving messages, but not for canceling a screensaver. For latter I recommend the answer to this question.
The proper way to do this is by telling Windows that your thread needs to have the display active. Commonly used by video players. P/Invoke the SetThreadExecutionState() API function, pass ES_DISPLAY_REQUIRED. And ES_SYSTEM_REQUIRED to keep the machine from shutting down automatically. Visit pinvoke.net for the required declarations.
Disabling the screen saver is much easier, according to this KB article:
This can be done easily using:
SystemParametersInfo( SPI_SETSCREENSAVEACTIVE,
FALSE,
0,
SPIF_SENDWININICHANGE
);
[...]
If you need the screen saver to start up again, you'll need to reinitialize the time-out period. Do this by [c]alling SystemParametersInfo (SPI_SETSCREENSAVEACTIVE, TRUE, 0, SPIF_SENDWININICHANGE).
You could try overriding DefWndProc instead.
public override void DefWndProc(ref Message msg)
{
if (msg.Msg == WM_SYSCOMMAND &&
((((long)msg.WParam & 0xFFF0) == SC_SCREENSAVE) ||
((long)msg.WParam & 0xFFF0) == SC_MONITORPOWER))
{
msg.Msg = 0;
msg.HWnd = IntPtr.Zero;
}
base.DefWndProc(ref msg);
}
I'm not on a Windows box right now, so I cannot test this. Let me know if it works.

How can I pass managed objects from one Process to another?

I have two assemblies that I'm trying to link together.
One is a sort of background process that is built with WinForms and will be designed to run as a Windows Service.
I have a second project that will act as a UI for the background process whenever a user launches it.
I've never tried attempting something like this with managed code before, so I've started trying to use windows messages to communicate between the two processes. I'm struggling when it comes to passing more than just IntPtrs back and forth, however.
Here's the code from a control in my UI project that registers itself with the background process:
public void Init()
{
IntPtr hwnd = IntPtr.Zero;
Process[] ps = Process.GetProcessesByName("BGServiceApp");
Process mainProcess = null;
if(ps == null || ps.GetLength(0) == 0)
{
mainProcess = LaunchApp();
}
else
{
mainProcess = ps[0];
}
SendMessage(mainProcess.MainWindowHandle, INIT_CONNECTION, this.Handle, IntPtr.Zero);
}
protected override void WndProc(ref Message m)
{
if(m.Msg == INIT_CONFIRMED && InitComplete != null)
{
string message = Marshal.PtrToStringAuto(m.WParam);
Marshal.FreeHGlobal(m.WParam);
InitComplete(message, EventArgs.Empty);
}
base.WndProc(ref m);
}
This is the code from the background process that's supposed to receive a request from the UI process to register for status updates and send a confirmation message.
protected override void WndProc(ref Message m)
{
if(m.Msg == INIT_CONNECTION)
{
RegisterUIDispatcher(m.WParam);
Respond(m.WParam);
}
if(m.Msg == UNINIT_CONNECTION)
{
UnregisterUIDispatcher(m.WParam);
if(m_RegisteredDispatchers.Count == 0)
{
this.Close();
}
}
base.WndProc(ref m);
}
private void Respond(IntPtr caller)
{
string test = "Registration confirmed!";
IntPtr ptr = Marshal.StringToHGlobalAuto(test);
SendMessage(caller, INIT_CONFIRMED, ptr, IntPtr.Zero);
}
The UI process receives the INIT_CONFIRMED message from my background process, but when I try to marshal the IntPtr back into a string, I get an empty string. Is the area of heap I am using out of scope to the other process or am I missing some security attribute maybe? Is there a better and cleaner way to go about something like this using an event driven model?
Not sure if you want to go this route, but you might have an easier time using WCF as the IPC layer, rather than low-level Windows IPC stuff. You'll need to build and expose interfaces for the service, then connect to them using your UI appklication.
There are a lot of good WCF tutorials out there, if you want to give it a shot.

Internet Explorer Toolbar Tab Key

I've written a IE Toolbar in C# and everything is working fine except that when I open a child Windows Form from my toolbar, the tab key doesn't work on the child form to allow me to move from field to field.
The interesting part is that when I open my child form using form.showDialog() instead of form.show() the tabs work like normal.
The toolbar I've created is based on this article and this article
I've implemented TranslateAcceleratorIO as mentioned in several articles, but still no luck.
Here are my implmentations of TranslateAcceleratorIO() and HasFocusIO() (implemented in my toolband class)
[DllImport("user32.dll")]
public static extern int TranslateMessage(ref MSG lpMsg);
[DllImport("user32", EntryPoint = "DispatchMessage")]
static extern bool DispatchMessage(ref MSG msg);
public int HasFocusIO()
{
return this.ContainsFocus ? 0 : 1; //S_OK : S_FALSE;
}
public int TranslateAcceleratorIO(ref MSG msg)
{
if (msg.message == 0x100)//WM_KEYDOWN
if (msg.wParam == (uint)Keys.Tab || msg.wParam ==(uint)Keys.F6)
{
if (SelectNextControl(
ActiveControl,
ModifierKeys == Keys.Shift ? false : true,
true,
true,
false)
)
{
return 0;//S_OK
}
}
else
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
return 0;//S_OK
}
return 1;//S_FALSE
}
I've also tried having TranslateAccelerator like this with no luck:
public int TranslateAcceleratorIO(ref MSG msg)
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
return 0;//S_OK
}
Has anybody else run into this issue?
Are you also implementing HasFocusIO? I believe your main toolbar class must also implement HasFocusIO and return true.
These types of problems with IE toolbars were the bane of my existence for a while. I think what I eventually ended up doing was creating separate UI threads and making my dialogs modal in those threads, which eliminated a bunch of weird issues. But I think implementing HasFocusIO and TranslateAcceleratorIO should work for this particular one.
Where are you implementing these? It's hard to tell from what you have there, are you implementing them in your Form or are you implementing them in your deskband class?
You need to implement them in your DeskBand implementation, and HasFocusIO needs to return true whenever one of your windows has focus (not just when the toolbar has focus). Then the messages for Tab, Delete, arrow keys, etc should be dispatched to the TranslateAcceleratorIO, also in your deskband, and from there you'll have to pass them along to your form.
The IE plugin framework is incredibly hacky that way.

Categories

Resources