I have a Windows program coded in C++. To get the drive's serial number of the computer's drive, I run "wmic path win32_physicalmedia get SerialNumber" in the program with _popen().
However, the computers that run the program may have many drives, and USB drives also appear in the list.
How can I do to know which of the drives has the program I'm running? Thanks!
Assuming you still want to do it with WMI: first of all you need some code to read WMI properties in C++. No need to repeat here, you can find it in Getting CPU ID code from C# to be in C++.
When you have that code you can stat to work with disks. First of all you need to remember how Windows organize disks:
Each physical disk (Win32_DiskDrive) is made by partitions (Win32_DiskPartition).
Each partition (Win32_DiskPartition) is a logical disk (Win32_LogicalDisk).
Mapping between each other is done with Win32_DiskDriveToDiskPartition and Win32_LogicalDiskToPartition.
You already know where you're running then you can do this mapping:
Fetch from Win32_LogicalDisk the one where DeviceID property matches drive you're running on:
DeviceID=C:
Query Win32_LogicalDiskToPartition and pick Antecedent for which Dependent has ID you previously found:
\\REPETTI\root\cimv2:Win32_DiskPartition.DeviceID="Disk #1, Partition #1" \\REPETTI\root\cimv2:Win32_LogicalDisk.DeviceID="C:"
Now you should query partitions in Win32_DiskPartition to find the one where DeviceID is Disk #1, Partition #1 however also Win32_DiskDriveToDiskPartition uses DeviceID for this mapping then you can directly query Win32_DiskDriveToDiskPartition to match given ID:
\\REPETTI\root\cimv2:Win32_DiskDrive.DeviceID="\\.\PHYSICALDRIVE1" \\REPETTI\root\cimv2:Win32_DiskPartition.DeviceID="Disk #1, Partition #1"
Now you just need to query Win32_DiskDrive searching for device ID \\.\PHYSICALDRIVE1:
WDC WDxxx ATA Device \\.\PHYSICALDRIVE1 WDC WDxxx ATA Device
And you can get its serial number (in this case same property is available both in Win32_PhysicalMedia and Win32_DiskDrive otherwise you should search by its Caption).
Without WMI
If you have to do it without WMI then it's little bit more tricky.
First of all you need to figure out which physical drive contains your logical drive_ you may follow How to list physical disks?.
When you have physical drive name easiest way is CreateFile() to open drive and get information with DeviceIoControl() sending S.M.A.R.T. commands. Don't think it's always so easy: with many drives it'll fail and you need administrative rights. Unfortunately there isn't a single perfect solution then you need to try different approaches. AFAIK best and most exhaustive code to handle this is written by Lynn McGuire for its DiskId32 utility.
Related
I am developing a tool that displays a status about various hardware components on a system we use at work. Currently, we have 16 touch screen monitors (all by 3M) plugged in to a Windows 10 box. I need to verify that any given monitor has an associated touch screen recognized by windows. This is to assess the system for any hardware malfunctions i.e. bad cable, bad USB port, bad Monitor, etc. We see this more than we would like to admit, usually where a monitor's display will be working fine but the USB controller on either end drops out and needs to be reset by unplugging/plugging back in
Unfortunately my code posting will be limited due to work constraints.
I can enumerate all of the monitors plugged in to the system via winapi's EnumDisplayDevices and EnumerateDisplayMonitors. I am able to build a list of all the HID touch screen devices using HIDApi.
From here I have no direction on where to go to link these two things together, if it is even possible. My first thought was the HID device information should have some sort of identifier shared by the results of calling the EnumDisplayDevices and EnumerateDisplayMonitors, but I have not found this to be the case. Another possibility would be to compare the coordinates/size of a monitor to a region that one of the touch controllers is responsible for. Again, not sure if that is possible.
In short, is there a way to associate a Touch device with it's corresponding monitor via c++?
I think you were just lucky that this driver suffix matched your monitor configuration. In my Windows 10 multi-monitor setup I get wrong displays when I look them up with this number in the driver entry as you described.
A reliable way for associating a HID device with a display seems to be:
Call GetRawInputDeviceList() to obtain the HID devices
Call GetRawInputDeviceInfo() with RIDI_DEVICEINFO to determine Usage and UsagePage
Call GetRawInputDeviceInfo() with RIDI_DEVICENAME to get a device string in the form \\\\?\\HID#VID_0EEF&PID_7200&Col01#6&152cc7f9&1&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
Query the registry for the mapping table at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wisp\Pen\Digimon and look up the display device name. In my case the HID names are all prefixed with 20- there but the remaining part seems to match the name queried by GetRawInputDeviceInfo() exactly. As a fallback method in case there is no match, I also parse the middle part as Clay Brooks described in his answer.
Call EnumDisplayDevices() with a null pointer for lpDevice and 0 for dwFlags in a loop until the function returns zero.
Within each loop iteration, call EnumDisplayDevices() again with the current device as lpDevice and EDD_GET_DEVICE_INTERFACE_NAME for dwFlags and observe that it returns a DeviceID in the form \\\\?\\DISPLAY#ELO2243#5&607b301&0&UID24833#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
Loop until a HID <-> display match is found and take the DeviceName returned by the "outer" EnumDisplayDevices() call which should be something like \\.\DISPLAY3
After the suggestions in the comments and looking deeper into the registry, I've found a way to link Touch controllers to a monitor.
Using HIDApi, you can poll the system and find a list of all the Touch Controllers you need to monitor. I filtered by the VID of the monitors we are using. A sample return value for the path looks something like this:
"\\?\hid#vid_0596&pid_0520&col02#8&33d9e616&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}"
The bold part can be used to link to the entries in HKLM/Software/Microsoft/Wisp/Pen/Digimon. An example entry is this:
"\\?\HID#VID_0596&PID_0520&Col03#8&33d9e616&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}" "\\?\DISPLAY#MSY1C2B#7&1083071f&0&UID524#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"
The first bold matches the data found through HIDApi and the second set of bolding, the monitor name and a UID, is listed in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY. Under here you can use the combination of monitor name and UID to find the Driver entry. Below is a sample driver entry:
{4d36e96e-e325-11ce-bfc1-08002be10318}\0010
The last bold number can then be used to match up with a DeviceID returned from EnumDisplayDevices(). Below is a sample DeviceID:
"MONITOR\MSY1C2B\{4d36e96e-e325-11ce-bfc1-08002be10318}\0010".
Then you can use this bolded section to match up to names of monitors returned from EnumDisplayMonitors().
I have an application, that needs to talk to a piece of custom hardware. I know roughly the format that the driver will register a symbolic name, however based on some physical switches on the card, the card will have a somewhat dynamic name. My question is is there way to find the registered symbolic name, or find the driver and create the symbolic name.
My application use the symbolic name for operations like CreateFile(), WriteFile(), etc.
Update
The driver is PNP, so it really only makes the one subkey under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\V70QT\, and I will have potentially more than 1 card. I thought for a second there, that I could use this registry key
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\V70QT\Enum]
"Count"=dword:00000001
"NextInstance"=dword:00000001
"0"="PCI\\VEN_10B5&DEV_2021&SUBSYS_202110B5&REV_03\\4&33c89357&0&08F0"
Because the symbolic key name gets built in a format similar to V70QTX_Y, where X is the card ID (switches on hardware), and Y is the channel (irrelevant here). I thought I could build the name up using the "NextInstance" value however that will not work, as the card could have a switch ID of like 4, and be the first instance.
If your driver shows up under [HKLM\System\CurrentControlSet\Services], it would simply be a matter of enumerating the subkeys there.
I'm developing in windows with C/C++ and I want to know is it possible to get an apropriate \\.\SCSI device name by \\.\PhysicalDrive ?..
For example, it's wonderful to know how to get that \\.\PhysicalDrive0 is the same that \\.\SCSI0.
Look at the code which I posted in my answer to the question. The author of the question had changed the text of the question so many time and the last version of text clear nor really what the original problem was.
In the example, which C source code you can download here, I show how to get many kind of information about the local drive using different Windows API. The important thing which you need is that some name conversion like DeviceType and DeviceNumber (received by IOCTL_STORAGE_GET_DEVICE_NUMBER) like the following
DeviceType: 7, DeviceNumber: 5, PartitionNumber: 1
are unique in the operation system and can be used to identify the same devices. The reference to the statement you can find in the documentation of IOCTL_STORAGE_GET_DEVICE_NUMBER control code:
The values in the
STORAGE_DEVICE_NUMBER structure are
guaranteed to remain unchanged until
the device is removed or the system is
restarted. It is not guaranteed to be
persistent across device restarts or
system restarts.
In the way you can compare \\.\SCSI0 devices and \\.\PhysicalDrive0 and find out the correspondence.
I googled a lot and I couldn't find any answer to this problem...
I have a C++ console application that reads a 1GB SD card that fixes improperly closed files and writes the FAT table accordingly. The SD card is written at the beginning by a firmware in a custom made device.
It worked OK up to Xp and stopped working in Win Vista/seven.
I tried elevating privileges: within an administrator account type, I launched a cmd window using the "run as administrator" method but no luck.
I also tried with a manifest asking for highestAvailable privileges but no luck.
I read in some post that “Windows Vista doesn't allow you to access the disks from user-mode processes at all. Does anybody know about any way of bypassing this behavior?
I’m working in a workaround however I would like to know if this is impossible or not
Edit:
This is my first post here so I don't quite understand about the linking issue... But I'm not reated to any spam at all... just asking in a comunity driven site :)
The code looks like
hDevice = CreateFile(buffer,GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,NULL, OPEN_EXISTING,0,NULL);
I then read the BTB information from the SD and look for and improperly closed file.
Finally when trying to write to the SD
WriteFile(hDevice,buffer,SD_SECTOR_SIZE, &temp, 0)
I get an Access denied (error #5)
The string on CreateFile() is \.\g: as the g letter correspond to the SD card on my machine. All that works ok and as I said before it woks on XP. I also tried using: DeviceIoControl with FSCTL_LOCK_VOLUME but that gives a mem fault error.
Hope this helps to understand and thanks for any help
I think this is due to the path string "buffer"; I ran into the same issue.
The path you are using to get device access needs to look lik this "\\.\PhysicalDrive%d"
%d is the decimal number of the drive.
From Vista on this string is CASE SENSITIVE.
Check the spelling. You also need admin rights, just as before in XP.
For Volumes,. the letter needs to CAPITALIZED
e.g. "\\.\G:"
Also note that it is much better to access the SD card as a device rathern than the volume, since if Windows mounts it, there might be a file system mounted with a write cache.
Furthermore: I forgot to mention that the buffer your read/write the data to/from should be page aligned and the read a multiple of the sector size.
VirtualAlloc() does this
You must dismount volume before writing raw data.
From MSDN:
A write on a volume handle will succeed if the volume does not have a mounted file system, or if one of the following conditions is true:
The sectors to be written to are boot sectors.
The sectors to be written to reside outside of file system space.
You have explicitly locked or dismounted the volume by using FSCTL_LOCK_VOLUME or FSCTL_DISMOUNT_VOLUME.
The volume has no actual file system. (In other words, it has a RAW file system mounted.)
A write on a disk handle will succeed if one of the following conditions is true:
The sectors to be written to do not fall within a volume's extents.
The sectors to be written to fall within a mounted volume, but you have explicitly locked or dismounted the volume by using FSCTL_LOCK_VOLUME or FSCTL_DISMOUNT_VOLUME.
The sectors to be written to fall within a volume that has no mounted file system other than RAW.
Sample code:
BOOL bResult = DeviceIoControl(hDevice, // device to be queried
FSCTL_DISMOUNT_VOLUME, // operation to perform
NULL, 0, // no input buffer
pdg, sizeof(*pdg), // output buffer
&junk, // # of bytes returned
(LPOVERLAPPED)NULL); // synchronous I/O
Sometimes a network drive that is already mapped to a drive letter because "disconnected". Using the normal Windows functions to access files / folders on that drive fail. As soon as the user manually clicks on that drive it the Windows Explorer dialog, it's magically repaired.
Since my program is a batch program I'd like to start this "magic" from my program (C++) but I haven't found a Windows function for that. There's nothing in the usual WNet... functions...
NET USE V: /DELETE
NET USE V: "\\server1\videos"
NET USE L: /DELETE
NET USE L: "\\server2\archive"
When the path is inserted, you could check to see if it is a network resource and before opening files, use WNetGetConnection() to get the network resource.
You could also try to use WNetRestoreConnectionW(), which seems to have more spurious support, depending on the environment.
Try re-connecting to the share via net use:
net use \\server\folder [/user:[domain\]username] [password]
If that doesn't work, you can net use /delete it first, then re-connect.
Isn't this what WNetAddConnection and WNetAddConnection2 are for?
I suspect that is really the same thing, though. Explorer probably caches the connection info somewhere in the registry. When the user tries to go to that drive Explorer sees that the mapping is disconnected, reads the connection info from the registry, and re-creates the connection. Maybe you could try running regmon while you create a drive mapping and see if you can figure out where and how the connection information is cached.
I had trouble with this at a client of mine not long ago. I don't know if it's possible in your situation, but our fix was to tweak the Server's network settings to stop the timeouts and disconnects. See MSKB 297684 for details.
I agree with the comment from CMB, above. I've been down this path (excuse the pun) in the past and it caused me no end of trouble.
If the path is user configurable, they could use m:\pathonserver or they could use \server\c\pathonserver.
It shouldn't make any difference to your code, opening a file as m:\blahdeblah.dat or \server\c\blahdeblah.dat will be identical.
Using the UNC path is far more reliable, Windows will reconnect to that path automatically whether or not the mapped letter is there.
If you map a drive to a network
share, the mapped drive may be disconnected after a regular interval
of inactivity, and Windows Explorer may display a red "X" on the icon
of the mapped drive. However, if you try to access or browse the
mapped drive, it reconnects quickly.
To avoid this behavior use the following command:
net config server /autodisconnect:-1
Explanation of Microsoft on this topic:
https://support.microsoft.com/da-dk/help/297684/mapped-drive-connection-to-network-share-may-be-lost