|
I'm not sure, but I got a "code never reached"-warning here
public bool UnregisterHandle()
{
if (this.handle != null)
{
return Win32Usb.UnregisterForUsbEvents(this.handle);
}
return false; <-- this is never reached!!
}
It puzzled me a bit, but in my desperation I tried to change this line
if (this.handle != (IntPtr)null)
and the warning was gone.
I always thought that the original version should work, but maybe I'm wrong and that might also be the solution for your problem.
cheers
ScruffR
|
|
|
|
|
Hi
After written the buffer you have to flush or close the file buffer to unregister the device.
/// <summary>
/// Write an output report to the device.
/// </summary>
/// <param name="oOutRep">Output report to write</param>
protected void Write(OutputReport oOutRep)
{
try
{
m_oFile.Write(oOutRep.Buffer, 0, oOutRep.BufferLength);
m_oFile.Flush();
OR
m_oFile.Close();
}
catch (IOException ex)
{
// The device was removed!
throw new HIDDeviceException("Probbaly the device was removed");
}
catch(Exception exx)
{
Console.WriteLine(exx.ToString());
}
}
modified on Thursday, July 16, 2009 6:40 AM
|
|
|
|
|
|
file: SpecifiedOutputReport.cs
Line 16
For loop starts at 1 , should start at 0 : first byte sent was always 0 , this gave me problems.
kind regards
Bakaneko
modified on Tuesday, April 8, 2008 7:01 PM
|
|
|
|
|
Hello man,
First, thank's for that article and component. It's a great job who help me a lot.
But, I still have a problem: I develop a WPF application, and the sniffer library component seems to be incompatible with wpf, as it require a winform. I dont' know how to deal with that...
Moreover, sniffer is very coupled with the winform. Have you ever think of creating an stand-alone component ?
Why not to place the winform inside the library and supply personalized events ?
Loïc
Loïc Berthollet
|
|
|
|
|
Thanks for the code, it's helping me find out more about HID.
What I'm trying to do is to detect a specific device based on PID and VID (in my case a barcode scanner) then when found I want to capture all input from that device regardless of whether my app has focus or not (ideally my app will run as a windows service).
Currently running your test app i can't even detect my particular device, when I enter the vid and pid (as found from running msinfo32.exe) it detects a device being connected and disconnected but not the specified device.
If you could offer any guidance I would be very grateful. Could you also get in touch if you are available for contract work?
Dan
danmoov2@googlemail.com
|
|
|
|
|
I was able to use this code and receive data from the USB barcode scanner.
What model of scanner are you using?
I'm using a product from Hand Held Products (model 3800g)
3800 General Purpose Linear Image Scanner[^]
The model that I have, by default is setup as a keyboard/wedge. I had to scan a programming barcode to make it a USB HID device. By doing this it also changed the Product ID from 02E1 to 02E7. There is an option to use a USB-COM emulator that allows the device to communicate with a virtual RS232 port.
|
|
|
|
|
hi man
great job!
i have been trying to catch the IR codes from my remote control for more than a month and i was too lazy to dig into HID myself.
but your application did the trick.
thanks again
|
|
|
|
|
Hi!
I'm trying to send data report to my USB device, but with no luck (i'm using your Sniffer example) It should control the LED blinking.
The SendData method doesn't work. Are you sure about writing to the USB device using FileStream ?
I hacked the USB Library and used HidD_SetFeature method and it worked. Can you please explain me how your report writing works ? I think it's a bit confusing.
Thx.
|
|
|
|
|
Hi
You have to write another method to handle the reports.
Steps For Handling Reports:
1) In win32usb.cs, add
HidD_SetOutputReport() for handling output reports and HidD_GetInputReport() for handling input reports.
-------------------------------------------------------------------------------------------
/// Send an output report to a HID device.
/// </summary>
/// <param name="HidDeviceObject">A handle to a Hid Device Object.</param>
/// <param name="ReportBuffer">The buffer of the output report to send to the device.</param>
/// <param name="ReportBufferLength">The size (in bytes) of ReportBuffer.</param>
/// <returns>'true' if successful.'false' otherwise.</returns>
[DllImport("hid.dll", SetLastError = true)] protected static extern bool HidD_SetOutputReport(IntPtr HidDeviceObject, byte[] ReportBuffer, int ReportBufferLength);
/// <summary>
/// Retrieve an input report from a HID device.
/// <param name=" HidDeviceObject">A handle to a Hid Device Object.</param>
/// <param name="ReportBuffer">The buffer that the input report should be placed into.The first byte of the buffer should be set to the report ID of the desired report.</param>
/// <param name="ReportBufferLength">The size (in bytes) of ReportBuffer. This value should be greater than or equal to the InputReportByteLength field as specified in the HIDP_CAPS structure for the device.</Param>
///<returns>'true' if successful.'false' otherwise. </returns>
[DllImport("hid.dll", SetLastError = true)] protected static extern bool HidD_GetInputReport(IntPtr HidDeviceObject, byte[] ReportBuffer, int ReportBufferLength);
-------------------------------------------------------------------------------------------
2) Write methods sendReport() and getReport() in HIDDevice.cs
protected void sendReport(OutputReport oOutRep)
{
try
{
// Call SetOutputReport to send this report buffer over the control pipe
HidD_SetOutputReport(m_hHandle, oOutRep.Buffer, oOutRep.BufferLength);
}
catch (Exception exx)
{
Console.WriteLine(exx.ToString());
}
}
protected void getReport(byte[] data,byte buffersize)
{
try
{
//Call GetInputReport to get the requested report buffer over the control pipe
HidD_GetInputReport(m_hHandle, data, buffersize);
}
catch (Exception exx)
{
Console.WriteLine(exx.ToString());
}
}
-------------------------------------------------------------------------------------------
3) In SpecifiedDevice.cs,
In class, public class SpecifiedDevice : HIDDevice write set_report() and get_report()
//set the request to send the report buffer over the control pipe.
public void set_report(byte[] data, byte buffersize)
{
SpecifiedOutputReport oRep = new SpecifiedOutputReport(this);
oRep.set_report(data, buffersize);
try
{
sendReport(oRep);
}
catch (HIDDeviceException ex)
{
}
}
//Receive the requested report buffer over the control pipe.
public void get_report(byte[] data,byte buffersize)
{
try
{
getReport(data,buffersize);
}
catch (HIDDeviceException ex)
{
}
}
-------------------------------------------------------------------------------------------
4) In SpecifiedOutputReport.cs,
public bool set_report(byte[] data, byte buffersize)
{
byte[] arrbuff = Buffer;
for (int i = 0; i < buffersize; i++)
{
arrbuff[i] = data[i];
}
if (arrbuff.Length < buffersize)
{
return false;
}
else
{
return true;
}
}
-------------------------------------------------------------------------------------------
5) In SpecifiedInputReport.cs,
public void get_report(byte[] inputbuffer)
{
inputbuffer = Buffer;
}
-------------------------------------------------------------------------------------------
Thank you,
|
|
|
|
|
hi mdeepa. thank u for your modifiation. i added this modification but i havent used them. do i have to do something else or is this enough??
and thx wimar for this
|
|
|
|
|
Hello,
I also tried to run the program, but as i debugged it, it seems it can't find my HID device.
My HID device vendor id and product id is correct still it returns false form "SetupDiEnumDeviceInterfaces" function.
In the "while" statement :
while (SetupDiEnumDeviceInterfaces(hInfoSet, 0, ref gHid, (uint)nIndex, ref oInterface))
{....}
It always returns false...
Please let me know solution for this asap.
Thanks.
Samir Karve
|
|
|
|
|
Add FILE_SHARE_READ | FILE_SHARE_WRITE in the CreateFile function:
m_handle = CreateFile(
DeviceName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
0,
0);
regards Jan
|
|
|
|
|
I managed to get the received data side of the USB HID component working with my AT89C5131 USB Development board but not the send data. I assume judging by all the "000 000 000 000" it puts in the send data field that it sends a string of data. Can anyone point me in the direction in the USB HID code to a spot where I can modify it so i only send one charactor of data, eg. if only I want to send the number 1?
|
|
|
|
|
This seems not to work on 64 bit Vista (and possibly XP x64, I have not tested). Any ideas how to get it to enumerate the devices? At the moment it does not error but enumerates to nothing?
|
|
|
|
|
Ok, here was the bug. I have not looked for other similar bugs.
In the definition of the struct DeviceInterfaceData, "Reserved" is given the type int. In the documentation it should correspond to ULONG_PTR. This means that UIntPtr (or maybe IntPtr) should be used instead. This is confirmed to work on 32 and 64 bit systems.
|
|
|
|
|
|
That is also my thread. I made it at about the same time as I posted the last comment.
Please look at my sourceforge project http://sourceforge.net/projects/libhidnet[^][^]. It runs on 32 and 64 bit Windows as well as Linux (and anything else with Mono and hiddev - I haven't checked which systems have hiddev). I haven't had any feedback on it yet or any suggestions but they are very welcome as I don't have much time to work on it.
|
|
|
|
|
Thanks again for the two fixes. Now that my code, mostly derived from this project, is working with 64-bit Windows I'm afraid I'm not motivated to do anything with your new project. But you are to be lauded for having done it and made it available. Thanks.
Rennie
|
|
|
|
|
Do you have a build with the 64-bit support you could provide me with? I've tried to download and build it myself but the result is a 18kb (compared to the builds in the projects builds) file which works with one device but not with another so I'm not sure the conversion made by visual 2008 was correct...
Thanks in advance // Magnus
|
|
|
|
|
On 32bit platforms, all SetupApi structures are 1-Byte packed. On 64bit platforms the SetupApi structures are 8-byte packed. (i.e., for 32 bit SP_DEVINFO_DATA.cbSize=28, for 64Bit SP_DEVINFO_DATA.cbSize=(36+4)=40)
I believe if you define the structurs like the following, the compiler will automatically handle the byte alignment at runtime. Haven't check it yet though...
[StructLayout(LayoutKind.Sequential)]
struct SP_DEVINFO_DATA
{
public UInt32 cbSize;
public Guid ClassGuid;
public UInt32 DevInst;
public IntPtr Reserved;
}
|
|
|
|
|
Yes, I already posted this in the forum linked to in another of the replies of this message. The only mystery to me now is with SP_DEVICE_INTERFACE_DETAIL_DATA[^]. SetupDiGetDeviceInterfaceDetail requires that SP_DEVICE_INTERFACE_DETAIL_DATA.cbSize be set to 5 on 32bit and 8 on 64bit. All I can assume is that this is 4+1 vs 4+4 but that doesn't really make much sense, given the data types in the struct (a DWORD and a TCHAR* pointer). I would expect it to be 8 on 32bit and 12 on 64bit. To make this worse, sizeof() in .net returns 260 (4+256) by adding the total size of the array rather than just the size of a pointer.
Do you know an elegant way to get this value that will also hold for any future platforms down the line, such as 128 bit? Is it supposed to be returning sizeof(DWORD) + sizeof(TCHAR), in which case I can understand the 5 on 32bit but not the 8 on 64bit. Could this be to do with 8 byte packing on 64bit rounding the size up?
With the following example, changing the "Pack" can achieve the correct size:
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
public int cbSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string DevicePath;
} With Pack = 1, it gives 5 for 32bit compatibility; with Pack = 8, it gives 8 for 64bit compatibility. Pack = 0 is supposed to use the default pack size for the platform but I compiled and ran this on 32 bit and it still gave me 8 (same on 64 bit). Also, this struct requires that SizeConst = 256 so this means using a totally separate struct to find the size, if using pack eventually does work (and without recompiling).
modified on Saturday, July 26, 2008 7:14 AM
|
|
|
|
|
Actually, I read on another web site that the 'cbSize' parameter of the structure should be the size of the DWORD plus the first character of the string. If this is the case, then possibly, the 5 and 8 makes sense.
On a 32-bit system, COM may be expecting standard ASCII characters, which are one byte. This would give us 4 bytes for the cbSize parameter and 1 byte for the array. Being that the packing is 1-byte, this would give us a total size of 5 bytes for the structure.
On a 64-bit system, COM may be expecting Unicode characters, which are two bytes. This would give us 4 bytes for the cbSize parameter and 2 bytes for the array. Being that the packing is 8-byte, this would give us a total size of 6 bytes for the structure and 2 bytes of padding, making the total structure size 8 bytes.
So really, I think the problem boils down to what COM expects and not the actual structure size as reported by the compiler. I think the following code will work on both platforms.
oDetail.Size = (uint)(Marshal.SizeOf(typeof(UInt32)) + IntPtr.Size/4);
On 32-bit systems, IntPtr will be 4 bytes. While on 64-bit systems, IntPtr will be 8 bytes. This will give us the 1- and 2-bytes we need to determine the structure size that COM expects.
Give it a try and let me know if it works on 64-bit. I don't have a 64-bit OS here to test it on.
SIDE NOTE: The array of bytes in this structure can be any size, and COM is expecting a NULL terminated string to determine the end. So in reality, it only need to know the first byte of the arry. Hope this makes sense...
|
|
|
|
|
Many places suggest System.Runtime.InteropServices.Marshal.SystemDefaultCharSize (1 on 32bit, 2 on 64bit). How would you get that to round up to 8 on 64 bit though? You could do things to round it manually but if you are doing that, it is just as bad as what I am currently using:
.cbSize = IntPtr.Size == 8 ? 8 : 5;
These places (such as pinvoke.net) have never actually bothered testing on 64 bit, though, and it just ends up setting it to 4+2=6. They just assume it works because on 32 bit, 4+1=5.
Is there anything anywhere that can define the packing size that SetupApi is using on the particular system at runtime?
|
|
|
|
|
On my system, Windows XP Pro 32-bit, Marshal.SystemDefaultCharSize returns 2 and not 1. That's why I decided to use the IntPtr.SizeOf() instead. It will have a different size on either platform, 4 for 32-bit, and 8 for 64-bit.
As far as getting the structure sizes to 5 and 8, it should happen automatically when you compile for the 64-bit OS because of structure alignment.
I'll install Windows Server 2003 64-bit on one of my computers down stairs and give it a try and see what I come up with. I'll run 2 scenarios: 1 - app compiled 32-bit running on 64-bit, then I will try app compiled 64-bit running on 64-bit and what turns up.
I probably won't get to it till Monday though. I'll be gone all day tomorrow.
|
|
|
|
|