I have an application which monitors touchscreen messages in a Windows tablet. I want to wake up some hardware when the user touches the touchscreen. I have used the approach from Using Raw Input from C# to handle multiple keyboards.
I call RegisterRawInputDevices() to register to receive touchscreen messages:
var rid = new RawInputDevice[1];
rid[0].UsagePage = 13; // HidUsagePage.Digitizer
rid[0].Usage = 4; // HidUsage.TouchScreen
rid[0].Flags = 0x00000100; // RawInputDeviceFlags.InputSink
rid[0].Target = this.Handle;
if (!RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0])))
{
// report error
}
I then receive WM_INPUT messages in my message pump:
protected override void WndProc(ref Message message)
{
switch (message.Msg)
{
case WmInput:
// handle touch messages
break;
}
base.WndProc(ref message);
}
This works fine most of the time. I can touch anywhere on the screen and my application gets a WM_INPUT message. But if I run Windows Device Manager, I do not get touch messages when I touch inside the Device Manager.
I have tested this with the Microsoft Digiinfo tool, and it has the same behaviour.
I also see the same behaviour with the Computer Management application.
Is there a class of applications that can block WM_INPUT messages? Is there some way around this problem? I may just have to accept this behaviour, but I would still like to understand it.
Related
I coded with c# in visual studio, windows form application. I want to see pid and vid of a USB when ıt is plugged in. I wrote this code but there is an error in foreach (ManagementObject service in s.Get()). In s.Get() part. It runs in Form1_Load part but it gets stuck in WNDProc.
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if(m.Msg == WM_DEVICECHANGE)
switch ((int)m.WParam)
{
case DBT_DEVICEARRIVAL:
listBox1.Items.Add("New Device Connected");
ManagementObjectSearcher s = new ManagementObjectSearcher("#SELECT * FROM Win32_USBHub");
foreach (ManagementObject service in s.Get())
{
listBox1.Items.Add(service);
}
string[] ports = SerialPort.GetPortNames();
Console.WriteLine("The following serial ports were found:");
foreach (string port in ports)
{
Console.WriteLine(port);
listBox1.Items.Add(port);
}
break;
case DBT_DEVICEREMOVECOMPLETE:
listBox1.Items.Add("Device Removed");
break;
}
The main issue is that the WM_DEVICECHANGE only comes for information you registered, with a few exceptions as can be read in the remarks of RegisterDeviceNotification.
Here are the details what you need to do:
To get the WM_DEVICECHANGE with DBT_DEVICEARRIVAL for devices, you need to call the Win32 API in user32.dll called RegisterDeviceNotification with a correctly filled DEV_BROADCAST_DEVICEINTERFACE_W struct.
If done so correctly you will get WM_DEVICECHANGE messages, which contain the event type (in our case DBT_DEVICEARRIVAL) as described in the Device Management Events, and a pointer to details. The pointer needs to be read as the DEV_BROADCAST_HDR struct , allowing you to recognise if this is indeed the DEV_BROADCAST_DEVICEINTERFACE_W struct. If so this struct will contain a name, which you will need to parse at it contains the VID & PID.
That is quite a lot to process, and it took me a couple of hours to get it right. If you need a quick solution, and skip implementing the horrible details, add the NuGet package Dapplo.Windows.Messages (VID & PID are available with 0.9.7 and later) to your project. Use the following code only once, otherwise your code will be called multiple times, there is no need to do this from a Window but it must be from a Windows Forms or WPF application:
var deviceNotificationSubscription = DeviceNotification
.OnDeviceArrival()
.Subscribe(deviceInterfaceChangeInfo => {
// Your code goes here, and will be automatically called
var vid = deviceInterfaceChangeInfo.Device.VendorId;
var pid = deviceInterfaceChangeInfo.Device.ProductId;
});
My library highly depend on System.Reactive, I won't go into details here, which allows a more functional approach to your application. You can stop receiving the events by calling deviceNotificationSubscription.Dispose(); The library creates it's own hidden message window to receive the window messages, so you can even continue receiving the information in the background.
The Device property of the DeviceInterfaceChangeInfo has the DevBroadcastDeviceInterface struct, which contains the original Win32 information, but additionally has some higher level properties like:
a friendly name, which is retrieved from the registry
device type like USB, HID etc including an IsUSB
vendor ID
product ID
a DeviceInterfaceClass enum for easier code access to the class
a generated URL to get more information on the device
Let me know if this works and helps here by and if you have any questions raise an issue on my Dapplo.Windows GitHub project! There is a lot more in this library but unfortunately most documentation still needs writing.
I want to have my app open up every single time the device is unlocked. Effectively, I need a consistent replacement for ACTION_USER_PRESENT.
(NOTE THIS IS FOR AN INTERDISCIPLINARY, PEER-REVIEWED ACADEMIC STUDY STARTING SOON AND IS VITAL FOR THE STUDY'S SUCCESS)
Before the Oero 8.0 update, ACTION_USER_PRESENT was a perfect way to start up the android app each time the device was unlocked.
Unfortunately the work-arounds I've been trying to use are just not cutting it. Effectively I've assigned a myBroadastReceiver to attempt to run the app and PowerManager to see if the device is on or not. Depending on if the device is being used will impact if in the myBroadcastReceiver code will Initiate an Intent.
Problem 1) The broadcast receiver can only be assigned to run at minimum every 15 minutes. I need it to run every time the device unlocks.
Problem 2) Sometimes the broadcast receiver doesnt even try to run for hours at a time... as if the assigned 15 minute check is more of a loose suggestion and not an explicit command.
SOME CODE:
public class classMyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context contextOfReceive, Intent intentOfReceive) {
////////////////////////////////////////////////////////////////////////////////////////////
//This loads up the user selected settings choosen at the homepage of the application.
final SharedPreferences internalAppInformation = contextOfReceive.getSharedPreferences("userPreferences", Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = internalAppInformation.edit();
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
//Code used to determine 2 things
// 1) if the Device being used or inactive
// 2) if the activity has already been prompted earlier and therefore should be in the foreground of the device
PowerManager pm = (PowerManager) contextOfReceive.getSystemService(Context.POWER_SERVICE);
boolean booleanIsScreenOn = pm.isInteractive();
boolean booleanIsActivityUp = internalAppInformation.getBoolean("booleanIsActivityUp", false);
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
//If Screen is Off (i.e. the device is NOT BEING USED AT THE MOMENT)
//then this code should allow the Activity to Start
if ( (!booleanIsActivityUp)&&(!booleanIsScreenOn) ) {
//Initiates and Starts up the Intent PromptAndClose.class
editor.putBoolean("booleanIsActivityUp", true);
editor.commit();
editor.apply();
//THE REST OF THE CODE BELOW IS JUST CHOOSING AND
// INITIATING THE PROGRAM AND IS NOT PROBLEMATIC.
}
}
More detailed code can be provided if it will be helpful. I am worried that more code will result it too much clutter for the reader.
ADDITIONAL CODE TO DESCRIBE WHEN THE myBroadcastReceiver is Initiated.
public class Settings extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
////////////////////////////////////////////////////////////////////////////////////////////
//Sets up and starts the calendar (with the setAlarm method for re-occuring attempts to
//prompt the app to move to the foreground if the right conditions are met.
Calendar calendar = Calendar.getInstance();
//if(Build.VERSION.SDK_INT >= 23) {
Log.i("Calendar", "Set Calendar >=23");
calendar.set(
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH),
calendar.get(Calendar.HOUR),
calendar.get(Calendar.MINUTE),
30
);
setAlarm(calendar.getTimeInMillis());
int time = (int) calendar.getTimeInMillis();
String timeString = String.valueOf(time);
Log.i("TIME", "time: " + timeString);
}
private void setAlarm(long timeInMillis) {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, classMyBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
assert alarmManager != null;
//RTC-Fires the pending intent at the specified time but does not wake up the device.
//The shortest interval is INTERVAL_FIFTEEN_MINUTES.
alarmManager.setInexactRepeating(AlarmManager.RTC, timeInMillis,
AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);
}
}
This code is present in the main activity of the application. The concept is that the first time the app is installed and ran, it will run this code and start and continuous loop of checking and displaying the app to the foreground of the device if the device is not being used. Once that intent is interacted with by the user and closed, the loop starts up again.
That is not going to work. Doze mode and app standby will make what you are trying to do very unreliable.
Try this: Create a foreground service. Start that foreground service when you need to start receiving this broadcast. In onCreate() of that service, call registerReceiver() register a receiver for ACTION_USER_PRESENT. So long as your service is running, you will receive the ACTION_USER_PRESENT broadcast as before.
We're sending a Win32 message from one process (process01) to another (process02).
Console.WriteLine(targetHandle); // 0x3072a
SendMessageTimeout(
targetHandle,
WM_COPYDATA,
IntPtr.Zero,
ref cds,
SendMessageTimeoutFlags.SMTO_NORMAL,
timeoutMs,
out result);
We've established that process01 is sending to the correct handle. Sometimes the message arrives at process02 and other times it doesn't arrive.
// SomeForm.cs
protected override void WndProc(ref Message m) {
// Sometimes the message arrives here
Console.WriteLine(m); // 0x3072a
}
When the message does not arrive at process02, there is no error message in process01. It simply fails silently.
What could be causing this? How can we further troubleshoot this? We have used Spy++ to search for and to listen to the messages to the receiving handle. Spy++ always finds the process by its handle. When the message does not show up in SomeForm.WndProc, it also does not show up in the Spy++ messages.
The problem was permission elevation:
the sending session was not elevated, and
the receiving session was elevated (i.e. run as administrator).
I am using the following code to handle taskkill on my process:
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
private class TestMessageFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == /*WM_CLOSE*/ 0x10)
{
MessageBox.Show("I'm shutting down");
var mailService = new MailService();
mailService.SendEmail("Test from application exit");
//Application.Exit();
return true;
}
return false;
}
}
and then
static void Main(string[] args)
{
Application.AddMessageFilter(new TestMessageFilter());
Application.Run();
}
The MessageBox pops up and the email is sent when I do taskkill /im MyProcess.exe. However this does not happen on windows shutdown.
Does Windows kill processes forcefully on shutdown or is it me who's missing something?
That you can see WM_CLOSE at all in an IMessageFilter is quite accidental and an implementation detail of taskkill.exe. You normally only see posted messages, WM_CLOSE is normally sent. I think you see taskkill.exe first trying to ask nicely, only using the sledge-hammer when the app doesn't respond fast enough. Task Manager used to do this as well but doesn't anymore in later Windows versions.
And no, it certainly can't work on a Windows shutdown. It sends a WM_QUERYENDSESSION message to a window to announce the shutdown.
Lots of good reasons to make this a service instead. But as long as you want to do it this way then you need a window to see that message. Subscribe its FormClosing event, the e.CloseReason property tells you why it is closing down. You'll see CloseReason.WindowsShutDown. You just need to keep the window invisible to keep it equivalent to what you have, override the SetVisibleCore() method as shown in this post.
The general pattern operating systems use is to request that running processes terminate gracefully, then kill them if they don't terminate within a timeout. Some applications will pop up a save changes prompt on shutdown, but they may not actually appear to the user - Windows can display a "shutting down" screen and say that some processes are still running - do you want to kill them and shut down anyway?
I believe if you're using Windows Forms you can achieve the same result as you have here with the Closing/Closed events*, so you could see if either of those fire by saving some text to a file (and make sure to flush it), and also see if you get any other message codes in PreFilterMessage in the same way.
*You could get either Closing or Closed or both, so check both. e.g. you can get a Closed without a prior Closing.
I'm using this(link) library to detect attach and detach events of USB devices. After detecting the right device attached(identified with specific VID/PID combination) I open a serial port connection and similarly when the device is detached I close the serial port connection.
My attach event works great and at the end I get a serial port that I can use but I'm having problems inside the detach event. The detach event fires correctly but when code execution reaches closeCOM(serialPort1) point it jumps to wndProc override loop and prevents execution of closeCOM() and whatever follows.
The library needs WndProc messages to detect the events and my code is implemented like this:
//Catch Windows messages and pass them to the USBClass class
protected override void WndProc(ref Message m)
{
USBPort.ProcessWindowsMessage(ref m);
base.WndProc(ref m);
}
Then I have a detach event which executes the following code:
if (!USBClass.GetUSBDevice(VID, PID, ref USBDeviceProperties, false) && USBDeviceConnected)
{
//Device is removed
USBDeviceConnected = false;
//Close COM port just in case we forgot to disconnect
closeCOM(serialPort1);
//update status strip
strip_device_status.Text = "Disconnected";
}
and here is the closeCOM function:
//This function handles COM port closing.
private void closeCOM(SerialPort port)
{
// If a serial port is open, disconnect it
if (port.IsOpen)
{
// close the serial port
port.Close();
}
//update com port status flag
COMConnected = false;
//update status strip
strip_COM_status.Text = "Disconnected";
}
It is closeCOM() in particular that's causing this "conflict" because if I comment out that line everything works, except I'm left with an open serial port possibly causing errors later on. What am I doing wrong that's causing the code to jump to WndProc override instead of normal execution? I would like to be able to do the port closing in the detach event.