I am trying to connect to a USB device that is detected as a CDC device on my system using the following code :
(I have presented only the part of the code relevant to my problem)
The code compiles fine and SetupDiGetClassDevs function runs ok too.
But SetupDiEnumDeviceInterfaces always returns false and because of this I am not able to move any further. Please tell me where it is wrong. Thanks.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Runtime.InteropServices;
using System.IO.Ports;
//**************************************************************
// Static class for access to USB dll for all the activity
// related to USB device
//**************************************************************
namespace USBDeviceConnect
{
#region Unmanaged
public class Native
{
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetupDiGetClassDevs(
ref Guid ClassGuid,
IntPtr Enumerator,
IntPtr hwndParent,
UInt32 Flags);
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
public static extern bool SetupDiEnumDeviceInterfaces(
IntPtr hDevInfo,
SP_DEVINFO_DATA devInfo,
ref Guid interfaceClassGuid,
UInt32 memberIndex,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
[DllImport(#"setupapi.dll", CharSet = CharSet.Auto)]
public static extern Boolean SetupDiEnumDeviceInterfaces(
IntPtr hDevInfo,
IntPtr devInfo,
ref Guid interfaceClassGuid,
UInt32 memberIndex,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
public static extern int SetupDiDestroyDeviceInfoList(
IntPtr DeviceInfoSet);
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
public static extern bool SetupDiEnumDeviceInfo(
IntPtr DeviceInfoSet,
UInt32 MemberIndex,
ref SP_DEVINFO_DATA DeviceInfoData);
//SP_DEVINFO_DATA
[StructLayout(LayoutKind.Sequential)]
public struct SP_DEVINFO_DATA
{
public int cbSize;
public Guid ClassGuid;
public int DevInst;
public ulong Reserved;
}
[StructLayout(LayoutKind.Sequential)]
public class SP_DEVICE_INTERFACE_DATA
{
public int cbSize;
public Guid interfaceClassGuid;
public int flags;
public ulong reserved;
};
//PARMS
public const int DIGCF_ALLCLASSES = (0x00000004);
public const int DIGCF_PRESENT = (0x00000002);
public const int DIGCF_PROFILE = (0x00000008);
public const int DIGCF_DEVICEINTERFACE = (0x00000010);
public const int INVALID_HANDLE_VALUE = -1;
public const int MAX_DEV_LEN = 1000;
public const int DEVICE_NOTIFY_WINDOW_HANDLE = (0x00000000);
public const int DEVICE_NOTIFY_SERVICE_HANDLE = (0x00000001);
public const int DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = (0x00000004);
public const int DBT_DEVTYP_DEVICEINTERFACE = (0x00000005);
public const int DBT_DEVNODES_CHANGED = (0x0007);
public const int WM_DEVICECHANGE = (0x0219);
public const int DIF_PROPERTYCHANGE = (0x00000012);
public const int DICS_FLAG_GLOBAL = (0x00000001);
public const int DICS_FLAG_CONFIGSPECIFIC = (0x00000002);
public const int DICS_ENABLE = (0x00000001);
public const int DICS_DISABLE = (0x00000002);
public const long ERROR_NO_MORE_ITEMS = 259L;
public const int ERROR_SUCCESS = 0;
}
#endregion
/****************************************************************************/
static class AccessUSB
{
public static void Main()
{
ConnectToDevice();
}
/* Execution starts here */
public static void ConnectToDevice()
{
/* Get the info of all connected devices */
//Globally Unique Identifier (GUID) for CDC class devices.
Guid InterfaceClassGuid = new Guid("a5dcbf10653011d2901f00c04fb951ed");
IntPtr DeviceInfoTable = (IntPtr)Native.INVALID_HANDLE_VALUE;
Native.SP_DEVICE_INTERFACE_DATA InterfaceDataStructure = new Native.SP_DEVICE_INTERFACE_DATA();
Native.SP_DEVINFO_DATA DevInfoData = new Native.SP_DEVINFO_DATA();
uint InterfaceIndex = 0;
uint ErrorStatus;
StringBuilder DeviceName = new StringBuilder();
DeviceInfoTable = Native.SetupDiGetClassDevs(ref InterfaceClassGuid, IntPtr.Zero, IntPtr.Zero, Native.DIGCF_PRESENT | Native.DIGCF_DEVICEINTERFACE);
if (DeviceInfoTable.ToInt32() != Native.INVALID_HANDLE_VALUE)
{
//Initialize an appropriate SP_DEVINFO_DATA structure.
DevInfoData.cbSize = Marshal.SizeOf(DevInfoData);
while (true)
{
InterfaceDataStructure.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(InterfaceDataStructure);
bool bRslt = Native.SetupDiEnumDeviceInterfaces(DeviceInfoTable, IntPtr.Zero, ref InterfaceClassGuid, InterfaceIndex, ref InterfaceDataStructure);
if (bRslt == true)
{
ErrorStatus = (uint)System.Runtime.InteropServices.Marshal.GetLastWin32Error();
if (Native.ERROR_NO_MORE_ITEMS == ErrorStatus)
{
Native.SetupDiDestroyDeviceInfoList(DeviceInfoTable);//Clean up the old structure we no longer need.
return;
}
}
else //Else some other kind of unknown error ocurred...
{
ErrorStatus = (uint)System.Runtime.InteropServices.Marshal.GetLastWin32Error();
Native.SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need.
return;
}
InterfaceIndex++;
}//end of while(true)
}
}
}
}
I'm not sure why you are trying to use SetupAPI. If it is a detected as a CDC ACM device, then it should have the usbser.sys driver associated with it, and it should show a COM port number in the Device Manager, and you can connect to that COM port using the .NET SerialPort class:
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.aspx
Related
How would you write this type of struct in c#?
struct _JOBOBJECT_BASIC_PROCESS_ID_LIST {
DWORD NumberOfAssignedProcesses;
DWORD NumberOfProcessIdsInList;
ULONG_PTR ProcessIdList[1];
}
sins there is no set size for the ProcessIdList array, what do you do? Do you just write it like this:
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
IntPtr ProcessIdList; //Must point to a allocated array, thanks jdweng for letting me know.
}
or do you just assign a size which is big enough, e.g.:
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_PATH)]
UIntPtr[] ProcessIdList; //Works just fine, but is limited to the SizeConst.
}
This sort of structure is usually declared (there are others like this one in WLan APIs for example) :
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
public int NumberOfAssignedProcesses;
public int NumberOfProcessIdsInList;
public IntPtr[] ProcessIdList;
public JOBOBJECT_BASIC_PROCESS_ID_LIST(IntPtr pList)
{
int nIntSize = Marshal.SizeOf<int>(); // 4
NumberOfAssignedProcesses = Marshal.ReadInt32(pList, 0);
NumberOfProcessIdsInList = Marshal.ReadInt32(pList, nIntSize);
ProcessIdList = new IntPtr[NumberOfProcessIdsInList];
for (int i = 0; i < NumberOfProcessIdsInList; i++)
{
IntPtr pItemList = IntPtr.Zero;
if (Marshal.SizeOf<IntPtr>() == 4)
pItemList = new IntPtr(pList.ToInt32() + (i * Marshal.SizeOf<IntPtr>()) + (nIntSize * 2));
else
pItemList = new IntPtr(pList.ToInt64() + (i * Marshal.SizeOf<IntPtr>()) + (nIntSize * 2));
IntPtr nPID = new IntPtr();
nPID = Marshal.ReadIntPtr(pItemList, 0);
ProcessIdList[i] = nPID;
}
}
}
A test with 5 Notepad launched and assigned to a job with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE,
then QueryInformationJobObject to enumerate the PIDs by using this structure =>
private IntPtr hJob = IntPtr.Zero;
bool bRet = false;
hJob = CreateJobObject(IntPtr.Zero, "Test Job Object");
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jbeli = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
jbeli.BasicLimitInformation.LimitFlags |= (JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_BREAKAWAY_OK);
int nLength = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
IntPtr pJobInfo = Marshal.AllocHGlobal(nLength);
Marshal.StructureToPtr(jbeli, pJobInfo, false);
SetInformationJobObject(hJob, JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, pJobInfo, (uint)nLength);
Marshal.FreeHGlobal(pJobInfo);
int nNbProcesses = 5;
for (int i = 0; i < nNbProcesses; i++)
{
using (Process exeProcess = new Process())
{
exeProcess.StartInfo.FileName = "notepad";
exeProcess.Start();
exeProcess.WaitForInputIdle();
IntPtr hProcess = exeProcess.Handle;
bRet = AssignProcessToJobObject(hJob, hProcess);
}
}
JOBOBJECT_BASIC_PROCESS_ID_LIST jobpil = new JOBOBJECT_BASIC_PROCESS_ID_LIST();
jobpil.NumberOfAssignedProcesses = nNbProcesses;
int nSize = Marshal.SizeOf<JOBOBJECT_BASIC_PROCESS_ID_LIST>() + (nNbProcesses - 1) * Marshal.SizeOf<IntPtr>();
IntPtr pJobpil = Marshal.AllocHGlobal(nSize);
Marshal.StructureToPtr(jobpil, pJobpil, false);
int nReturnLength = 0;
bRet = QueryInformationJobObject(hJob, JOBOBJECTINFOCLASS.JobObjectBasicProcessIdList, pJobpil, nSize, out nReturnLength);
if (bRet)
{
var processidlist = new JOBOBJECT_BASIC_PROCESS_ID_LIST(pJobpil);
foreach (var pid in processidlist.ProcessIdList)
{
Console.WriteLine("PID: {0}", pid.ToString());
}
}
else
{
int nErr = Marshal.GetLastWin32Error();
Win32Exception win32Exception = new Win32Exception(nErr);
this.Activate();
MessageBox.Show("Error: " + win32Exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Marshal.FreeHGlobal(pJobpil);
// CloseHandle can be added in Form1_FormClosed :
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
CloseHandle(hJob);
}
Declarations =>
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string lpName);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInfoClass, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool QueryInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, [Out, MarshalAs(UnmanagedType.SysUInt)] IntPtr lpJobObjectInformation, int cbJobObjectInformationLength, out int lpReturnLength);
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public ulong PerProcessUserTimeLimit;
public ulong PerJobUserTimeLimit;
public int LimitFlags;
public IntPtr MinimumWorkingSetSize;
public IntPtr MaximumWorkingSetSize;
public int ActiveProcessLimit;
public IntPtr Affinity;
public int PriorityClass;
public int SchedulingClass;
}
[StructLayout(LayoutKind.Sequential)]
struct IO_COUNTERS
{
public ulong ReadOperationCount;
public ulong WriteOperationCount;
public ulong OtherOperationCount;
public ulong ReadTransferCount;
public ulong WriteTransferCount;
public ulong OtherTransferCount;
}
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo;
public IntPtr ProcessMemoryLimit;
public IntPtr JobMemoryLimit;
public IntPtr PeakProcessMemoryUsed;
public IntPtr PeakJobMemoryUsed;
}
//
// Basic Limits
//
public const int JOB_OBJECT_LIMIT_WORKINGSET = 0x00000001;
public const int JOB_OBJECT_LIMIT_PROCESS_TIME = 0x00000002;
public const int JOB_OBJECT_LIMIT_JOB_TIME = 0x00000004;
public const int JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x00000008;
public const int JOB_OBJECT_LIMIT_AFFINITY = 0x00000010;
public const int JOB_OBJECT_LIMIT_PRIORITY_CLASS = 0x00000020;
public const int JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = 0x00000040;
public const int JOB_OBJECT_LIMIT_SCHEDULING_CLASS = 0x00000080;
//
// Extended Limits
//
public const int JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY_HIGH = JOB_OBJECT_LIMIT_JOB_MEMORY;
public const int JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x00000400;
public const int JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800;
public const int JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000;
public const int JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000;
public const int JOB_OBJECT_LIMIT_SUBSET_AFFINITY = 0x00004000;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY_LOW = 0x00008000;
public enum JOBOBJECTINFOCLASS
{
JobObjectBasicAccountingInformation = 1,
JobObjectBasicLimitInformation,
JobObjectBasicProcessIdList,
JobObjectBasicUIRestrictions,
JobObjectSecurityLimitInformation, // deprecated
JobObjectEndOfJobTimeInformation,
JobObjectAssociateCompletionPortInformation,
JobObjectBasicAndIoAccountingInformation,
JobObjectExtendedLimitInformation,
JobObjectJobSetInformation,
JobObjectGroupInformation,
JobObjectNotificationLimitInformation,
JobObjectLimitViolationInformation,
JobObjectGroupInformationEx,
JobObjectCpuRateControlInformation,
JobObjectCompletionFilter,
JobObjectCompletionCounter,
JobObjectReserved1Information = 18,
JobObjectReserved2Information,
JobObjectReserved3Information,
JobObjectReserved4Information,
JobObjectReserved5Information,
JobObjectReserved6Information,
JobObjectReserved7Information,
JobObjectReserved8Information,
JobObjectReserved9Information,
JobObjectReserved10Information,
JobObjectReserved11Information,
JobObjectReserved12Information,
JobObjectReserved13Information,
JobObjectReserved14Information = 31,
JobObjectNetRateControlInformation,
JobObjectNotificationLimitInformation2,
JobObjectLimitViolationInformation2,
JobObjectCreateSilo,
JobObjectSiloBasicInformation,
JobObjectReserved15Information = 37,
JobObjectReserved16Information,
JobObjectReserved17Information,
JobObjectReserved18Information,
JobObjectReserved19Information = 41,
JobObjectReserved20Information,
MaxJobObjectInfoClass
}
I think any of the ways you mentioned should work.
In addition, there is a matching feature in c#: Define an array with the fixed keyword:
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
fixed IntPtr ProcessIdList[1];
}
See documentation:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/unsafe-code-pointers/fixed-size-buffers
Also no bounds check, so you should be able to read behind the end of the struckt easily:
Note
Except for memory created by using stackalloc, the C# compiler and the common language runtime (CLR) do not perform any security buffer overrun checks. As with all unsafe code, use caution.
I'm trying to limit a process CPU usage by calling NtSetInformationProcess with ProcessQuotaLimits info class. When using NtQueryInformationProcess with the ProcessQuotaLimits class I get the right numbers for the Page limits/working sets etc. but CpuRateQuota is not filled.
The code I'm using
public struct _QUOTA_LIMITS_EX
{
public uint PagedPoolLimit;
public uint NonPagedPoolLimit;
public uint MinimumWorkingSetSize;
public uint MaximumWorkingSetSize;
public uint PagefileLimit;
public ulong TimeLimit;
public uint WorkingSetLimit;
public uint Reserved2;
public uint Reserved3;
public uint Reserved4;
public uint Flags;
public _RATE_QUOTA_LIMIT CpuRate;
}
public struct _RATE_QUOTA_LIMIT
{
public uint RateData;
public uint RatePercent;
public uint Reserved0;
}
[DllImport("ntdll.dll", SetLastError = true)]
private static extern int NtSetInformationProcess(IntPtr hProcess, int processInformationClass, ref _QUOTA_LIMITS_EX processInformation, int processInformationLength);
[DllImport("ntdll.dll", SetLastError = true)]
private static extern int NtQueryInformationProcess( IntPtr processHandle, int processInformationClass, ref _QUOTA_LIMITS_EX processInformation, uint processInformationLength, ref int returnLength);
public void Limit()
{
Process.EnterDebugMode();
_QUOTA_LIMITS_EX quotaLimits = new _QUOTA_LIMITS_EX();
int size = 56;
int returnLength = 0;
int status = NtQueryInformationProcess(this._process.Handle, 1 /*ProcessQuotaLimits*/, ref quotaLimits, (uint)size, ref returnLength);
}
The call returns NT_STATUS 0, which means succeeded. I'm trying this on Windows server 2016 Standard which should be equivalent to Windows 10. Using JobInformation and suspending/resuming the process aren't viable options in this case.
I'm trying to open info property of file.
In the previous versions of Windows, properties window was shown and then the control was given to next function in my code, but in Windows 10 function call stucks until I'm closing file properties with mouse click.
I wonder what have been changed in the new Windows version?
My code is below:
private const int SwShow = 5;
private const uint SeeMaskInvokeidlist = 12;
public static bool ShowFileProperties(string filename)
{
var info = new Shellexecuteinfo();
info.cbSize = Marshal.SizeOf(info);
info.lpVerb = "properties";
info.lpFile = filename;
info.nShow = SwShow;
info.fMask = SeeMaskInvokeidlist;
return ShellExecuteEx(ref info);
}
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern bool ShellExecuteEx(ref Shellexecuteinfo lpExecInfo);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct Shellexecuteinfo
{
public int cbSize;
public uint fMask;
public IntPtr hwnd;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpVerb;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpFile;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpParameters;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpDirectory;
public int nShow;
public IntPtr hInstApp;
public IntPtr lpIDList;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpClass;
public IntPtr hkeyClass;
public uint dwHotKey;
public IntPtr hIcon;
public IntPtr hProcess;
}
static void Main(string[] args)
{
Console.WriteLine("Show file info.");
ShowFileProperties(args[0]);
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine("File info was shown.");
}
I am trying to get raw input data from a Surface touch screen, using RAWINPUT API.
Getting the devices list works good. But when I want to register the touch screen device with RegisterRawInputDevices, I have issues : the function returns false with 87 (ERROR_INVALID_PARAMETER) in GetLastError... I have tried different things that I read online but none work.
I am using Interop on C# for very simple desktop console application, developping with Visual Studio 2013 on Windows 8.1. The target is a Surface Pro 3.
The code doing the work with the API is hereunder... (sorry for the ugly editing).
I will be so thanksful for your help :)
Pierre
CLASS for the API wrapping in C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace ConsoleApplication3
{
class APIWrapper
{
#region Properties
private static int _vendorID=-1;
public static int VendorID
{
get { return _vendorID; }
}
private static int _productID=-1;
public static int ProductID
{
get { return _productID; }
}
#endregion
#region API structs
internal struct RAWINPUTDEVICELIST_ELMT
{
public IntPtr hDevice;
public uint dwType;
}
public enum RawInputDeviceType : uint
{
RIM_TYPEMOUSE = 0,
RIM_TYPEKEYBOARD = 1,
RIM_TYPEHID = 2,
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWINPUTDEVICE
{
public ushort usUsagePage;
public ushort usUsage;
public int dwFlags;
public IntPtr hwndTarget;
}
public enum RawInputDeviceInfoType : uint
{
RIDI_DEVICENAME = 0x20000007,
RIDI_DEVICEINFO = 0x2000000b,
RIDI_PREPARSEDDATA = 0x20000005,
}
public const ushort RIDEV_INPUTSINK =0x00000100;
public const ushort RIDEV_PAGEONLY = 0x00000020;
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO_HID
{
public int dwVendorId;
public int dwProductId;
public int dwVersionNumber;
public ushort usUsagePage;
public ushort usUsage;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO_MOUSE
{
public int dwId;
public int dwNumberOfButtons;
public int dwSampleRate;
public bool fHasHorizontalWheel;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RID_DEVICE_INFO_KEYBOARD
{
public int dwType;
public int dwSubType;
public int dwKeyboardMode;
public int dwNumberOfFunctionKeys;
public int dwNumberOfIndicators;
public int dwNumberOfKeysTotal;
}
[StructLayout(LayoutKind.Explicit)]
internal struct RID_DEVICE_INFO
{
[FieldOffset(0)]
public uint cbSize;
[FieldOffset(4)]
public RawInputDeviceType dwType;
[FieldOffset(8)]
public RID_DEVICE_INFO_MOUSE mouse;
[FieldOffset(8)]
public RID_DEVICE_INFO_KEYBOARD keyboard;
[FieldOffset(8)]
public RID_DEVICE_INFO_HID hid;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWINPUTHEADER
{
public RawInputDeviceType dwType;
public int dwSize;
public IntPtr hDevice;
public uint wParam;
}
[StructLayout(LayoutKind.Explicit)]
internal struct RAWMOUSE
{
[FieldOffset(0)]
public ushort usFlags;
[FieldOffset(2)]
public uint ulButtons;
[FieldOffset(4)]
public ushort usButtonFlags;
[FieldOffset(2)]
public ushort usButtonData;
[FieldOffset(6)]
public uint ulRawButtons;
[FieldOffset(10)]
public int lLastX;
[FieldOffset(14)]
public int lLastY;
[FieldOffset(18)]
public uint ulExtraInformation;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWKEYBOARD
{
public ushort MakeCode;
public ushort Flags;
public ushort Reserved;
public ushort VKey;
public uint Message;
public uint ExtraInformation;
}
[StructLayout(LayoutKind.Sequential)]
internal struct RAWHID
{
public int dwSizeHid;
public int dwCount;
//use of a pointer here for struct reason
public IntPtr pbRawData;
}
[StructLayout(LayoutKind.Explicit)]
internal struct RAWINPUT
{
[FieldOffset(0)]
public RAWINPUTHEADER header;
[FieldOffset(16 + 8)]
public RAWMOUSE mouse;
[FieldOffset(16 + 8)]
public RAWKEYBOARD keyboard;
[FieldOffset(16 + 8)]
public RAWHID hid;
}
#endregion
#region API functions
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetRawInputDeviceList([In, Out] RAWINPUTDEVICELIST_ELMT[] InputdeviceList, [In, Out] ref uint puiNumDevices, [In] uint cbSize);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetRawInputDeviceInfo([In] IntPtr hDevice, [In] RawInputDeviceInfoType uiCommand, [In, Out] IntPtr pData, [In, Out] ref uint pcbSize);
[DllImport("user32.dll", SetLastError = true)]
static extern bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevices, uint uiNumDevices, uint cbSize);
[DllImport("user32.dll")]
static extern uint GetRegisteredRawInputDevices([In, Out] RAWINPUTDEVICE[] InputdeviceList, [In, Out] ref uint puiNumDevices, [In] uint cbSize);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetRawInputBuffer([In,Out] RAWINPUT[] pData, [In, Out] ref uint pcbSize, [In] uint cbSizeHeader);
#endregion
#region Methods for devices
public static bool GetRawInputDeviceList()
{
bool res = false;
RAWINPUTDEVICELIST_ELMT[] pRawInputDeviceList = null;
uint puiNumDevices = 0;
uint returnCode = GetRawInputDeviceList(pRawInputDeviceList, ref puiNumDevices, (uint)Marshal.SizeOf(new RAWINPUTDEVICELIST_ELMT()));
res = (0xFFFFFFFF != returnCode);
if (res)
{
//alloc array
pRawInputDeviceList = new RAWINPUTDEVICELIST_ELMT[puiNumDevices];
//get devices
returnCode = GetRawInputDeviceList(pRawInputDeviceList, ref puiNumDevices, (uint)Marshal.SizeOf((typeof(RAWINPUTDEVICELIST_ELMT))));
res = (0xFFFFFFFF != returnCode);
if (res)
{
//look for the touchscreen.
bool foundTouchScreen = false;
foreach (RAWINPUTDEVICELIST_ELMT rawInputDevice in pRawInputDeviceList)
{
//IntPtr pData = IntPtr.Zero;
//uint strsize = 0;
//IntPtr deviceHandle = rawInputDevice.hDevice;
//returnCode = GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.RIDI_DEVICENAME, pData, ref strsize);
//pData = Marshal.AllocHGlobal((int)strsize);
//returnCode = GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.RIDI_DEVICENAME, pData, ref strsize);
////Console.WriteLine("Result = " + returnCode + " ErrorCode = " + Marshal.GetLastWin32Error());
//string name = Marshal.PtrToStringAnsi(pData);
//Console.WriteLine("Name = " + name);
uint structsize = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO));
RID_DEVICE_INFO di = new RID_DEVICE_INFO();
di.cbSize = structsize;
IntPtr pData = Marshal.AllocHGlobal((int)structsize);
returnCode = GetRawInputDeviceInfo(rawInputDevice.hDevice, RawInputDeviceInfoType.RIDI_DEVICEINFO, pData, ref structsize);
if (0xFFFFFFF != returnCode && 0 != returnCode)
{
di = (RID_DEVICE_INFO)Marshal.PtrToStructure(pData, typeof(RID_DEVICE_INFO));
//Console.WriteLine("di.dwType = " + Enum.GetName(typeof(RawInputDeviceType), di.dwType));
switch (di.dwType)
{
case RawInputDeviceType.RIM_TYPEHID:
/* Console.WriteLine("di.hid.dwVendorId = " + di.hid.dwVendorId);
Console.WriteLine("di.hid.dwProductId = " + di.hid.dwProductId);
Console.WriteLine("di.hid.dwVersionNumber = " + di.hid.dwVersionNumber);
Console.WriteLine("di.hid.usUsagePage = " + di.hid.usUsagePage);
Console.WriteLine("di.hid.usUsage = " + di.hid.usUsage);*/
if (0x0D == di.hid.usUsagePage && 0x04 == di.hid.usUsage)
{
_vendorID = di.hid.dwVendorId;
_productID = di.hid.dwProductId;
foundTouchScreen = true;
}
break;
case RawInputDeviceType.RIM_TYPEKEYBOARD:
case RawInputDeviceType.RIM_TYPEMOUSE:
default:
break;
}
if (foundTouchScreen)
{
RAWINPUTDEVICE[] rawInputDevicesToMonitor = new RAWINPUTDEVICE[1];
RAWINPUTDEVICE device = new RAWINPUTDEVICE();
device.dwFlags =RIDEV_INPUTSINK;
device.hwndTarget = Process.GetCurrentProcess().MainWindowHandle;
device.usUsage = di.hid.usUsage;
device.usUsagePage = di.hid.usUsagePage;
rawInputDevicesToMonitor[0] = device;
if (!RegisterRawInputDevices(rawInputDevicesToMonitor, (uint)1, (uint)Marshal.SizeOf(new RAWINPUTDEVICE())))
{
Console.WriteLine("Registration of device --> NOK (error: " + Marshal.GetLastWin32Error()+")");
RAWINPUTDEVICE [] pRegisteredRawInputDeviceList = null;
uint puiNumRegDevices = 0;
returnCode = GetRegisteredRawInputDevices(pRegisteredRawInputDeviceList, ref puiNumRegDevices, (uint)Marshal.SizeOf(new RAWINPUTDEVICE()));
res = (0xFFFFFFFF != returnCode);
if (res)
{
//alloc array
pRegisteredRawInputDeviceList = new RAWINPUTDEVICE[puiNumRegDevices];
//get devices
returnCode = GetRegisteredRawInputDevices(pRegisteredRawInputDeviceList, ref puiNumRegDevices, (uint)Marshal.SizeOf((typeof(RAWINPUTDEVICE))));
Console.WriteLine("Registered devices nb : " + returnCode);
}
}
break;
}
}
}
}
/*Need to set RIDEV_INPUTSINK in the dwFlags member and set hwndTarget to be able to make use of this function otherwise
* GetRawInputBuffer will ALWAYS say 0 when you try to find out what size you need the buffer to be.
*/
}
/*else
int error = Marshal.GetLastWin32Error();*/
return res;
}
#endregion
}
}
MAIN CLASS:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
//look for the touch screen device
if (!APIWrapper.GetRawInputDeviceList())
{
Console.WriteLine("Error occured when getting RawInputDevice List.");
}
if (APIWrapper.VendorID == -1 && APIWrapper.ProductID == -1)
{
Console.WriteLine("No Touchscreen device has been found.");
}
else
{
Console.WriteLine("Touchscreen found : VendorID=" + APIWrapper.VendorID + " ProductID=" + APIWrapper.ProductID);
//wait for rawinputdata
Console.WriteLine("Waiting data loop : started.");
uint dataNb = APIWrapper.ReadHIDData();
switch (dataNb)
{
case 0xFFFFFFFF:
Console.WriteLine("An error occured.");
break;
case 0:
Console.WriteLine("No data received.");
break;
default:
Console.WriteLine(dataNb + " rawInputData received");
break;
}
Console.WriteLine("Waiting data loop : ended.");
}
Console.ReadLine();
}
}
}
Try to use mfakane/rawinput-sharp: C# wrapper library for Raw Input
Following Microsoft's documentation on RIL I've been able to implement a code that retrieves Cell ID, LAC, MCC, MNC and Signal Strength. Using these data and http://www.opencellid.org/ I'm able to retrieve latitude and longitude of that cell tower. The problem is that I need to implement some kind of triangulation algorithm to get a more accurate position. But before even thinking in triangulation, I'm going to need more than one tower ID to work with. How can I get them? I tried to create an array of towerIDs and populate it in a loop, while a tower id does not exist in the array then add it, but if it exists then ignore it and keep looking for another one. Obviously it did not work, once it gets one it keeps it and if I delete the object and create a new one it gets the same tower. How can I get a different one?
Thanks in advance.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace GPS_Test
{
public class CellTower
{
public int CellID { get; set; }
// LAC (Local Area Code)
public int LAC { get; set; }
// MCC (Mobile Country Code)
public int MCC { get; set; }
// MNC (Mobile Network Code)
public int MNC { get; set; }
// Received signal strength
public int signalStrength { get; set; }
// Base Station ID
//public int baseStationID { get; set; }
}
public class RIL
{
public delegate void RILRESULTCALLBACK(uint dwCode,
IntPtr hrCmdID, IntPtr lpData, uint cbData, uint dwParam);
public delegate void RILNOTIFYCALLBACK(uint dwCode,
IntPtr lpData, uint cbData, uint dwParam);
[DllImport("ril.dll")]
public static extern IntPtr RIL_Initialize(uint dwIndex,
RILRESULTCALLBACK pfnResult,
RILNOTIFYCALLBACK pfnNotify,
uint dwNotificationClasses,
uint dwParam,
out IntPtr lphRil);
[DllImport("ril.dll", EntryPoint = "RIL_GetCellTowerInfo")]
public static extern IntPtr RIL_GetCellTowerInfo(IntPtr hril);
[DllImport("ril.dll")]
public static extern IntPtr RIL_Deinitialize(IntPtr hril);
[DllImport("ril.dll", EntryPoint = "RIL_GetSignalQuality")]
public static extern IntPtr RIL_GetSignalQuality(IntPtr hRil);
[StructLayout(LayoutKind.Explicit)]
internal class RILCELLTOWERINFO
{
[FieldOffset(0)]
uint dwSize;
[FieldOffset(4)]
uint dwParams;
[FieldOffset(8)]
public uint dwMobileCountryCode;
[FieldOffset(12)]
public uint dwMobileNetworkCode;
[FieldOffset(16)]
public uint dwLocationAreaCode;
[FieldOffset(20)]
public uint dwCellID;
[FieldOffset(28)]
public uint dwBaseStationID;
[FieldOffset(36)]
public uint dwRxLevel;
}
[StructLayout(LayoutKind.Explicit)]
internal class RILSIGNALQUALITY
{
[FieldOffset(0)]
uint dwSize;
[FieldOffset(4)]
uint dwParams;
[FieldOffset(8)]
public int nSignalStrength;
[FieldOffset(12)]
public uint nMinSignalStrength;
[FieldOffset(16)]
public uint nMaxSignalStrength;
[FieldOffset(20)]
public uint dwBitErrorRate;
[FieldOffset(24)]
public uint nLowSignalStrength;
[FieldOffset(28)]
public uint nHighSignalStrength;
}
}
public class CellTowerInfo
{
private static AutoResetEvent dataReceived = new AutoResetEvent(false);
private static AutoResetEvent whSignalQuality = new AutoResetEvent(false);
private static RIL.RILCELLTOWERINFO towerInfo;
private static RIL.RILSIGNALQUALITY signalQuality;
public static CellTower GetCellTowerInfo()
{
IntPtr hRil = IntPtr.Zero;
IntPtr hResult = IntPtr.Zero;
hResult = RIL.RIL_Initialize(1,
new RIL.RILRESULTCALLBACK(CellTowerData),
null, 0, 0, out hRil);
if (hResult != IntPtr.Zero)
return null;
hResult = RIL.RIL_GetCellTowerInfo(hRil);
dataReceived.WaitOne();
RIL.RIL_Deinitialize(hRil);
CellTower ct = new CellTower();
ct.LAC = (int)towerInfo.dwLocationAreaCode;
ct.MCC = (int)towerInfo.dwMobileCountryCode;
ct.MNC = (int)towerInfo.dwMobileNetworkCode;
ct.CellID = (int)towerInfo.dwCellID;
ct.signalStrength = GetSignalQuality();
return ct;
}
public static int GetSignalQuality()
{
IntPtr hRes = IntPtr.Zero;
IntPtr hSignalQ = IntPtr.Zero;
hRes = RIL.RIL_Initialize(1, new RIL.RILRESULTCALLBACK(SignalQualityCallback),
null, 0, 0, out hSignalQ);
hRes = RIL.RIL_GetSignalQuality(hSignalQ);
whSignalQuality.WaitOne();
RIL.RIL_Deinitialize(hSignalQ);
return signalQuality.nSignalStrength;
}
private static void CellTowerData(uint dwCode, IntPtr hrCmdID,
IntPtr lpData, uint cbData, uint dwPara)
{
towerInfo = new RIL.RILCELLTOWERINFO();
Marshal.PtrToStructure(lpData, (object)towerInfo);
dataReceived.Set();
}
private static void SignalQualityCallback(uint dwCode, IntPtr hrCmdID,
IntPtr lpData, uint cbData, uint dwPara)
{
signalQuality = new RIL.RILSIGNALQUALITY();
Marshal.PtrToStructure(lpData, (object)signalQuality);
whSignalQuality.Set();
}
}
}
Try to save all the info regarding the current signal, after doing so restart the service looking to another signal but first check the one you had stored, if it's the same disregard and keep looking.
Good luck!