Start a screensaver when explorer is not the shell - c#

I'm running my own kiosk application as the shell (replacing HKLM/Software/Microsoft/Windows NT/winlogon/shell).
The application needs to be able to turn off the monitor and I was using Process.Start("scrnsave.scr") to do this. It works on my dev machine but not when the shell is replaced.
It's clearly because the UseShellExecute is set to true, but when I set it to false I can't get the screensaver to run. Using explorer.exe as the command and scrnsave.scr as the argument just causes an explorer window to open.
Is there a switch I can pass to explorer to get it to run the screensaver or is there another way to achieve the same thing?
Thanks.

You can start the screen saver by sending a windows message to the system.
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_SCREENSAVE, 0)
You will need the following definitions
static readonly IntPtr HWND_BROADCAST = new IntPtr(0xffff);
static readonly IntPtr SC_SCREENSAVE = new IntPtr(0xf140);
const uint WM_SYSCOMMAND = 0x112;
[DllImport("User32",SetLastError=true)]
extern static int SendMessage(
IntPtr hWnd,
uint Msg,
IntPtr wParam,
IntPtr lParam);
Which you can then use as follows
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_SCREENSAVE, IntPtr.Zero);

Related

WH_KEYBOARD with Alt+Tab stop working

When I set up non-global WH_KEYBOARD hook, it works fine and all keys are catched. But if I press Alt+Tab and then return to the window, hook stops its working with no reason.
This is my hook proc where I'm trying to block all keyboard messages for proccess with id = root:
private static IntPtr HookCallback (int nCode, IntPtr wParam, IntPtr lParam)
{
var proc = 0u;
GetWindowThreadProcessId(GetForegroundWindow(), out proc);
if (proc != root) return CallNextHookEx(hooks[0], nCode, wParam, lParam);
return new IntPtr(1);
}
For developing I use 32bit Windows in VirtualBox.
UPDATE:
It also doesn't depend on blocking or passing parameters to the next hook: code variant that do nothing then calling next hook stops working after Alt+Tab too. Losing focus and activating of the window doesn't stop hook if it was done not with Alt+Tab.
After looking for some samples and analysing my code I've found how to solve this "bug". I should set last two parameters in SetWindowsHookEx function in such way:
SetWindowsHookEx(HookType.WH_KEYBOARD, HookCallback,
IntPtr.Zero, GetCurrentThreadId());
but not like this:
SetWindowsHookEx(HookType.WH_KEYBOARD, HookCallback,
GetModuleHandle(curModule.ModuleName), 0);

Using SendMessage() to minimize all windows, but need a more efficient way than Thread.Sleep() to wait until the legacy desktop is showing

In my C# console application, I am using SendMessage() to minimize all windows, effectively showing the Windows 8 Legacy Desktop. This works great, but I have to use a Thread.Sleep(1000) in order to wait for the Legacy Desktop to actually show before before I try to do anything else.
IntPtr lHwnd = FindWindow("Shell_TrayWnd", null);
SendMessage(lHwnd, WM_COMMAND, (IntPtr)MIN_ALL, IntPtr.Zero);
Thread.Sleep(1000);
I really want to replace the Thread.Sleep() with a more efficient way to detect that the Legacy Desktop is showing before continuing on.
Any ideas?
Edit:
Here are the Interop wrappers and constants. just in case it helps..
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true)]
static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, IntPtr lParam);
const int WM_COMMAND = 0x111;
const int MIN_ALL = 419;
const int MIN_ALL_UNDO = 416;
I'm not sure if this will work any better for you, but perhaps it's worth a try...
(1) Add to your project a reference to "Shell32" (via Add Reference -> COM -> Microsoft Shell Controls and Automation).
(2) Set the reference's "Embed Interop Types" to false.
(3) Use the following code to minimise all the windows:
dynamic shell = new Shell32.ShellClass();
shell.MinimizeAll();
However, I suspect that this is just an alternative way of doing the SendMessage().

How to close the window by its name?

I want to close window with some name (any application, for example, calculator and etc.). How to do it in C#? Import WinAPI functions?
Yes, you should import the Windows API functions: FindWindow(), SendMessage(); and WM_CLOSE constant.
Native definitions of the Windows API functions:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
/// <summary>
/// Find window by Caption only. Note you must pass IntPtr.Zero as the first parameter.
/// </summary>
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
const UInt32 WM_CLOSE = 0x0010;
Client code:
IntPtr windowPtr = FindWindowByCaption(IntPtr.Zero, "Untitled - Notepad");
if (windowPtr == IntPtr.Zero)
{
Console.WriteLine("Window not found");
return;
}
SendMessage(windowPtr, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
You're trying to close windows belonging to other processes. That isn't something you can assume will go reliably. For one thing, YOU don't own those windows so YOU don't really have any automatic entitlement to go and mess with the other processes' windows.
As the other answer suggests, you can try sending a WM_CLOSE to the window but it comes with the caveat that the other process isn't really entitled to honour it. The response to WM_CLOSE can be anything to acceptance and a clean shutdown to outright rejection. In the latter case, you've really got no option. It's not your process. In between, as you've seen, there could be any sort of intermediate windows, dialog boxes, etc, that you'd have to contend with.
So what are you trying to achieve here? Why are you trying to close windows belonging to other processes? It might help to clarify what the aim is.

How to send keyboard key in my application?

I'm currently using SendKeys.SendWait(text); in C#
but SendKeys sending the key global and I have to activate my application and then send it. And another problem is when I type something in my keyboard (in another app) and the SendKeys function activates (in my app) mistakes happen.
So how can I send a message to my application regardless what application is active and what I type in my keyboard?
SendMessage() does what you want. You'll need to use it like:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
const UInt32 WM_CHAR = 0x0102;
const int VK_Q = 0x51; // taken from http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx
SendMessage(handleToTheInputForm, WM_CHAR, VK_Q, 1);
You will need to get a handle on the other application's window so that you can bring it to focus and reliably send your keystrokes to it,
Have a look at this tutorial
http://www.codeproject.com/KB/cs/SendKeys.aspx

Send Keystrokes to a program even if its in background using c#

I wanna send key stroke to a program even if it is running in background. But I can do this only for NOTEPAD like this,
[DllImport("user32.dll")]
protected static extern byte VkKeyScan(char ch);
[DllImport("user32.dll", SetLastError = true)]
protected static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.Dll", EntryPoint = "PostMessageA")]
protected static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
char Key = // key value to send
IntPtr hWnd = FindWindowEx(_handle, IntPtr.Zero, "edit", null); // _handle is the windows handle of the program (here its notepad)
PostMessage(hWnd, WM_KEYDOWN, VkKeyScan(Key), 0);
But for all other applications I can't send keystrokes if its in background. Since I don't know the lpszClass of that program (I think this is the userControl name of the typing area in that program. For NotePad it is "edit". I found this surfing internet).
For all other applications what I'm doing is, get the application to foreground, then send the key, then again get my program foreground. I need my program to be run as foreground always.
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
SetForegroundWindow(_handle); // _handle is the windows handle of the program
System.Threading.Thread.Sleep(50); // Waiting few milliseconds till application coming to foreground.
wsh.SendKeys(Key.ToString(), ref wait); // wsh is WshShellClass wsh= new WshShellClass();
SetForegroundWindow(_mainHandle); // _mainHandle is the windows handle of my application
But this way is not working. some keys getting missed and the program foreground->background->foregound->background...... like its dancing...
How to send keys to other applications if its running in background.
or are there any way/source to find the lpszClass of a program ?
Sorry if I have missed any required information. this is a large application. I have posted only required parts here. If someone needs any additional information, pls ask.
I think you'll need to have the background program install a low-level keyboard hook via the win32 function SetWindowsHookEx().
Here's the MSDN documentation for SetWindowsHookEX()
http://msdn.microsoft.com/en-us/library/ms644990(v=vs.85).aspx
And here's the KB article on how to do it from C#
http://support.microsoft.com/kb/318804
This article goes into some detail, too: http://www.codeguru.com/columns/vb/article.php/c4829
I expect your app will get caught by various spyware/anti-virus software as a keyboard logger, though.
Good luck.
You may be able to figure out the lpszClass of the program using an inspection tool such as WinSpy++. It gives you a crosshair that you can drag and position over the desired control. This was able to easily provide me with the "edit" class name for notepad.
If things aren't working, click the "More>>" button in the lower right of WinSpy++, then click the "Locate" button to view the control hierarchy; you may need to post the WM_KEYDOWN message to one of the parent or child controls instead.

Categories

Resources