DeviceIoControl for SCSI INQUIRY command returns error 50 - c++

I am trying to access a USB scanner through the IOCTL commands. This is on Windows 7. I did not deal with IOCTL coding before, so I first tried the following snippet based on what I could find with a quick search.
#include "stdafx.h"
#include <stddef.h>
#include <Windows.h>
#include <ntddscsi.h>
#include <usbscan.h>
typedef struct
{
SCSI_PASS_THROUGH spt;
BYTE sense[18];
BYTE data[36];
} SPTSD;
LPTSTR ErrorMessage(DWORD error)
{
LPTSTR errorText = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&errorText,
0,
NULL);
return errorText;
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE h = CreateFile(L"\\\\.\\Usbscan0", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != h)
{
SPTSD sptsd={0};
sptsd.spt.Length = sizeof (sptsd.spt);
sptsd.spt.SenseInfoLength = sizeof(sptsd.sense);
sptsd.spt.DataTransferLength = sizeof(sptsd.data);
sptsd.spt.SenseInfoOffset = offsetof (SPTSD, sense);
sptsd.spt.DataBufferOffset = offsetof (SPTSD, data);
sptsd.spt.TimeOutValue = 30;
sptsd.spt.DataIn = SCSI_IOCTL_DATA_IN;
sptsd.spt.CdbLength = 6;
sptsd.spt.Cdb[0] = 0x12; // SCSI INQUIRY command
sptsd.spt.Cdb[1] = 0;
sptsd.spt.Cdb[2] = 0;
sptsd.spt.Cdb[3] = 0;
sptsd.spt.Cdb[4] = sizeof(sptsd.data);
sptsd.spt.Cdb[5] = 0;
DWORD dwReturnedBytes;
BOOL b;
b = DeviceIoControl(h, IOCTL_SCSI_PASS_THROUGH, &sptsd, sizeof(sptsd), &sptsd, sizeof(sptsd), &dwReturnedBytes, NULL);
if (b == 0)
{
LPTSTR errortext = ErrorMessage(GetLastError());
wprintf(L"DeviceIoControl(IOCTL_SCSI_PASS_THROUGH-INQUIRY) failed with error %d : %s\r\n", GetLastError(), errortext);
LocalFree(errortext);
}
else
{
wprintf(L"DeviceIoControl(IOCTL_SCSI_PASS_THROUGH-INQUIRY) succeeded\r\n");
for (int i=0; i<dwReturnedBytes; i++)
{
wprintf(L"%02x ", sptsd.data[i]);
}
wprintf(L"\r\nEnd of returned data\r\n");
}
DEVICE_DESCRIPTOR dd;
b = DeviceIoControl(h, IOCTL_GET_DEVICE_DESCRIPTOR, &dd, sizeof(dd), &dd, sizeof(dd), &dwReturnedBytes, NULL);
if (b == 0)
{
LPTSTR errortext = ErrorMessage(GetLastError());
wprintf(L"DeviceIoControl(IOCTL_GET_DEVICE_DESCRIPTOR) failed with error %d : %s\r\n", GetLastError(), errortext);
LocalFree(errortext);
}
else
{
wprintf(L"DeviceIoControl(IOCTL_GET_DEVICE_DESCRIPTOR) succeeded\r\n");
wprintf(L"VendorId = %x, ProductId = %x, Version = %x\r\n", dd.usVendorId, dd.usProductId, dd.usBcdDevice);
wprintf(L"End of returned data\r\n");
}
CloseHandle(h);
}
return 0;
}
I tried both 32-bit and 64-bit versions of Windows 7 but the result is the same on both (error 50 : The request is not supported.). Interestingly, second DeviceIoControl call works and returns the VID/PID of the device, along with the firmware version.
Based on the error message, I would think this IOCTL is not supported. However, I looked into it and found out that this IOCTL code is mandatory for all devices, so there must be something I am doing wrong. How should this code be modified so that the INQUIRY command will succeed?

According to http://msdn.microsoft.com/en-us/library/ff548569%28v=vs.85%29.aspx, these IOCTL codes are recognized by the kernel-mode still image driver for USB buses.
IOCTL_CANCEL_IO
IOCTL_GET_CHANNEL_ALIGN_RQST
IOCTL_GET_DEVICE_DESCRIPTOR
IOCTL_GET_PIPE_CONFIGURATION
IOCTL_GET_USB_DESCRIPTOR
IOCTL_GET_VERSION
IOCTL_READ_REGISTERS
IOCTL_RESET_PIPE
IOCTL_SEND_USB_REQUEST
IOCTL_SET_TIMEOUT
IOCTL_WAIT_ON_DEVICE_EVENT IOCTL_WRITE_REGISTERS
My understanding is that any other IOCTL code should be sent via IOCTL_SEND_USB_REQUEST control code. This explains why trying to send a INQURY command using the above code does not work.
EDIT: It was simply a matter of using WriteFile to send the INQUIRY command and ReadFile to read the response. However, there seems an additional issue that I do not understand: The device wants an extra byte after the 6 bytes of the INQUIRY command to send the response. Otherwise, ReadFile will only return a single byte (0x3). I will update this reply again if I figure out what is happening here.

Related

Getting Connection-State from Bluetooth Low Energy Device from Device Manager

i'm developing on a Bluetooth Low Energy Device and i need to see in code if the device is connected or not.
First thing i noticed was that there is in the Devicemanager a Attribute "Verbunden"-> English: Connected and it says true or false if my device is connected or not. So i need to read that Attribute in my program.
What i have tried till now:
Getting all Devices with SetupDiGetClassDevs
Getting the FriendlyName with SetupDiGetDeviceRegistryProperty
Searching for my Device with the name.
That works.
Now i wanted to get that Connected-Attribute but i didn't find out what i have to use at SetupDiGetDeviceRegistryProperty.
SetupDiGetDeviceRegistryProperty is described here https://msdn.microsoft.com/en-us/library/windows/hardware/ff551967(v=vs.85).aspx
Maybe someone knows what is the right value for Property.
My Code:
int get_device_info( void )
{
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
FILE * devices = fopen("devices.txt", "a+");
GUID AGuid;
//GUID can be constructed from "{xxx....}" string using CLSID
CLSIDFromString(TEXT(TO_SEARCH_DEVICE_UUID), &AGuid);
GUID BluetoothInterfaceGUID = AGuid;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(&BluetoothInterfaceGUID,
0, // Enumerator
0,
DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return 1;
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i,
&DeviceInfoData);i++)
{
DWORD DataT;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
//
// Call function with null to begin with,
// then use the returned buffer size (doubled)
// to Alloc the buffer. Keep calling until
// success or an unknown failure.
//
// Double the returned buffersize to correct
// for underlying legacy CM functions that
// return an incorrect buffersize value on
// DBCS/MBCS systems.
//
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_FRIENDLYNAME,
//SPDRP_DEVICEDESC,
//SPDRP_CAPABILITIES,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() ==
ERROR_INSUFFICIENT_BUFFER)
{
// Change the buffer size.
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = (wchar_t *)LocalAlloc(LPTR,buffersize * 2);
}
else
{
// Insert error handling here.
break;
}
}
if(buffer)
{
if( strcmp("Name of Device",AnsiString(buffer).c_str())==0)
{
fprintf(devices,"Result:[%s]",AnsiString(buffer).c_str());
if (buffer) LocalFree(buffer);
}
}
}
if ( GetLastError()!=NO_ERROR &&
GetLastError()!=ERROR_NO_MORE_ITEMS )
{
// Insert error handling here.
return 1;
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
fclose(devices);
return 0;
}
Instead of using SetupDiEnumDeviceInfo, you would try:
1. using SetupDiEnumDeviceInterfaces
2. using SetupDiGetDeviceInterfaceProperty
3. using SetupDiGetDeviceInterfacePropertyKeys to get a list of all Property Keys available for the interface
4. using SetupDiGetDeviceProperty and/or SetupDiGetDeviceRegistryProperty
Instead of using SPDRP_XXX constants, you would use DEVPROP, as defined in 'devpkey.h' ...
Below are a few examples taken from the log of a test prog I wrote to discover the whole thing:
DEVPROPNAME: DEVPKEY_DeviceInterface_Bluetooth_DeviceAddress
DEVPROPGUID: {2BD67D8B-8BEB-48D5-87E0-6CDA3428040A}
DEVPROPPID: 1
DEVPROPTYPE: DEVPROP_TYPE_STRING
Value: c026df001017
DEVPROPNAME: DEVPKEY_Device_Children
DEVPROPGUID: {4340A6C5-93FA-4706-972C-7B648008A5A7}
DEVPROPPID: 9
DEVPROPTYPE: DEVPROP_TYPE_STRING_LIST
Value:
BTHLEDevice\{00001800-0000-1000-8000-00805f9b34fb}_c026df001017\8&2fd07168&1&0001
BTHLEDevice\{00001801-0000-1000-8000-00805f9b34fb}_c026df001017\8&2fd07168&1&0008
BTHLEDevice\{00001809-0000-1000-8000-00805f9b34fb}_c026df001017\8&2fd07168&1&000c
BTHLEDevice\{0000180f-0000-1000-8000-00805f9b34fb}_c026df001017\8&2fd07168&1&0010
BTHLEDevice\{0000180a-0000-1000-8000-00805f9b34fb}_c026df001017\8&2fd07168&1&0014
BTHLEDevice\{00001523-1212-efde-1523-785feabcd123}_c026df001017\8&2fd07168&1&0019
On a second subject, you are 'working' on the 'device' itself ( SetupDiGetClassDevs(&BluetoothInterfaceGUID...) [and then working on the \BTHLE\ tree in Registry].
After listing all GattServices of this device and getting their uuids, you could restart that iteration on the device_guid itself SetupDiGetClassDevs(&GattServiceGUID...) [and then working on the \BTHLEDevice\ tree in Registry].
Now, to answer your question, I'm still searching myself :) But I'm not really sure:
1) that it is a working (dynamic) information to know the connection state
2) that it is a 'Property' you can access by the above methods
I have found out a solution.
GUID AGuid;
//GUID can be constructed from "{xxx....}" string using CLSID
CLSIDFromString(TEXT(TO_SEARCH_DEVICE_UUID), &AGuid);
GUID BluetoothInterfaceGUID = AGuid;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(&BluetoothInterfaceGUID,
0, // Enumerator
0,
DIGCF_ALLCLASSES | DIGCF_PRESENT);//DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);//DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return 1;
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i,
&DeviceInfoData);i++)
{
DWORD DataT;
LPTSTR buffer = NULL;
LPTSTR buffer1 = NULL;
DWORD buffersize = 0;
while (!SetupDiGetDeviceRegistryProperty( // Get Name
hDevInfo,
&DeviceInfoData,
SPDRP_FRIENDLYNAME,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() ==
ERROR_INSUFFICIENT_BUFFER)
{
// Change the buffer size.
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = (wchar_t *)LocalAlloc(LPTR,buffersize * 2);
}
else
{
// Insert error handling here.
break;
}
}
{
if(strcmp("Your Device",AnsiString(buffer).c_str())==0) //Found your device
{
//########
DEVPROPTYPE ulPropertyType;
DWORD dwSize;
ULONG devst;
// memset(devst,0,sizeof(devst));
bool err = SetupDiGetDeviceProperty( //Checking Connection State
hDevInfo,
&DeviceInfoData,
&DEVPKEY_Device_DevNodeStatus, //Connected(0x02000000)
&ulPropertyType,
(BYTE *) &devst,
sizeof(devst),
&dwSize,
0);
DWORD error;
error = GetLastError();
if (devst &0x02000000) {
//"Status: Getrennt "
}
else
{
//"Status: Verbunden"
}
Hope this snippet helps.

Crash when calling ReadFile after LockFileEx

I have several processes that try to read and write the same file. I want each of them to lock the file so that only one of them accesses it at a time.
I tried this (edit: this is a complete test code this time):
#include "stdafx.h"
#include "Windows.h"
bool test()
{
const char* path = "test.txt";
HANDLE hFile = CreateFileA(path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("ERROR: Cannot open file %s\n", path);
return false;
}
// Lock the file
{
OVERLAPPED overlapped = {0};
BOOL res = LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, ~0, ~0, &overlapped);
if (!res)
{
printf("ERROR: Cannot lock file %s\n", path);
return false;
}
}
DWORD fileSize = GetFileSize(hFile, NULL);
if (fileSize > 0)
{
char* content = new char[fileSize+1];
// Read the file
BOOL res = ReadFile(hFile, content, fileSize, NULL, NULL);
if (!res)
{
printf("ERROR: Cannot read file %s\n", path);
}
delete[] content;
}
const char* newContent = "bla";
int newContentSize = 3;
// Write the file
BOOL res = WriteFile(hFile, newContent, newContentSize, NULL, NULL);
if (!res)
{
//int err = GetLastError();
printf("ERROR: Cannot write to file\n");
}
// Unlock the file
{
OVERLAPPED overlapped = {0};
UnlockFileEx(hFile, 0, ~0, ~0, &overlapped);
}
CloseHandle(hFile);
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
bool res = test();
return 0;
}
This works fine on my computer, which has Windows 8. But on my colleague's computer, which has Windows 7, it crashes. Specifically, the calls to ReadFile and WriteFile crash, always.
Note that it never enters the code paths with the error printfs. This code triggers no error except for a write at location 0x00000000 in ReadFile (when run on Windows 7).
We tried to also pass the overlapped struct to the ReadFile and WriteFile calls. It prevents the crash but the lock doesn't work anymore, the file is all scrambled (not with this test code, with the real code).
What am I doing wrong?
Looks like your problem is:
lpNumberOfBytesRead [out, optional] argument is null in your call.
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
Heres your problem :
You are missing a necessary struct-member and:
0 and ~0 and {0} are all bad code, constant expressions like these will always produce unepected results -- WINAPI doesnt work like libc, parameters are not always compared against constants, instead they are tested against/via macros and other preprocessor-definitions themselves so passing constant values or initializing WINAPI structs with constants will often lead to errors like these.
After years of experimenting i have found that there is only one surefire way of avoiding them, i will express it in corrected code :
OVERLAPPED overlapped;
overlapped.hEvent = CreateEvent( ........... ); // put valid parameters here!
UnlockFileEx(hFile, 0 /*"reserved"*/, ULONG_MAX, ULONG_MAX, &overlapped);
please read this carefully : http://msdn.microsoft.com/en-us/library/windows/desktop/aa365716%28v=vs.85%29.aspx

Visual Studio errors and getting a device GUID and path name?

Evening everyone I wondered if some could answer me 2 quick questions.
I made an app to communicate with arm device which works fine, however when I move PC etc, I need to reconfigure the device path. Its a long one like below.
Path: \\?\usb#vid_045e&pid_0040#6&ff454f2&0&3#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
I done some reading up and discovered it's two features SetupDiGetClassDevs and SetupDiGetDeviceInstanceId I need. My question is am I looking in the right place i.e will these 2 functions return the path like above. Also what is the techinical name for this path?
I found what I think is a nice example (always learn better from example) on Microsoft's website cut and paste below but this throws up error C2440: '=' : cannot convert from 'HLOCAL' to 'LPTSTR'
which is a new one on me a pointer error?
This is the code
#include <stdio.h>
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
#include <regstr.h>
int main( int argc, char *argv[ ], char *envp[ ] )
{
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES );
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return 1;
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i,
&DeviceInfoData);i++)
{
DWORD DataT;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
//
// Call function with null to begin with,
// then use the returned buffer size (doubled)
// to Alloc the buffer. Keep calling until
// success or an unknown failure.
//
// Double the returned buffersize to correct
// for underlying legacy CM functions that
// return an incorrect buffersize value on
// DBCS/MBCS systems.
//
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_DEVICEDESC,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() ==
ERROR_INSUFFICIENT_BUFFER)
{
// Change the buffer size.
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = LocalAlloc(LPTR,buffersize * 2); // ERROR LINE
}
else
{
// Insert error handling here.
break;
}
}
printf("Result:[%s]\n",buffer);
if (buffer) LocalFree(buffer);
}
if ( GetLastError()!=NO_ERROR &&
GetLastError()!=ERROR_NO_MORE_ITEMS )
{
// Insert error handling here.
return 1;
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
return 0;
}
Hope its an easy one thank you.
You need to typecast the return value from LocalAlloc():
buffer = (LPSTR) LocalAlloc(LPTR,buffersize * 2);
For more info, see the LocalAlloc() documentation on MSDN.

Send IOCTL to Windows device driver - CreateFile fails

I want to send an IOCTL command to a PC/SC reader connected to my computer (win7 64 bit).
In order to send an IOCTL command I need a HANDLE to the device, which I'm unable to create.
The device is listed as "OMNIKEY 1021" in the device manager, the physical device object name is "\Device\USBPDO-15". Using the "WinObj" tool, I can detect 2 symlinks:
USB#VID_076B&PID_1021#5&291f6990&0&1#{50dd5230-ba8a-11d1-bf5d-0000f805f530}
USB#VID_076B&PID_1021#5&291f6990&0&1#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
My problem: I cannot create a valid handle to this device with the CreateFile function:
I found several possible formats on MSDN/Google to use as the lpFileName param of the CreateFile function, but none of them seem to work:
\\?\Device\USBPDO-15
\\.\Device\USBPDO-15
\\GLOBAL??\Device\USBPDO-15
\GLOBAL??\Device\USBPDO-15
\\.\USBPDO-15
\\?\USB#VID_076B&PID_1021#5&291f6990&0&1#{50dd5230-ba8a-11d1-bf5d-0000f805f530}
\\.\USB#VID_076B&PID_1021#5&291f6990&0&1#{50dd5230-ba8a-11d1-bf5d-0000f805f530}
\\GLOBAL??\USB#VID_076B&PID_1021#5&291f6990&0&1#{50dd5230-ba8a-11d1-bf5d-0000f805f530}
\GLOBAL??\USB#VID_076B&PID_1021#5&291f6990&0&1#{50dd5230-ba8a-11d1-bf5d-0000f805f530}
\\?\USB#VID_076B&PID_1021#5&291f6990&0&1#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
\\.\USB#VID_076B&PID_1021#5&291f6990&0&1#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
\\GLOBAL??\USB#VID_076B&PID_1021#5&291f6990&0&1#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
\GLOBAL??\USB#VID_076B&PID_1021#5&291f6990&0&1#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
Code sample:
#include <iostream>
#include <Windows.h>
int main (int argc, char* argv[])
{
HANDLE handle = CreateFile (
L"\\\\.\\Device\\USBPDO-15",
0,
FILE_SHARE_READ, //FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0, //FILE_FLAG_OVERLAPPED,
NULL
);
if (handle == INVALID_HANDLE_VALUE)
std::cout << "INVALID HANDLE" << std::endl;
else
std::cout << "HANDLE: " << std::hex << handle << std::endl;
}
Notes:
The returned handle is always invalid
Always running as Administrator, so the privileges should not be a problem
edit:
Solution:
The PC/SC service takes exclusive ownership of the devices, so any attempt to call 'CreateFile' will always fail.
The solution is a kernel space driver, this allows you to pass IRP's to the driver. (I was able to implement a KMDF filter driver to alter data sent/received to/from the device)
Try it my way. I'm using Setup API to enumerate all USB active devices in the system and get paths. That way you can find out whether it's the path or other arguments that CreateFile doesn't like.
I'll add some comments a bit later, if anyone's interested.
HDEVINFO hDevInfo = SetupDiGetClassDevs( &_DEVINTERFACE_USB_DEVICE, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if(hDevInfo == INVALID_HANDLE_VALUE)
{
return ERR_FAIL;
}
std::vector<SP_INTERFACE_DEVICE_DATA> interfaces;
for (DWORD i = 0; true; ++i)
{
SP_DEVINFO_DATA devInfo;
devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
BOOL succ = SetupDiEnumDeviceInfo(hDevInfo, i, &devInfo);
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
if (!succ) continue;
SP_INTERFACE_DEVICE_DATA ifInfo;
ifInfo.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
if (TRUE != SetupDiEnumDeviceInterfaces(hDevInfo, &devInfo, &(_DEVINTERFACE_USB_DEVICE), 0, &ifInfo))
{
if (GetLastError() != ERROR_NO_MORE_ITEMS)
break;
}
interfaces.push_back(ifInfo);
}
std::vector<SP_INTERFACE_DEVICE_DETAIL_DATA*> devicePaths;
for (size_t i = 0; i < interfaces.size(); ++i)
{
DWORD requiredSize = 0;
SetupDiGetDeviceInterfaceDetail(hDevInfo, &(interfaces.at(i)), NULL, NULL, &requiredSize, NULL);
SP_INTERFACE_DEVICE_DETAIL_DATA* data = (SP_INTERFACE_DEVICE_DETAIL_DATA*) malloc(requiredSize);
assert (data);
data->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &(interfaces.at(i)), data, requiredSize, NULL, NULL))
{
continue;
}
devicePaths.push_back(data);
}
Just try with CreateFile(L"\\\\.\\{GUID}",etc...

Serial Comm using WriteFile/ReadFile

//#include "StdAfx.h"
#include <stdio.h>
#include <windows.h>
#include <winbase.h>
#include <iostream>
#include <tchar.h>
using namespace std;
int main()
{
int com = 'COM2';
string data = "\n 010400 \n";
char output[32];
//unsigned int length = 0;
DCB config = {0};
bool abContinue = true;
DWORD dwBytesWritten;
DWORD dwBytesRead;
int isRead = false;
HANDLE m_hCommPort = ::CreateFile(L"COM2",
GENERIC_READ|GENERIC_WRITE,//access ( read and write)
0, //(share) 0:cannot share the COM port
0, //security (None)
OPEN_EXISTING,// creation : open_existing
0, // we dont want overlapped operation
0// no templates file for COM port...
);
config.DCBlength = sizeof(config);
if((GetCommState(m_hCommPort, &config) == 0))
{
printf("Get configuration port has a problem.");
return FALSE;
}
config.BaudRate = 9600;
config.StopBits = ONESTOPBIT;
config.Parity = PARITY_NONE;
config.ByteSize = DATABITS_8;
config.fDtrControl = 0;
config.fRtsControl = 0;
if (!SetCommState(m_hCommPort, &config))
{
printf( "Failed to Set Comm State Reason: %d\n",GetLastError());
//return E_FAIL;
}
printf("Current Settings\n Baud Rate %d\n Parity %d\n Byte Size %d\n Stop Bits %d", config.BaudRate,
config.Parity, config.ByteSize, config.StopBits);
int isWritten = WriteFile(m_hCommPort, &data,(DWORD) sizeof(data), &dwBytesWritten, NULL);
//memset(output, 0, sizeof(output));
while (abContinue)
{
isRead = ReadFile(m_hCommPort, output, sizeof(output), &dwBytesRead, NULL);
if(!isRead)
{
abContinue = false;
break;
}
}
cin.get();
}
I am having trouble reading from the com port. If I step through the code, it goes into "isRead = ReadFile(m_hCommPort, output, sizeof(output), &dwBytesRead, NULL);" and doesn't come back out.... This is my first try at this with no success.
You might try some code something like this after you've opened the file, but before you try to use it:
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(m_hCommPort, &timeouts))
// setting timeouts failed.
Edit: perhaps it's easier to start with some code that works, and make it do what you want rather than trying to get your code to work. Here's a simple terminal program. It's minimalist in the extreme, but does work (at least well enough to let me see output from my GPS, for one example). It's a long ways from what anybody (least of all me) would call sophisticated, but should give at least some idea of how to get started.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
void system_error(char *name) {
// Retrieve, format, and print out a message from the last error. The
// `name' that's passed should be in the form of a present tense noun
// (phrase) such as "opening file".
//
char *ptr = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
GetLastError(),
0,
(char *)&ptr,
1024,
NULL);
fprintf(stderr, "\nError %s: %s\n", name, ptr);
LocalFree(ptr);
}
int main(int argc, char **argv) {
int ch;
char buffer[1];
HANDLE file;
COMMTIMEOUTS timeouts;
DWORD read, written;
DCB port;
HANDLE keyboard = GetStdHandle(STD_INPUT_HANDLE);
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode;
char port_name[128] = "\\\\.\\COM3";
char init[] = ""; // e.g., "ATZ" to completely reset a modem.
if ( argc > 2 )
sprintf(port_name, "\\\\.\\COM%c", argv[1][0]);
// open the comm port.
file = CreateFile(port_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if ( INVALID_HANDLE_VALUE == file) {
system_error("opening file");
return 1;
}
// get the current DCB, and adjust a few bits to our liking.
memset(&port, 0, sizeof(port));
port.DCBlength = sizeof(port);
if ( !GetCommState(file, &port))
system_error("getting comm state");
if (!BuildCommDCB("baud=19200 parity=n data=8 stop=1", &port))
system_error("building comm DCB");
if (!SetCommState(file, &port))
system_error("adjusting port settings");
// set short timeouts on the comm port.
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(file, &timeouts))
system_error("setting port time-outs.");
// set keyboard to raw reading.
if (!GetConsoleMode(keyboard, &mode))
system_error("getting keyboard mode");
mode &= ~ ENABLE_PROCESSED_INPUT;
if (!SetConsoleMode(keyboard, mode))
system_error("setting keyboard mode");
if (!EscapeCommFunction(file, CLRDTR))
system_error("clearing DTR");
Sleep(200);
if (!EscapeCommFunction(file, SETDTR))
system_error("setting DTR");
if ( !WriteFile(file, init, sizeof(init), &written, NULL))
system_error("writing data to port");
if (written != sizeof(init))
system_error("not all data written to port");
// basic terminal loop:
do {
// check for data on port and display it on screen.
ReadFile(file, buffer, sizeof(buffer), &read, NULL);
if ( read )
WriteFile(screen, buffer, read, &written, NULL);
// check for keypress, and write any out the port.
if ( kbhit() ) {
ch = getch();
WriteFile(file, &ch, 1, &written, NULL);
}
// until user hits ctrl-backspace.
} while ( ch != 127);
// close up and go home.
CloseHandle(keyboard);
CloseHandle(file);
return 0;
}
If you do not explicitly set the timeouts, then ReadFile will indefinitely block until data becomes available.
ReadFile function may be blocking your thread,if so, it will remain blocked until some data can be read from Serial port. Here is a link see if its help. Good luck.
I had this problem on a readfile, with the timeouts set. This was driving me crackers so I ended up getting some code from the web which did work and then changing line by line to see where the error was.
Turns out he readfile was fine. My problem was a WaitCommEvent which was hanging when the port was disconnected as no com event is ever received...