I need to know when the user switches to the logon screen (as triggered by ctrl-alt-del) in order to circumvent a pesky bug in WPF. I want to work around this bug by reinitializing my GUI after returning from the logon screen. Currently it works, but I have to trigger it manually.
I have found SystemEvents.SessionSwitch, but unfortunately this is only triggered when logging off.
How can I detect when the logon screen is displayed by forming ctrl-alt-del?
The tricky thing is that this is not a session change, but rather just a desktop change. In particular, Ctrl+Alt+Del switches to a secured desktop associated with Winlogon.
I don't think you're really supposed to detect this kind of thing (that is, after all, the whole point of having a "secure desktop"), but you could probably do it using an Active Accessibility hook. Call the SetWinEventHook function to install an event hook for the EVENT_SYSTEM_DESKTOPSWITCH event and see what notifications you receive.
To get it going, you'll need to do the following:
Ensure that you're pumping a message loop on your client thread in order to receive event notifications. This shouldn't be a problem for a standard WPF application.
Make sure that you specify the WINEVENT_OUTOFCONTEXT flag, considering that you're working from managed code. You don't want the system to attempt to inject your DLL that contains the callback function into every process. Instead, this will cause the callback function to be called asynchronously from a queue; much safer from the land of managed code.
A little bit of P/Invoke magic. To get you started…
const uint WINEVENT_OUTOFCONTEXT = 0x0;
const uint EVENT_SYSTEM_DESKTOPSWITCH = 0x0020;
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin,
uint eventMax,
IntPtr hmodWinEventProc,
WinEventDelegate lpfnWinEventProc,
uint idProcess,
uint idThread,
uint dwFlags);
delegate void WinEventDelegate(IntPtr hWinEventHook,
uint event,
IntPtr hwnd,
int idObject,
int idChild,
uint dwEventThread,
uint dwmsEventTime);
[DllImport("user32.dll")]
static extern bool UnhookWinEvent(IntPtr hWinEventHook);
The process which gets started to show the logon screen seems to be called LogonUI.exe.
Using the Windows Management Instrumentation (WMI) infrastructure you can listen for processes which start and shut down. You will need to reference the System.Management assembly.
var interval = new TimeSpan( 0, 0, 1 );
const string isWin32Process = "TargetInstance isa \"Win32_Process\"";
// Listen for started processes.
WqlEventQuery startQuery
= new WqlEventQuery( "__InstanceCreationEvent", interval, isWin32Process );
_startWatcher = new ManagementEventWatcher( startQuery );
_startWatcher.Start();
_startWatcher.EventArrived += OnStartEventArrived;
// Listen for closed processes.
WqlEventQuery stopQuery
= new WqlEventQuery( "__InstanceDeletionEvent", interval, isWin32Process );
_stopWatcher = new ManagementEventWatcher( stopQuery );
_stopWatcher.Start();
_stopWatcher.EventArrived += OnStopEventArrived;
Handling these events, you can get information about the started or closed process. This way you can verify when LogonUI.exe was shut down, and subsequently trigger the required actions.
void OnStopEventArrived( object sender, EventArrivedEventArgs e )
{
var o = (ManagementBaseObject)e.NewEvent[ "TargetInstance" ];
string name = (string)o[ "Name" ];
...
}
Related
I sent a WM_ACTIVE message using postmessage api to some programs.
When a program is deactivated, sending a message does not actually activate the window, but the program thinks it is active. ( It actually succeeded. )
However, I think it is very inefficient to send postmessage regularly.
If I want to check the WM_ACTIVE value of the program and it is inactivated, I try to send a WM_ACTIVE message again using the POSTMESSAGE API to confuse the program itself with being active, but I can't think of a way. Although there is an idea that hooking would be easy to use, C# did not support other types of global hooking except for the keyboard and mouse.
Can anyone come up with any other ideas? please help me.
To check if a process is focused you should use GetForegroundWindow to get the focused window handle and then use GetWindowThreadProcessId to get the process from that window handle:
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(int hWnd, out int ProcessId);
IntPtr focusedWindow = GetForegroundWindow(); //get the focused window
int focusedProcessID = 0;
GetWindowThreadProcessID(focusedWindow, out focusedProcessID); //get it's process id
Process focusedProcess = Process.GetProcessById(focusedProcessID);//get the focused process
Console.WriteLine("Current Focused Process:" + focusedProcess.ProcessName);
I was wondering if there are any examples and/or documentation on how to handle Plug and Play event messages used in Windows. Ideally what I am trying to accomplish is to be able to have my application detect a device that has been connected to a machine without having to have a timer, that on tick, will poll ALL COM ports. I find that doing this is extremely inefficient and ramps up my application's CPU usage ten fold. My application is in C# and is currently leveraging .NET 4.0 we are looking to upgrade to .NET 4.5 within the next month. So I am reaching out to find some kind of literature on how to do this. As this is my fist look into supporting a plug and play devices please be gentle with the criticism.
EDIT: Also this application will be running on Windows 7 and Windows XP
I've accomplished this in the past when writing a file browser by using a dummy HwndSource and adding an event handler via the HwndSource.AddHook() method.
// In object constructor
var hwndSource = new HwndSource(0, 0, 0, 0, 0, "", IntPtr.Zero); // Set up dummy HwndSource
hwndSource.AddHook(sourceHook);
IntPtr sourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg = WM_DEVICECHANGE)
if (wParam.ToInt32 == DBT_DEVICEARRIVAL) // Do what you need to do
if (wParam.ToInt32 == DBT_DEVICEREMOVALCOMPLETE) // Handle device removal
}
// Uses these defined constants:
private const int WM_DEVICECHANGE = 0x219;
private const int DBT_DEVICEARRIVAL = 0x8000;
private const int DBT_DEVICEREMOVALCOMPLETE = 0x8004;
The MSDN for WM_DEVICECHANGE also has info for other const definitions that may be useful:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v=vs.85).aspx
According to my research, when I run C# executable which opens WinForm, within .NET, they don't offer the function to access those WinForm object from separate c# process (separate file I mean) but win32 API does.
Then I came across 3 functions from API.
FindWindow();
GetWindowLong();
CallWindowProc()
I need to call it from top down to the bottom but then I got stuck by CallWIndowProc() because
I can't figure what I should pass for last 3 arguments.
private static extern UIntPtr CallWindowProc(IntPtr a, IntPtr b, uint c, IntPtr d, IntPtr e);
c, d and e
According to the doc, it should be some sort of "message" which is int. But where can I get such value???
http://msdn.microsoft.com/en-us/library/ms633571(v=vs.85).aspx
Code:
[DllImportAttribute("User32.dll")]
private static extern IntPtr FindWindow(String ClassName, String WindowName);
[DllImportAttribute("User32.dll")]
private static extern long GetWindowLong(IntPtr a, int b);
[DllImportAttribute("User32.dll")]
private static extern UIntPtr CallWindowProc(IntPtr a, IntPtr b, uint c, IntPtr d, IntPtr e);
[STAThread]
static void Main(string[] args)
{
IntPtr lResult;
uint lMsg = 0;
IntPtr HWND = FindWindow("WindowsFormsApplication1.Form1", "Form1");
int GWL_WNDPROC = -4;
long WNDPROC = GetWindowLong(HWND, GWL_WNDPROC);
lResult = CallWindowProc(WNDPROC, HWND, lMsg, 0, 0);
}
Clarification
OK.. I should have made it clear.. my goal is to run following chunk of code against the WebForm being executed. (I'ts WatiN)
var t = new Thread(() =>
{
Settings.AutoStartDialogWatcher = false;
var ie = new IE(form1.webBrowser1.ActiveXInstance);
ie.GoTo("http://www.google.com");
ie.TextField(Find.ByClass("lst")).TypeText("this is awesome!!");
ie.Button(Find.ByName("btnG")).Click();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
What message you are trying to send to callWinProc?
Arguments are
nProc is a value returned previously by SubClassWindow() (Source Window).
hWnd is the handle to the window that was subclassed (target window).
nMsg is the message (one of the WM_* values defined in WINDOWS.CH, basically kind of event or message like click is one message). For complete system messages see http://msdn.microsoft.com/en-us/library/ms644927(v=vs.85).aspx#system_defined
wParam depends on nMsg. For click, it takes left or right click
lParam depends on nMsg. for click it takes the location as lparam
you can see wparam and lparam defination for each message.
It looks like you're trying to call the window proc of a window from a different thread/process. I'm assuming this because you're using FindWindow, and I can't see where you created the window. If that is what you are doing, CallWindowProc won't work because you cannot call a window proc from a thread other than the one that created the window. What you need is SendMessage, which accepts the same last four parameters (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) - to interpret them you need to know what message you're sending.
I recommand to use the parameter names from the native methode just for clearness. You can get those pinvoke signatures from pinvoke.net so you don't have to do it on your own all the time. These messages are definded in header files and documented in the msdn. Its quiete hard to use the right message in the correct manner if you're new to win32 and/or C#.
If you want to intercept the windows messages of your form you need a windows message hook, but this doesn't work in .Net. You can also read this article which cover this topic.
Maybe you should try to find a complete different solution for your problem. Other IPC methodes etc.
EDIT: The CLR type of your form (WindowsFormsApplication1.Form1) is not the class name you have to put in FindWindow, FindWindow is an unmanaged api and isn't aware of the CLR typesystem. Try out Spy++ to investigate some windows on your PC.
The desktop application I'm developing need to know what windows were active while the application was run. Currently it performs GetForegroundWindow() call (of user32.dll) every 250 msec. The approach is not very accurate.
Is there any Windows (WINAPI?) event which fires every time the active (focused) window changed? I'd like to subscribe with my callback function.
Thanks.
Yes, you can use SetWinEventHook function.
hEvent = SetWinEventHook(EVENT_SYSTEM_FOREGROUND ,
EVENT_SYSTEM_FOREGROUND , NULL,
WinEventProcCallback, 0, 0,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
.......
VOID CALLBACK WinEventProcCallback ( HWINEVENTHOOK hWinEventHook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
/* your code here */
}
There's the WM_ACTIVATE message, which is sent to the activated and deactivated windows.
Here’s the situation:
We have a 3rd party application that intermittently displays an error message. Usually the error occurs when no one is in the office, so we don’t know exactly what time the message box is popping up. We are working with our vendor to determine what the issue is, and they want to know exactly when the error is occurring so we can provide them with network conditions etc… at the time of the error. The error message is not logged anywhere by the application, so I have been tasked with somehow logging when it occurs.
I have C#.NET as my tool. So far the closest things I have found to a solution are FindWindow and EnumChildWindows or hooking into Windows messages. I am a recent college grad and just started my job so both of these routes will be fairly complicated for me. Before I invest a lot of time trying to learn what I need to try to make one of those methods work, I wanted to check here and see if there was a simpler solution.
Really all I need is to log when a message box appears and some identifying information about the message box. It isn’t necessary to log only messages from the application in question.
Thank you for your help. Please let me know if I need to clarify anything.
EDIT:
I've tried to code something with Hans' suggestions and references. I relied pretty heavily on his code sample. Right now I have a form that will accept a process name. Clicking a button will create an instance of the following class. I did some testing with Notepad, but it just cycled through the findMessageBox method even when I had a dialog box open. I tried using EnumChildWindows instead of EnumThreadWindows and the same thing happened. I confirmed that the program had the correct PID with Spy++. I'd appreciate any suggestions on what I need to fix.
EDIT:
It's working now. Thank you so much for your help. I was passing the wrong value from GetWindowProcessThreadId to EnumThreadWindows. I still will be working on it some as I can clean it up some and I don't want an open dialog logged continuously, but those are trivial things. I've posted the code I have now with the primary funcionality just in case anyone else has to do a similar thing in the future:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
namespace LogDialog
{
class DialogLogger
{
TextWriter log = new StreamWriter(#"C:\ErrorLog\ErrorLog.txt");
private Timer mTimer;
private uint lpdwProcessId;
private IntPtr mhwnd;
uint threadID;
//*************P/Invoke Declarations*************//
private delegate bool EnumThreadWndProc(IntPtr hwnd, IntPtr lp);
private delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lp);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern bool EnumThreadWindows(int dwThreadId, EnumThreadWndProc callback, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hwnd, StringBuilder buffer, int buflen);
//Retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window.
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint lpdwProcessId);
//***********************************************//
//Constructor; initiates timer
public DialogLogger(string processName)
{
setWindowProcessID(processName); //set process ID
mTimer = new Timer(); //create timer for logging
mTimer.Interval = 50; //set interval
mTimer.Enabled = true; //enable
mTimer.Tick += new EventHandler(findMessageBox); //set event handler
}
private void setWindowProcessID(string processName)
{
mhwnd = Process.GetProcessesByName(processName)[0].MainWindowHandle;
threadID = GetWindowThreadProcessId(mhwnd, out lpdwProcessId);
}
//Enumerates windows to find a message box
private void findMessageBox(object sender, EventArgs e)
{
EnumThreadWndProc callback = new EnumThreadWndProc(checkDialogWindow);
EnumThreadWindows((int)threadID, callback, IntPtr.Zero);
GC.KeepAlive(callback);
}
//Checks if hwnd is a dialog
private bool checkDialogWindow(IntPtr hwnd, IntPtr lp)
{
StringBuilder sb = new StringBuilder(260);
GetClassName(hwnd, sb, sb.Capacity);
if (sb.ToString() != "#32770") return true;
log.WriteLine("Error Logged: {0}", DateTime.Now.ToLongTimeString());
return false;
}
}
}
They are jerking you around, knowing full well that this is not that easy to implement. It is utterly trivial for them to add the logging, they should already have done so if their app is that sensitive to network conditions. The most positive view on this request is that they'll hope you'll figure this out by yourself from trying to make this work. Could happen. Talk to your supervisor and point this out.
How about this simple approach: create a screen capture every 2 minutes and just check the image files the next day?
If you can attach a debugger, it should be rather trivial :)