DeviceIoControl giving ERROR_BAD_LENGTH error when called in DLL - c++

I am want to find the type of drive for that i used DeviceIoControl function which is working. However when I use the same function in DLL it returns with ERROR_BAD_LENGTH error. Following is my code.
BOOL Globals::IsUsbDevice ( wchar_t letter)
{
wchar_t volumeAccessPath[] = L"\\\\.\\X:";
volumeAccessPath [4] = letter;
HANDLE deviceHandle= CreateFileW(
volumeAccessPath,
0, // no access to the Drive
FILE_SHARE_READ | // Share mode
FILE_SHARE_WRITE,
NULL, // Default Security attributes
OPEN_EXISTING, // Disposition
0, // file attributes
NULL); // do not Copy file attributes
if (deviceHandle == INVALID_HANDLE_VALUE) // cannot open the drive
{
CloseHandle (deviceHandle);
return (FALSE);
}
// Setup query
STORAGE_PROPERTY_QUERY Query;
memset (&Query, 0, sizeof (Query));
Query.PropertyId = StorageDeviceProperty;
Query.QueryType = PropertyStandardQuery;
// Issue query
DWORD bytes;
//STORAGE_DEVICE_DESCRIPTOR Devd;
STORAGE_BUS_TYPE busType = BusTypeUnknown;
char OutBuf[1024] = {0}; // good enough, usually about 100 bytes
PSTORAGE_DEVICE_DESCRIPTOR pDevDesc = (PSTORAGE_DEVICE_DESCRIPTOR)OutBuf;
pDevDesc->Size = sizeof(OutBuf);
if (DeviceIoControl (deviceHandle,
IOCTL_STORAGE_QUERY_PROPERTY,
&Query, sizeof(STORAGE_PROPERTY_QUERY),
pDevDesc, pDevDesc->Size,
&bytes,NULL))
{
busType = pDevDesc->BusType;
}
else
{
// Retrieve the system error message for the last-error code
..........
}
CloseHandle (deviceHandle);
return BusTypeUsb == busType;
}
I am executing my program as Administrator.
Any help would be greatly appreciated.

Related

ReadDirectoryChangesW rejecting HANDLE accepted by CreateIoCompletionPort

I'm adding functionality to my (Qt-based) application to monitor an arbitrary folder on my Windows system for any activity recursively (something the Qt variant QFileSystemWatcher lacks). After opening the folder with CreatFileW(), I create a completion port to receive the overlapped I/O, and then I queue a read using ReadDirectoryChangesW().
I have placed all of this in the following "simple" Win32 console application to demonstrate (note that the "stdafx.h" header has been modified to include "windows.h", but is otherwise as the Visual Studio 2013 IDE generated it):
#include "stdafx.h"
#define MAX_BUFFER 4096
struct ThreadData
{;
DWORD winerr;
HANDLE handle;
unsigned int flags;
int recursive;
HANDLE completion_port;
CHAR buffer[MAX_BUFFER];
DWORD buffer_len;
OVERLAPPED overlapped;
};
int _tmain(int argc, _TCHAR* argv[])
{
DWORD winerr;
ThreadData td;
td.flags = FILE_NOTIFY_CHANGE_FILE_NAME|
FILE_NOTIFY_CHANGE_DIR_NAME|
FILE_NOTIFY_CHANGE_ATTRIBUTES|
FILE_NOTIFY_CHANGE_SIZE|
FILE_NOTIFY_CHANGE_LAST_WRITE|
FILE_NOTIFY_CHANGE_LAST_ACCESS|
FILE_NOTIFY_CHANGE_CREATION|
FILE_NOTIFY_CHANGE_SECURITY;
td.recursive = 1;
td.completion_port = INVALID_HANDLE_VALUE;
td.handle = INVALID_HANDLE_VALUE;
td.handle = CreateFileW(L"J:\\Font", // arbitrary folder
FILE_LIST_DIRECTORY, // required
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
// Use FILE_FLAG_OVERLAPPED for asynchronous operation with ReadDirectoryChangesW.
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
if(td.handle == INVALID_HANDLE_VALUE)
{
winerr = GetLastError();
CloseHandle(td->handle);
return 0;
}
td.completion_port = CreateIoCompletionPort(td.handle,
td.completion_port,
(ULONG_PTR)td,
0); // max num processors
if(td.completion_port == INVALID_HANDLE_VALUE)
{
winerr = GetLastError();
CloseHandle(td.completion_port);
CloseHandle(td.handle);
return 0;
}
BOOL rdc = ReadDirectoryChangesW(td.handle,
td.buffer, // read results
MAX_BUFFER,
td.recursive, // watch subdirectories
// NOTE: At least one flag is required!
td.flags, // see Notify Filters below
&td.buffer_len,
&td.overlapped,
NULL); // completion routine
if(rdc == 0)
{
winerr = GetLastError(); // "The handle is invalid. (0x6)"
CloseHandle(td.completion_port);
CloseHandle(td.handle);
return 0;
}
// Launch thread here to handle completions and trigger new ones
...
// Clean up when the thread is done
CloseHandle(td.completion_port);
CloseHandle(td.handle);
return 0;
}
The thing to note about this code is that it is modeled after a Python module ("watcher"), written in C, that provides similar functionality to a Python environment. I've used it in Python, and it works as expected with all of the same settings in this C++ fragment.
In the above code, CreateIoCompletionPort() accepts the HANDLE generated by CreateFileW(), but ReadDirectoryChangesW() does not. It returns 0, and GetLastError() is returning "The handle is invalid. (0x6)". I've tried this under both 32- and 64-bit compiles, just in case that made any difference (I was using the 64-bit version of Python). Also, the directory specified doesn't appear to matter: All directories I specify produce the same result, which suggests it's a problem with the settings somewhere.
Is there something in the CreateFileW() call that might cause the HANDLE to be valid for generating a completion port, but would give the ReadDirectoryChangesW() function heartburn?
You are not initializing the I/O Completion Port correctly, and you are not initializing the OVERLAPPED structure at all. ReadDirectoryChangesW() is failing because the OVERLAPPED::hEvent field contains an invalid event object handle. That is the invalid handle that the error code is referring to, not the directory handle.
Try this instead:
#include "stdafx.h"
#define MAX_BUFFER 4096
struct ThreadData
{
DWORD winerr;
HANDLE handle;
DWORD flags;
BOOL recursive;
HANDLE completion_port;
CHAR buffer[MAX_BUFFER];
DWORD buffer_len;
OVERLAPPED overlapped;
};
int _tmain(int argc, _TCHAR* argv[])
{
DWORD winerr;
ThreadData td;
td.flags = FILE_NOTIFY_CHANGE_FILE_NAME|
FILE_NOTIFY_CHANGE_DIR_NAME|
FILE_NOTIFY_CHANGE_ATTRIBUTES|
FILE_NOTIFY_CHANGE_SIZE|
FILE_NOTIFY_CHANGE_LAST_WRITE|
FILE_NOTIFY_CHANGE_LAST_ACCESS|
FILE_NOTIFY_CHANGE_CREATION|
FILE_NOTIFY_CHANGE_SECURITY;
td.recursive = TRUE;
td.completion_port = NULL;
td.handle = CreateFileW(L"J:\\Font", // arbitrary folder
FILE_LIST_DIRECTORY, // required
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
// Use FILE_FLAG_OVERLAPPED for asynchronous operation with ReadDirectoryChangesW.
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
if(td.handle == INVALID_HANDLE_VALUE)
{
winerr = GetLastError();
return 0;
}
td.completion_port = CreateIoCompletionPort(td.handle,
NULL,
(ULONG_PTR)&td,
0); // max num processors
if(td.completion_port == NULL)
{
winerr = GetLastError();
CloseHandle(td.handle);
return 0;
}
ZeroMemory(&td.overlapped, sizeof(td.overlapped)); // <-- add this!
// required if the thread uses GetOverlappedResult()...
// optional if the thread uses GetQueuedCompletionStatus()...
/*
td.overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(td.overlapped.hEvent == NULL)
{
winerr = GetLastError();
CloseHandle(td.completion_port);
CloseHandle(td.handle);
return 0;
}
*/
BOOL rdc = ReadDirectoryChangesW(td.handle,
td.buffer, // read results
MAX_BUFFER,
td.recursive, // watch subdirectories
// NOTE: At least one flag is required!
td.flags, // see Notify Filters below
&td.buffer_len,
&td.overlapped,
NULL); // completion routine
if(rdc == FALSE)
{
winerr = GetLastError();
//CloseHandle(td.overlapped.hEvent);
CloseHandle(td.completion_port);
CloseHandle(td.handle);
return 0;
}
// Launch thread here to handle completions and trigger new ones
...
// Clean up when the thread is done
//CloseHandle(td.overlapped.hEvent);
CloseHandle(td.completion_port);
CloseHandle(td.handle);
return 0;
}
CreateIoCompletionPort returns NULL on error, not INVALID_HANDLE_VALUE. So your first error is on this line:
td.completion_port = INVALID_HANDLE_VALUE;
It must be this instead:
td.completion_port = NULL;
And this incorrect check:
if(td.completion_port == INVALID_HANDLE_VALUE)
Must be this instead:
if(td.completion_port == NULL)
You get NULL in td.completion_port after CreateIoCompletionPort because the initial value of td.completion_port is invalid. Also, you are incorrectly handling the error case (say try close invalid handles).

DeviceIoControl() with IOCTL_DISK_GET_DRIVE_GEOMETRY is failing and returning error code 87. Why?

Relevant code is as follows:
std::wstring path = ApplicationData::Current->LocalFolder->Path->Data();
std::wstring testFileName = path + std::wstring(L"\\TestVariablySized");
this->hMappedFile = CreateFile2(
testFileName.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
OPEN_ALWAYS,
NULL);
uint32_t checkF = GetLastError();
DISK_GEOMETRY geo = { 0 };
DWORD bReturned = 0;
bool controlCheck = DeviceIoControl(
(HANDLE)hMappedFile, // handle to device
IOCTL_DISK_GET_DRIVE_GEOMETRY, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
(LPVOID)&geo, // output buffer
(DWORD)sizeof(geo), // size of output buffer
(LPDWORD)&bReturned, // number of bytes returned
NULL);
uint32_t check = GetLastError();
After this, controlCheck is false and check is ERROR_INVALID_PARAMETER. checkF is ERROR_ALREADY_EXISTS, which shouldn't be a problem here.
As far as I can tell, I've called DeviceIoControl() in a way consistent with the IOCTL_DISK_GET_DRIVE_GEOMETRY documentation.
, but clearly I'm missing something. Your help is most appreciated.
Edit:
Per responses received, I altered things to be as follows:
HANDLE hDevice = CreateFile2(
L"\\.\PhysicalDrive0",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
OPEN_EXISTING,
NULL);
uint32_t checkF = GetLastError();
DISK_GEOMETRY geo = { 0 };
DWORD bReturned = 0;
bool controlCheck = DeviceIoControl(
hDevice, // handle to device
IOCTL_DISK_GET_DRIVE_GEOMETRY, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
(LPVOID)&geo, // output buffer
(DWORD)sizeof(geo), // size of output buffer
(LPDWORD)&bReturned, // number of bytes returned
NULL);
uint32_t check = GetLastError();
CloseHandle(hDevice);
Which should be closer to being correct, even if it's not quite correct yet. checkF is ERROR_FILE_NOT_FOUND, which I found strange. I tried "\\.\PhysicalDrive1" and "\\.\PhysicalDrive2" as well, but receive the same result. controlCheck is still false, but check is now ERROR_INVALID_HANDLE.
As far as I can tell, I've called DeviceIoControl() in a way consistent with the IOCTL_DISK_GET_DRIVE_GEOMETRY documentation
Actually, you are not, because you did not pay attention to this tidbit of the documentation:
hDevice
A handle to the disk device from which the geometry is to be retrieved. To retrieve a device handle, call the CreateFile function.
You are not passing a handle to a disk device, you are passing a handle to a filesystem path instead.
When calling CreateFile2() to get a handle to a disk device, you need to specify a physical device in \\.\PhysicalDriveX format instead, not a filesystem path.
Also, as the CreateFile2() documentation says:
The following requirements must be met for such a call to succeed:
The caller must have administrative privileges. For more information, see Running with Special Privileges.
The dwCreationDisposition parameter must have the OPEN_EXISTING flag.
When opening a volume or floppy disk, the dwShareMode parameter must have the FILE_SHARE_WRITE flag.
You are using OPEN_ALWAYS instead of OPEN_EXISTING.
Please read the "Physical Disks and Volumes" section of the CreateFile2() documentation more carefully.
Try something more like this instead:
std::wstring path = L"\\\\.\\PhysicalDrive0";
DWORD errCode;
hMappedFile = CreateFile2(
path.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
OPEN_EXISTING,
NULL);
if (this->hMappedFile == INVALID_HANDLE_VALUE)
{
errCode = GetLastError();
// handle error as needed...
}
else
{
DISK_GEOMETRY geo = { 0 };
DWORD dwReturned = 0;
bool controlCheck = DeviceIoControl(
hMappedFile, // handle to device
IOCTL_DISK_GET_DRIVE_GEOMETRY, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
&geo, // output buffer
sizeof(geo), // size of output buffer
&dwReturned, // number of bytes returned
NULL);
if (!controlCheck)
{
errCode = GetLastError();
// handle error as needed...
}
else
{
// use drive as needed...
}
CloseHandle(hMappedFile);
}

What's wrong with this pipeline communication code?

I'm trying to implement in my code with pipeline communication.
Build success but my code doesn't work.
My Pipeline communication code is :
int CTssPipeClient::Start(VOID)
{
m_uThreadId = 0;
m_hThread = (HANDLE)_beginthreadex(NULL, 0, ProcessPipe, LPVOID(this), 0, &m_uThreadId);
return 1;
}
VOID CTssPipeClient::Stop(VOID)
{
m_bRunning = FALSE;
if(m_hThread)
{
WaitForSingleObject(m_hThread, INFINITE);
CloseHandle(m_hThread);
}
if(m_hPipe)
{
CloseHandle(m_hPipe);
}
}
UINT CTssPipeClient::Run()
{
BOOL fSuccess;
DWORD dwMode;
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\tssnamedpipe");
m_vMsgList.clear();
m_bRunning = TRUE;
// Try to open a named pipe; wait for it, if necessary.
while (m_bRunning)
{
m_hPipe = CreateFile(
lpszPipename, // pipe name
GENERIC_READ // read and write access
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
// Break if the pipe handle is valid.
if (m_hPipe == INVALID_HANDLE_VALUE)
{
Sleep(1000);
continue;
}
dwMode = PIPE_READMODE_MESSAGE;
fSuccess = SetNamedPipeHandleState(
m_hPipe, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
if (!fSuccess)
{
continue;
}
while(fSuccess)
{
if(m_vMsgList.size() > 0)
{
DWORD cbWritten;
// Send a message to the pipe server.
fSuccess = WriteFile(
m_hPipe, // pipe handle
m_vMsgList[0].c_str(), // message
(m_vMsgList[0].length() + 1)*sizeof(TCHAR), // message length
&cbWritten, // bytes written
NULL); // not overlapped
m_vMsgList.erase(m_vMsgList.begin());
if (!fSuccess)
{
break;
}
}
Sleep(200);
}
CloseHandle(m_hPipe);
}
_endthreadex(0);
return 0;
}
DWORD CTssPipeClient::WriteMsg(LPCTSTR szMsg)
{
if(!m_bRunning)
{
Start();
}
wstring wstr(szMsg);
m_vMsgList.push_back(wstr);
return 0;
}
I was tried fix this problem. But I didn't found What's wrong?
Please help me. I'm grateful for your help.
Thank you.
The reason is simple. Because you open a file with only read mode.
Please modify like this:
m_hPipe = CreateFile(
lpszPipename, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
I hope that helps.

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.

WINAPI C++ Get current physical drive number

I have a function
DWORD GetPhysicalDriveSerialNumber(UINT nDriveNumber, CString& strSerialNumber)
{
DWORD dwResult = NO_ERROR;
strSerialNumber.Empty();
// Format physical drive path (may be '\\.\PhysicalDrive0', '\\.\PhysicalDrive1' and so on).
CString strDrivePath;
strDrivePath.Format(_T("\\\\.\\PhysicalDrive%u"), nDriveNumber);
// call CreateFile to get a handle to physical drive
HANDLE hDevice = ::CreateFile(strDrivePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hDevice)
return ::GetLastError();
// set the input STORAGE_PROPERTY_QUERY data structure
STORAGE_PROPERTY_QUERY storagePropertyQuery;
ZeroMemory(&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY));
storagePropertyQuery.PropertyId = StorageDeviceProperty;
storagePropertyQuery.QueryType = PropertyStandardQuery;
// get the necessary output buffer size
STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader = { 0 };
DWORD dwBytesReturned = 0;
if (!::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
&storageDescriptorHeader, sizeof(STORAGE_DESCRIPTOR_HEADER),
&dwBytesReturned, NULL))
{
dwResult = ::GetLastError();
::CloseHandle(hDevice);
return dwResult;
}
// allocate the necessary memory for the output buffer
const DWORD dwOutBufferSize = storageDescriptorHeader.Size;
BYTE* pOutBuffer = new BYTE[dwOutBufferSize];
ZeroMemory(pOutBuffer, dwOutBufferSize);
// get the storage device descriptor
if (!::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
pOutBuffer, dwOutBufferSize,
&dwBytesReturned, NULL))
{
dwResult = ::GetLastError();
delete[]pOutBuffer;
::CloseHandle(hDevice);
return dwResult;
}
// Now, the output buffer points to a STORAGE_DEVICE_DESCRIPTOR structure
// followed by additional info like vendor ID, product ID, serial number, and so on.
STORAGE_DEVICE_DESCRIPTOR* pDeviceDescriptor = (STORAGE_DEVICE_DESCRIPTOR*)pOutBuffer;
const DWORD dwSerialNumberOffset = pDeviceDescriptor->SerialNumberOffset;
if (dwSerialNumberOffset != 0)
{
// finally, get the serial number
strSerialNumber = CString(pOutBuffer + dwSerialNumberOffset);
}
// perform cleanup and return
delete[]pOutBuffer;
::CloseHandle(hDevice);
return dwResult;
}
I want to get current drive number(drive number of program located in)
Example(for my system):
If i will run porgram on disk c it must return 0(hdd 0)
If i will run progrman on disk d or e it must return 1(hdd 1)
Flash drive 2 etc.
How can I do this?