How to read file from USB mass storage Device using Visual C++? - c++

I developed an MFC Dialog application in C++ in MS VS 2013 Ultimate under Windows 7 Maximal. As a progenitor of source code I use CodeProject paper in Detecting Hardware Insertion or Removal.
My application is a user-mode application. It is intended for detection of adding or removing hardware from/to computer. For this purpose I handle WM_DEVICECHANGE message and call RegisterDeviceNotification() function in my application. So, schematically, my aplication does the following:
Calls SetupDiGetClassDevs() to get a handle of device info set HDEVINFO.
Calls SetupDiEnumDeviceInfo() to enumerate all the device in the info set. Upon each iteration, we will get a SP_DEVINFO_DATA.
During the enumeration, SetupDiGetDeviceInstanceId() is called to read the instance ID for each device. The instance ID is in the form of "USB\Vid_04e8&Pid_503b\0002F9A9828E0F06".
If the instance ID match the DEV_BROADCAST_DEVICEINTERFACE.dbcc_name, then SetupDiGetDeviceRegistryProperty() is called to retrieve the description or friendly name.
But now I'm in need of reading of file from USB mass storage device when this device is pluged in (when the DBT_DEVICEARRIVAL device event has place). How can I do it programmatically in Visual C++?

The parameter of DBT_DEVICEARRIVAL is a DEV_BROADCAST_VOLUME which includes a mask of the drive letter assinged. So since you are only after mass storage devices the following works.
DEV_BROADCAST_VOLUME *pj = (DEV_BROADCAST_VOLUME*) lParam;
if (pj->dbcv_devicetype == DBT_DEVTYPE_VOLUME) {
long um = pj->dbcv_unitmask;
for ( int i=0; i < 26; i++ ) {
if (um&1) break;
um = um >> 1;
}
if ( i < 26 ) {
char Drive = 'A' + i;
}
}
In practice, some drives are ready to read instantly, others need few seconds.

Related

How to track screens through time? [duplicate]

I have a setup with two regular displays and three projectors connected to a windows pc. In my win32 program I need to uniquely identify each monitor and store information for each such that I can retrieve the stored information even after computer restart.
The EnumDisplayDevices seems to return different device orders after restarting the computer. There is also GetPhysicalMonitorsFromHMONITOR which at least gives me the display's name. However, I need something like a serial number for my projectors, since they are the same model. How can I get such a unique identifier?
EDIT: This is the solution I came up with after reading the answer from user Anders (thanks!):
DISPLAY_DEVICEA dispDevice;
ZeroMemory(&dispDevice, sizeof(dispDevice));
dispDevice.cb = sizeof(dispDevice);
DWORD screenID;
while (EnumDisplayDevicesA(NULL, screenID, &dispDevice, 0))
{
// important: make copy of DeviceName
char name[sizeof(dispDevice.DeviceName)];
strcpy(name, dispDevice.DeviceName);
if (EnumDisplayDevicesA(name, 0, &dispDevice, EDD_GET_DEVICE_INTERFACE_NAME))
{
// at this point dispDevice.DeviceID contains a unique identifier for the monitor
}
++screenID;
}
EnumDisplayDevices with the EDD_GET_DEVICE_INTERFACE_NAME flag should give you a usable string. And if not, you can use this string with the SetupAPI to get the hardware id or driver key or whatever is unique enough for your purpose.
Set this flag to EDD_GET_DEVICE_INTERFACE_NAME (0x00000001) to retrieve the device interface name for GUID_DEVINTERFACE_MONITOR, which is registered by the operating system on a per monitor basis. The value is placed in the DeviceID member of the DISPLAY_DEVICE structure returned in lpDisplayDevice. The resulting device interface name can be used with SetupAPI functions and serves as a link between GDI monitor devices and SetupAPI monitor devices.

Get unique identifier for Windows monitors

I have a setup with two regular displays and three projectors connected to a windows pc. In my win32 program I need to uniquely identify each monitor and store information for each such that I can retrieve the stored information even after computer restart.
The EnumDisplayDevices seems to return different device orders after restarting the computer. There is also GetPhysicalMonitorsFromHMONITOR which at least gives me the display's name. However, I need something like a serial number for my projectors, since they are the same model. How can I get such a unique identifier?
EDIT: This is the solution I came up with after reading the answer from user Anders (thanks!):
DISPLAY_DEVICEA dispDevice;
ZeroMemory(&dispDevice, sizeof(dispDevice));
dispDevice.cb = sizeof(dispDevice);
DWORD screenID;
while (EnumDisplayDevicesA(NULL, screenID, &dispDevice, 0))
{
// important: make copy of DeviceName
char name[sizeof(dispDevice.DeviceName)];
strcpy(name, dispDevice.DeviceName);
if (EnumDisplayDevicesA(name, 0, &dispDevice, EDD_GET_DEVICE_INTERFACE_NAME))
{
// at this point dispDevice.DeviceID contains a unique identifier for the monitor
}
++screenID;
}
EnumDisplayDevices with the EDD_GET_DEVICE_INTERFACE_NAME flag should give you a usable string. And if not, you can use this string with the SetupAPI to get the hardware id or driver key or whatever is unique enough for your purpose.
Set this flag to EDD_GET_DEVICE_INTERFACE_NAME (0x00000001) to retrieve the device interface name for GUID_DEVINTERFACE_MONITOR, which is registered by the operating system on a per monitor basis. The value is placed in the DeviceID member of the DISPLAY_DEVICE structure returned in lpDisplayDevice. The resulting device interface name can be used with SetupAPI functions and serves as a link between GDI monitor devices and SetupAPI monitor devices.

Access Strucuture Sensor via OpenNI 2 from UWP App targeting Windows 10

I'd like to access the Structure Sensor (https://structure.io) via OpenNI 2 (https://github.com/occipital/openni2) from an UWP App running on a Windows 10 Desktop.
The Setup
For this very reason I created a Windows Runtime Component (Universal Windows) in C++ besides my actual UWP App. This component exports several functions basically miming the initialization behavior of one of the samples in above OpenNI Github repo.
I extended the code to also iterate through all available devices:
// Initialize OpenNI
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
logError("Initialize failed + " + std::string(OpenNI::getExtendedError()));
return false;
}
// Get all attached sensors supported by OpenNI
Array<DeviceInfo> deviceList;
OpenNI::enumerateDevices(&deviceList);
for (int i = 0; i < deviceList.getSize(); i++) {
logInfo(deviceList[i].getName());
logInfo(deviceList[i].getUri());
}
// Actual open device
Device device;
rc = device.open(deviceList[0].getUri());
if (rc != STATUS_OK)
{
logError("Error = " + to_string(rc));
logError("Couldn't open device " + std::string(OpenNI::getExtendedError()));
return false;
}
The Problem
Calling above code from my UWP app through the Windows Runtime Component is successful when initializing OpenNI and enumerating over all available devices:
[INFO] PS1080
[INFO] \\?\usb#vid_1d27&pid_0600#13261#{c3b5f022-5a42-1980-1909-ea72095601b1}
Actually Opening the device via device.open is the actual problem (Error 1 = STATUS_ERROR)
[ERROR] Error = 1
[ERROR] Couldn't open device Could not open "\\?\usb#vid_1d27&pid_0600#13261#{c3b5f022-5a42-1980-1909-ea72095601b1}": USB device not found!
I'm also under the impression that above error message is a bit misleading, as the actual message when having no device attached is:
[ERROR] Error = 1
[ERROR] Couldn't open device DeviceOpen using default: no devices found
I already tried to add a USB device capability to the package mainifest without any success.
<DeviceCapability Name="usb">
<Device Id="vidpid:1D27 0600">
<!--<Function Type="classId:ff * *" />-->
<Function Type="name:vendorSpecific"/>
</Device>
</DeviceCapability>
I also verified that above code is working when directly building a classic C++ program without targeting UWP at all.
I would be very happy for any direction/hint you can provide me with
The Solution
Microsoft's UWP policy simply doesn't allow access to USB devices. But you can workaround that by grant the UWP AppContainer Process access to the Structure IO sensor.
Some manual work is required though:
Open the registry editor and go to the USB entry of the Structure IO sensor HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\VID_1D27&PID_0600
Uncollapse this node and right click on the node below this one and copy the whole key in to clipboard. The last digit is very important here and differs from machine to machine (e.g. HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\VID_1D27&PID_0600\13261)
Copy this key into following registry file where the brackets are. The following registry modification basically allows every UWP app access to the structure I/O sensor.
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\VID_1D27&PID_0600\13261]
"Security"=hex:1,0,4,90,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,2,0,60,0,4,0,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,12,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,5,20,0,0,0,20,2,0,0,0,0,14,0,0,0,0,10,1,1,0,0,0,0,0,5,B,0,0,0,0,0,18,0,0,0,0,10,1,2,0,0,0,0,0,F,2,0,0,0,1,0,0,0
Modify the following batch script to point to the full path(!) of above registry file. This script is needed to modify the registry with the security string. This is only allowed by Window's SYSTEM account. That's why we need to create a task for that.
call schtasks /create /RU SYSTEM /SC ONCE /TN DeviceAC /TR "reg import c:\full\path\to\registry\file.reg" /ST 00:00
call schtasks /run /tn DeviceAC
call schtasks /delete /tn DeviceAC /f
Run the above batch script with Administrator privileges
After successfully executing the script, make sure there's a new entry called "Security" below you node from 2.
If the sensor is already connected to your PC you'll need to reconnect it.
Now the code from my Question above should work :)
You'll find a detailed read on how to solve this problem here:
https://developer.microsoft.com/en-us/windows/iot/Samples/CustomDeviceAccessor

input delay with PortAudio callback and ASIO sdk

I'm trying to get the input from my guitar to be played through my computer using the portaudio library and the ASIO sdk.
I have been following some of the tutorials on the official website to get the basics set up. Currently I got it working so that portaudio is listening to the right input and output device and I have the callback setup to just output the input and do nothing with it like this:
static int paTestCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
{
float *out = (float*)outputBuffer;
float* in = (float*)inputBuffer;
for (int i = 0; i<framesPerBuffer; i++)
{
*out++ = *in++; /* left */
*out++ = *in++; /* right */
}
return 0;
}
This callback is setup by calling this:
PaError error = Pa_OpenDefaultStream(&stream, 2, 2, paFloat32, 44100, paFramesPerBufferUnspecified, paTestCallback, &data);
Pa_StartStream(stream);
Now, this does work but I have a lot of delay (about 0.5s) when I strike a string on my guitar and when I hear it through the monitors.
Is there a way to solve this delay? Do I need to rewrite the callback method?
EDIT:
So, I got the delay to be a lot better using this code instead of the basic Pa_OpenDefaultStream()
int defaultIn = Pa_GetDefaultInputDevice();
int defaultOut = Pa_GetDefaultOutputDevice();
PaStreamParameters *inParam = new PaStreamParameters();
inParam->channelCount = 2;
inParam->device = defaultIn;
inParam->sampleFormat = paFloat32;
inParam->suggestedLatency = 0.05;
PaStreamParameters *outParam = new PaStreamParameters();
outParam->channelCount = 2;
outParam->device = defaultOut;
outParam->sampleFormat = paFloat32;
outParam->suggestedLatency = 0;
error = Pa_OpenStream(&stream, inParam, outParam, 44100, paFramesPerBufferUnspecified, paNoFlag, paTestCallback, &data);
if (error != paNoError) {
Logger::log("[PortAudioManager] Could not open default stream. Exiting function...");
return;
}
Pa_StartStream(stream);
There is still a little bit of delay though, mostly noticeable when playing more then just a single note.
EDIT:
I figured out with the help of Ross-Bencina that the windows default input device and output device doesn't change anything to the index of the host api's in PortAudio. I seemed to be using MME all this time. I did the following to get the right index for the ASIO device:
int hostNr = Pa_GetHostApiCount();
std::vector<const PaHostApiInfo*> infoVertex;
for (int t = 0; t < hostNr; ++t) {
infoVertex.push_back(Pa_GetHostApiInfo(t));
}
Then I just checked which is the one with ASIO and set the suggestedLatency in both PaStreamParameters to 0 and the delay is now gone and sound is good (although it's mono for now).
You are on the right track using paFramesPerBufferUnspecified.
The ASIO latency behavior depends on the driver. There are two possibilities:
The ASIO driver lets the code (i.e. PortAudio) request a latency (possibly with some constraints). PortAudio finds to best match between a supported driver buffer size and the latency that you request.
The other possibility is that your audio interface does not provide programmatic control over latency settings. Instead, latency is only selectable from the driver's ASIO control panel UI (and the driver will force a fixed buffer size on PortAudio). In this case, you should investigate the driver control panel UI to set the lowest workable latency.
In either case, your approach with Pa_OpenStream is close to optimal, but you should request zero latency for both input and output (in your edit you're requesting 50ms input latency, zero output latency). The end result will be that PortAudio selects the lowest available ASIO buffer size. If this turns out to be unstable (audio glitches) then you'll need to increase the requested latency.
include/pa_asio.h exposes a host-API-specific interface for querying the ASIO buffer sizes allowed by the driver (be aware that this can change if you change settings in the control panel). It also provides a function to display the driver's control panel UI.
EDIT: Note that Pa_GetDefaultInputDevice() and Pa_GetDefaultOutputDevice() will only return ASIO devices if you built PortAudio for ASIO only. If you included any other more common APIs in the build (e.g. WMME or DirectSound) they will be given priority as the (lowest common denominator) default device. You could add a check that you are actually accessing the ASIO device:
assert(Pa_GetHostApiInfo(Pa_GetDeviceInfo(Pa_GetDefaultOutputDevice())->hostApi)->type == paASIO);
If PortAudio is compiled with support for multiple host APIs: To get the default ASIO device: enumerate host APIs using Pa_GetHostApiCount and Pa_GetHostApiInfo to find the ASIO host API. Then pull the default ASIO device indices from the returned PaHostApiInfo struct.

How to enumerate an USB hub that is attached to the first port of root hub on Windows Embedded 7

I am posting here for the first time, I hope this will be clear and readable.
I am currently trying to test the presence of usb devices on an embedded system using a specific HCD and port path programmatically using C++ and Visual Studio 2008.
The idea is to pass in the port number and the hcd value as the parameters of the function, and the function will return a true or false that indicates the connection status.
I have written some code to populate the root hub and prove that the device attached to port 1 of the root hub is a hub using bool DeviceIsHub from usbioctl.h.
However, when I attempt to enumerate the usb hub attached to port 1 of root so that I may test for the connection status of the downstream ports for the presence of device(ports 1 and 2 of this usb hub). It does not seem to know how many downstream ports the usb hub has.
I checked USBVIEW/TreeView, both application tells me that devices are there
but I am not sure what ioctl command code to use such that I can enumerate the downstream ports so I can check the connection status.
The structure of the device based on USB view and USB tree provides the following.
Root hub - it has 7 ports, only the first port is being used.
A USB hub (it has four available ports) is attached to the first port of the root hub.
Two USB devices (USB mouse and USB keyboard) are attached to port 1 and port 2 of the USB hub.
I have tried IOCTL_USB_GET_CONNECTION_INFORMATION, IOCTL_USB_GET_CONNECTION_NAME,
IOCTL_USB_GET_CONNECTION_INFORMATION_EX, IOCTL_USB_PORT_CONNECTOR_PROPERTIES
(which is not supported, it can only be used in windows 8, this is the exact ioctl call they used to enumerate the ports).
Please ignore the MessageBoxes, those are for me to check the control path status and determine which route it was following.
Please find the code that I wrote as I attempt to enumerate/populate the usb hub. I did not include the Root hub code because it would make this snippet too big.
My questions mainly resides in the enumeration process of the secondary USB hub I believe.
I just checked the registry key of the device. it appears that the USB hub is enumerated and present on the device since the information is shown under regedit HKLM->System->CurrentControlSet->Enum->USB. I believe I am not enumerating it correctly within my test application.
Any help would be greatly appreciated.
Update
The part that I am most concerned about is the DeviceIoControl Calls that attempts to get the size and the actual name of that USB hub.
It currently only takes in USB_GET_NODE_INFORMATION. Any other ioctl calls that are intended to retrieve the name of the hub will fail at the first DeviceIoControl where it attempts to get the size of the hub name so that it know how much memory to allocate
for it.
Update Part 2
From observing the usbview open source code, I believe I need to enumerate the host controller and all the devices first before checking for the presence of device. I drew a conclusion such that without doing the enumeration of controller, it only goes so far down the tree (at best second layer, which is where the external hub is attached to in my case).
I am currently attempting to enumerate the other devices and controllers in hope that I can get to the third layer of device. I will keep on updating this thread until either I figure out the problem myself or someone is capable of answering my questions.
//we are connected to the external hub, now we can begin the configuration and enumeration of the external hub.
ULONG kBytes = 0;
USB_HUB_NAME SubHubName;
//Create a Handle for the external hub driver
char Name[16];
wsprintf(Name, "\\\\.\\HCD%d", HcdSub);
HANDLE SubHub = CreateFile(Name,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
//Check to see if the handle was created successfully
if (SubHub == INVALID_HANDLE_VALUE)
{
MessageBox(NULL,"SubHandle Fail ","TEST",MB_OK);
return false;
}
//Query the SUBHUB/External Hub for the structure, this will tell us the number of down stream ports we need to enumerate
ioctlSuccess = DeviceIoControl(SubHub,
IOCTL_USB_GET_NODE_INFORMATION,
0,
0,
&SubHubName,
sizeof(SubHubName),
&kBytes,
NULL);
//If the command failed, close the handle and return false.
if(!ioctlSuccess)
{
CloseHandle(SubHub);
MessageBox(NULL," sub hub size fail ","TEST",MB_OK);
return false;
}
//Prepare to receive the SubHubName
kBytes = SubHubName.ActualLength;
USB_HUB_NAME *subHubNameW = (USB_HUB_NAME *) malloc(sizeof(USB_HUB_NAME) * kBytes);
//Check if the allocation failed, if it did, free the memory allocated and return false.
if (subHubNameW == NULL)
{
free(subHubNameW);
CloseHandle(SubHub);
MessageBox(NULL,"SUBHubNameW=NULL ","TEST",MB_OK);
return false;
}
//Send the command to retrieve the name
ioctlSuccess = DeviceIoControl(SubHub,
IOCTL_USB_GET_NODE_INFORMATION,
NULL,
0,
subHubNameW,
kBytes,
&kBytes,
NULL);
//We no longer need this handle.
CloseHandle(SubHub);
if(!ioctlSuccess)
{
if(subHubNameW !=NULL)
{
free(subHubNameW);
}
MessageBox(NULL,"GET NODE INFO FAIL ","TEST",MB_OK);
return false;
}
//Converts the SubHubNAme from widechar to a cahr.
MessageBox(NULL,"BEGIN CONVERTION","TEST",MB_OK);
kBytes = wcslen(subHubNameW->HubName) + 1;
char *subhubname = (char *) malloc(sizeof(char)*kBytes);
wcstombs(subhubname,subHubNameW->HubName, kBytes);
//we no longer need subHubNameW the information is now in subhubname.
if(subHubNameW !=NULL)
{
free(subHubNameW);
}
//Attempt to open a handle to driver for sub hub.
int SubhdnSize = strlen(subhubname) + sizeof("\\\\.\\");
char *subhubnamelength = (char *) malloc(sizeof(char) * SubhdnSize);
sprintf(subhubnamelength, "\\\\.\\%s", subhubname);
//We no longer need subhubname, so free it.
if(subhubname !=NULL) free(subhubname);
//Attempt to open a handle for enumerating ports on this hub.
HANDLE ExternalHub = CreateFile(subhubnamelength,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
//we no longer need subhubnamelength, so free it if it is not NULL
if(subhubnamelength != NULL) free(subhubnamelength);
//Check and see if the handle was created successfully, if not, return false.
if(ExternalHub == INVALID_HANDLE_VALUE)
{
CloseHandle(ExternalHub);
MessageBox(NULL,"EXT handle fail ","TEST",MB_OK);
return false;
}
}
USB_NODE_CONNECTION_ATTRIBUTES *PortConnection =
(USB_NODE_CONNECTION_ATTRIBUTES *) malloc(sizeof(USB_NODE_CONNECTION_ATTRIBUTES));
PortConnection ->ConnectionIndex = Port;
ioctlSuccess = DeviceIoControl(ExternalHub,
IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES,
PortConnection,
sizeof(USB_NODE_CONNECTION_ATTRIBUTES),
PortConnection,
sizeof(USB_NODE_CONNECTION_ATTRIBUTES),
&kBytes,
NULL);
if(!ioctlSuccess)
{
MessageBox(NULL,"DEVICE CONNECTION FAIL ","TEST",MB_OK);
return false;
}
if(PortConnection->ConnectionStatus !=DeviceConnected)
{
printf("The Connection Status Returns: %d",PortConnection->ConnectionStatus);
printf("\n");
return false;
}
Enumerating USB on Windows 7 will fail if UAC is enabled and application doesn't have enough privilege. Windows Embedded 7 may fail also on similar task.
There is also a possibility to enumerate through registry.
You can not enumerate anything possibly. Normally the usb device is either a bus device or a child of a bus device. Sense the bus device is not removable, it is automatically enumerated by acpi.sys the root device during boot, or if a bus device for some other device attached to the root node, then that device has to undergo some event that means it detects the device and then enumerates it, plug and play will automatically look for it's device type's driver and if installed will load it. If the usb say has 4 actual usb connectors, that are controlled from a central device, there could be a usb driver/mini driver pair. In that case the miniport driver is a child of the usb driver and is enumerated by it and attached to it. The miniport's job is to know the actual hardware, and irp's and all other io will come from it's parent. If there are several physical connections there may be additional child drivers. They all operate the hardware and there is a hot plug. When the firmware detects the installation of a usb device it communicates this to the miniport driver and on down the stack to the bus and ultimately it is processed by plug and play. Plug and play will then have the miniport driver enumerate it's device, but it needs to get a hardware id. Then it can find it's driver and load that, then the device is installed and ready for operation.
With out knowing the device stack it is not clear what device it is referring to. Keep in mind the driver stack may not reflect the actual hardware topology. There are also things called logical devices which do not represent any piece of hardware. Any of these would have to be taken into account and you need to know which device corresponds to the end of the node.
Also one little detail. I'm not as familiar with user mode api's and drivers as I am kernel, but it seems wsprintf second argument controls format of the output buffer from the input. It should be %[]%[] were [] is a symbol that represents the format. It would format the first character according to the first symbol then the second character with teh second symbol. Seems you are doing something different.
A final note, it appears the use of wsprintf() is now deprecated instead for other api's.