How to check if a file is being used by another application? - c

I am using the following code to check if a file is being used by another application:
HANDLE fh = CreateFile("D:\\1.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (fh == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "The file is in use", "Error", 0);
}
If the file is being used by another application, the message box is displayed. However, the message box is also displayed if the file does not exists!
So what should I do to solve this problem, should I also check if the file exists (using another function), or can the parameters of CreateFile() be changed to only return INVALID_HANDLE_VALUE if the file is in use and does exists?

If you wish to find out, which process has a file open, use the Restart Manager. The procedure consists of the following steps (as outlined in Raymond Chen's blog entry How do I find out which process has a file open?):
Create a Restart Manager session (RmStartSession).
Add a file resource to the session (RmRegisterResource).
Ask for a list of all processes affected by that resource (RmGetList).
Close the session (RmEndSession).
Sample code:
#include <Windows.h>
#include <RestartManager.h>
#pragma comment(lib, "Rstrtmgr.lib")
bool IsFileLocked( const wchar_t* PathName ) {
bool isFileLocked = false;
DWORD dwSession = 0x0;
wchar_t szSessionKey[CCH_RM_SESSION_KEY + 1] = { 0 };
if ( RmStartSession( &dwSession, 0x0, szSessionKey ) == ERROR_SUCCESS ) {
if ( RmRegisterResources( dwSession, 1, &PathName,
0, NULL, 0, NULL ) == ERROR_SUCCESS ) {
DWORD dwReason = 0x0;
UINT nProcInfoNeeded = 0;
UINT nProcInfo = 0;
if ( RmGetList( dwSession, &nProcInfoNeeded,
&nProcInfo, NULL, &dwReason ) == ERROR_MORE_DATA ) {
isFileLocked = ( nProcInfoNeeded != 0 );
}
}
RmEndSession( dwSession );
}
return isFileLocked;
}

You need to use GetLastError() to know why CreateFile() failed, eg:
// this is requesting exclusive access to the file, so it will
// fail if the file is already open for any reason. That condition
// is detected by a sharing violation error due to conflicting
// sharing rights...
HANDLE fh = CreateFile("D:\\1.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (fh == INVALID_HANDLE_VALUE)
{
switch (GetLastError())
{
case ERROR_PATH_NOT_FOUND:
case ERROR_FILE_NOT_FOUND:
MessageBox(NULL, "The file does not exist", "Error", 0);
break;
case ERROR_SHARING_VIOLATION:
MessageBox(NULL, "The file is in use", "Error", 0);
break;
//...
default:
MessageBox(NULL, "Error opening the file", "Error", 0);
break;
}
}
else
{
// the file exists and was not in use.
// don't forget to close the handle...
CloseHandle(fh);
}

Related

A function works when I use gcc, but when I use Microsoft Visual Studio's compiler it does nothing

When I run this with gcc using code:blocks, it creates the registration.txt on F if it doesn't exist and writes the password and username, but when I use this in my project using Microsoft Visual Studio's compiler it does nothing.
For example if I call this function such as: Write("JohnDoe", "password123"),
in the file registration.txt should appear in a line: JohnDoe, password123.
const char *FILEPATH = "F:\\registration.txt";
int Write(char *username, char *password) {
if (username == NULL || password == NULL) {
return -1;
}
BOOL error = TRUE;
size_t lengthUsername = strlen(username);
size_t lengthPassword = strlen(password);
LPDWORD bytesUsernameWritten = 0;
char comma[2] = ",";
char newLine[3] = "\r\n";
LPDWORD bytesPasswordWritten = 0;
LPDWORD bytesWrittenComma = 0;
//if the file doesn't exist, we create it
HANDLE file = CreateFile((LPCWSTR)FILEPATH, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE) {
if (GetLastError() != ERROR_FILE_EXISTS) {
printf("0x%x", GetLastError());
CloseHandle(file);
return -1;
} //the file exist, we try to create it
file = CreateFile((LPCWSTR)FILEPATH, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE) {
printf("Couldn't open the file. Error : 0x%x", GetLastError());
CloseHandle(file);
return -1;
}
}
//We try to write the username and the password in file, each combination on each line, in this format: username, password
error = WriteFile(file, username, (DWORD)lengthUsername, bytesUsernameWritten, NULL);
if (error == FALSE) {
printf("The username couldn't have been written. Error 0x%x\n", GetLastError());
CloseHandle(file);
return -1;
}
error = WriteFile(file, comma, 1, bytesWrittenComma, NULL);
if (error == FALSE) {
printf("The comma couldn't have been written. Error 0x%x\n", GetLastError());
CloseHandle(file);
return -1;
}
error = WriteFile(file, password, (DWORD)lengthPassword, bytesPasswordWritten, NULL);
if (error == FALSE) {
printf("The password couldn't have been written. Error 0x%x\n", GetLastError());
CloseHandle(file);
return -1;
}
error = WriteFile(file, newLine, 2, bytesPasswordWritten, NULL);
if (error == FALSE) {
printf("The endline couldn't have been written. Error 0x%x\n", GetLastError());
CloseHandle(file);
return -1;
}
CloseHandle(file);
return 0;
}
Your main problem is confusion between using Unicode and ASCII.
All windows API functions that take string parameters have two versions:
One that works with LPCSTR and one that works with LPCWSTR.
You can cast char * to LPCSTR and use the ASCII version CreateFileA, but you can not cast it to LPCWSTR and use the CreateFileW - the Unicode version of CreateFile as it expects strings in UCS-16 encoding where each character takes 2 bytes.
Which version of the function is called depends on a compiler flag. For CodeBlocks on Windows the default is to use ASCII versions, so your function works.
For VS the default is Unicode, so the file path string gets messed up and the file is not created.
Also, you have two other erros:
You are using WriteFile incorrectly.
The 4th parameter is a pointer, where WriteFile stores number of bytes written.
You are passing a NULL pointer, because you set variables such as bytesUsernameWritten to 0. But according to MS documentation, you can only use NULL there if the last parameter, lpOverlapped is not NULL.
What you should do, is declare bytesUsernameWritten to be DWORD and pass its address using & operator.
Otherwise, even if the function creates the file successfully, you will not get the number of bytes that were written.
You are trying to close INVALID_HANDLE_VALUE
This is unnecessary, but fortunately it should not crash you program.
Finally, there is no reason to try to call CreateFile twice.
Just use one call with OPEN_ALWAYS parameter.
This will open an existing file, but if the file does not exist it will create it automatically instead of failing.

CreateFile over USB HID device fails with Access Denied (5) since Windows 10 1809

Since the latest Windows 10 1809 update we can no longer open a USB HID keyboard-like device of ours using CreateFile. We reduced the problem to this minimal example:
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#include <hidsdi.h>
void bad(const char *msg) {
DWORD w = GetLastError();
fprintf(stderr, "bad: %s, GetLastError() == 0x%08x\n", msg, (unsigned)w);
}
int main(void) {
int i;
GUID hidGuid;
HDEVINFO deviceInfoList;
const size_t DEVICE_DETAILS_SIZE = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH;
SP_DEVICE_INTERFACE_DETAIL_DATA *deviceDetails = alloca(DEVICE_DETAILS_SIZE);
deviceDetails->cbSize = sizeof(*deviceDetails);
HidD_GetHidGuid(&hidGuid);
deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
if(deviceInfoList == INVALID_HANDLE_VALUE) {
bad("SetupDiGetClassDevs");
return 1;
}
for (i = 0; ; ++i) {
SP_DEVICE_INTERFACE_DATA deviceInfo;
DWORD size = DEVICE_DETAILS_SIZE;
HIDD_ATTRIBUTES deviceAttributes;
HANDLE hDev = INVALID_HANDLE_VALUE;
fprintf(stderr, "Trying device %d\n", i);
deviceInfo.cbSize = sizeof(deviceInfo);
if (!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i,
&deviceInfo)) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
break;
} else {
bad("SetupDiEnumDeviceInterfaces");
continue;
}
}
if(!SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo,
deviceDetails, size, &size, NULL)) {
bad("SetupDiGetDeviceInterfaceDetail");
continue;
}
fprintf(stderr, "Opening device %s\n", deviceDetails->DevicePath);
hDev = CreateFile(deviceDetails->DevicePath, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if(hDev == INVALID_HANDLE_VALUE) {
bad("CreateFile");
continue;
}
deviceAttributes.Size = sizeof(deviceAttributes);
if(HidD_GetAttributes(hDev, &deviceAttributes)) {
fprintf(stderr, "VID = %04x PID = %04x\n", (unsigned)deviceAttributes.VendorID, (unsigned)deviceAttributes.ProductID);
} else {
bad("HidD_GetAttributes");
}
CloseHandle(hDev);
}
SetupDiDestroyDeviceInfoList(deviceInfoList);
return 0;
}
It enumerates all HID devices, trying to obtain the vendor ID/product ID for each one using CreateFile over the path provided by SetupDiGetDeviceInterfaceDetail and then calling HidD_GetAttributes.
This code runs without problems on previous Windows versions (tested on Windows 7, Windows 10 1709 and 1803, and the original code from which this was extracted works since always from XP onwards), but with the latest update (1809) all keyboard devices (including ours) cannot be opened, as CreateFile fails with access denied (GetLastError() == 5). Running the program as administrator doesn't have any effect.
Comparing the output before and after the update, I noticed that the devices that now cannot be opened gained a trailing \kbd in the device path, i.e. what previously was
\\?\hid#vid_24d6&pid_8000&mi_00#7&294a3305&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
now is
\\?\hid#vid_24d6&pid_8000&mi_00#7&294a3305&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}\kbd
Is it a bug/new security restriction in the latest Windows 10 version? Was this code always wrong and it worked by chance before? Can this be fixed?
Update
As a desperate attempt, we tried to remove the \kbd from the returned string... and CreateFile now works! So, now we have a workaround, but it would be interesting to understand if that's a bug in SetupDiGetDeviceInterfaceDetail, if it's intentional and if this workaround is actually the correct thing to do.
I think this is a new security restriction in the latest Windows 10 version.
I looked for the string KBD (in UTF-16 format) - it exists only in two drivers in version 1809, hidclass.sys and kbdhid.sys, and doesn't exist in version 1709.
In hidclass.sys they changed the HidpRegisterDeviceInterface function. Before this release it called IoRegisterDeviceInterface with GUID_DEVINTERFACE_HID and the ReferenceString pointer set to 0. But in the new version, depending on the result of GetHidClassCollection, it passes KBD as ReferenceString pointer.
Inside kbdhid.sys they changed KbdHid_Create, and here is a check for the KBD string to return errors (access denied or sharing violation).
To understand more exactly why, more research is needed. Some disasm:
For reference, HidpRegisterDeviceInterface from 1709 build
here ReferenceString == 0 always (xor r8d,r8d), and there's no check cmp word [rbp + a],6 on class collection data
However, KbdHid_Create in 1809 contains a bug. The code is:
NTSTATUS KbdHid_Create(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
//...
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (PFILE_OBJECT FileObject = IrpSp->FileObject)
{
PCUNICODE_STRING FileName = &FileObject->FileName;
if (FileName->Length)
{
#if ver == 1809
UNICODE_STRING KBD = RTL_CONSTANT_STRING(L"KBD"); // !! bug !!
NTSTATUS status = RtlEqualUnicodeString(FileName, &KBD, FALSE)
? STATUS_SHARING_VIOLATION : STATUS_ACCESS_DENIED;
#else
NTSTATUS status = STATUS_ACCESS_DENIED;
#endif
// log
Irp->IoStatus.Status = status;
IofCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
}
// ...
}
What it this function trying to do here? It looks for passed PFILE_OBJECT FileObject from Irp current stack location. It no FileObject is provided or it has an empty name, allow open; otherwise, the open fails.
Before 1809 it always failed with error STATUS_ACCESS_DENIED (0xc0000022), but starting from 1809, the name is checked, and if it's equal to KBD (case sensitive) another error - STATUS_SHARING_VIOLATION is returned. However, name always begins with the \ symbol, so it will never match KBD. It can be \KBD, so, to fix this check, the following line needs to be changed to:
UNICODE_STRING KBD = RTL_CONSTANT_STRING(L"\\KBD");
and perform the comparison with this string. So, by design we should have got a STATUS_SHARING_VIOLATION error when trying to open a keyboard device via *\KBD name, but due to an implementation error we actually got STATUS_ACCESS_DENIED here
Another change was in HidpRegisterDeviceInterface - before the call to IoRegisterDeviceInterface on the device it queries the GetHidClassCollection result, and if some WORD (2 byte) field in the structure is equal to 6, adds KBD suffix (ReferenceString). I guess (but I'm not sure) that 6 can be the Usage ID for keyboard, and the rationale for this prefix is to set Exclusive access mode
Actually, we can have a FileName begin without \ if we use relative device open via OBJECT_ATTRIBUTES. So, just for test, we can do this: if the interface name ends with \KBD, first open the file without this suffix (so with empty relative device name), and this open must work ok; then, we can try relative open file with name KBD - we must get STATUS_SHARING_VIOLATION in 1809 and STATUS_ACCESS_DENIED in previous builds (but here we will be have no \KBD suffix):
void TestOpen(PWSTR pszDeviceInterface)
{
HANDLE hFile;
if (PWSTR c = wcsrchr(pszDeviceInterface, '\\'))
{
static const UNICODE_STRING KBD = RTL_CONSTANT_STRING(L"KBD");
if (!wcscmp(c + 1, KBD.Buffer))
{
*c = 0;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, const_cast<PUNICODE_STRING>(&KBD) };
oa.RootDirectory = CreateFileW(pszDeviceInterface, 0,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (oa.RootDirectory != INVALID_HANDLE_VALUE)
{
IO_STATUS_BLOCK iosb;
// will be STATUS_SHARING_VIOLATION (c0000043)
NTSTATUS status = NtOpenFile(&hFile, SYNCHRONIZE, &oa, &iosb,
FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT);
CloseHandle(oa.RootDirectory);
if (0 <= status)
{
PrintAttr(hFile);
CloseHandle(hFile);
}
}
return ;
}
}
hFile = CreateFileW(pszDeviceInterface, 0,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
PrintAttr(hFile);
CloseHandle(hFile);
}
}
void PrintAttr(HANDLE hFile)
{
HIDD_ATTRIBUTES deviceAttributes = { sizeof(deviceAttributes) };
if(HidD_GetAttributes(hFile, &deviceAttributes)) {
printf("VID = %04x PID = %04x\r\n",
(ULONG)deviceAttributes.VendorID, (ULONG)deviceAttributes.ProductID);
} else {
bad(L"HidD_GetAttributes");
}
}
In a test on 1809 I actually got STATUS_SHARING_VIOLATION, that also shows another bug in kbdhid.KbdHid_Create - if we check FileName, we need to check RelatedFileObject - is it 0 or not.
Also, not related to bug, but as suggestion: it is more efficient to use CM_Get_Device_Interface_List instead of the SetupAPI:
volatile UCHAR guz = 0;
CONFIGRET EnumInterfaces(PGUID InterfaceClassGuid)
{
CONFIGRET err;
PVOID stack = alloca(guz);
ULONG BufferLen = 0, NeedLen = 256;
union {
PVOID buf;
PWSTR pszDeviceInterface;
};
for(;;)
{
if (BufferLen < NeedLen)
{
BufferLen = RtlPointerToOffset(buf = alloca((NeedLen - BufferLen) * sizeof(WCHAR)), stack) / sizeof(WCHAR);
}
switch (err = CM_Get_Device_Interface_ListW(InterfaceClassGuid,
0, pszDeviceInterface, BufferLen, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
case CR_BUFFER_SMALL:
if (err = CM_Get_Device_Interface_List_SizeW(&NeedLen, InterfaceClassGuid,
0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
default:
return err;
}
continue;
case CR_SUCCESS:
while (*pszDeviceInterface)
{
TestOpen(pszDeviceInterface);
pszDeviceInterface += 1 + wcslen(pszDeviceInterface);
}
return 0;
}
}
}
EnumInterfaces(const_cast<PGUID>(&GUID_DEVINTERFACE_HID));
The fix is in this windows update released today (March 1, 2019).
https://support.microsoft.com/en-us/help/4482887/windows-10-update-kb4482887
You can find a workaround at Delphi-Praxis in German
For short: Change in the Unit JvHidControllerClass
if not HidD_GetAttributes(HidFileHandle, FAttributes) then
raise EControllerError.CreateRes(#RsEDeviceCannotBeIdentified);
to
HidD_GetAttributes(HidFileHandle, FAttributes);
and recompile the Delhi JCL and JCVL Components by running the JEDI Install EXE.

Use Windows Semaphores to synchronize Windows File Mappings

I want to use Windows Semaphores to add synchronization to a Windows File Mapping. So, one process creates the file mapping and another (perhaps multiple other processes) can come in and access the data that is shared. Can anyone give a suggestion as to how this can be done. I have done the following:
In the process that creates the file mapping, I have used CreateSemaphore and specified a name. In another process that attempts to access the data, I use OpenSemaphore to get a handle to the created sempahore, then I call WaitForSingleObject, I then switch on this value, and if its WAIT_OBJECT0, I perform the work, and finally calling ReleaseSemaphore once the work is done.
I am doing this in C, using a JNI shared library.
The problem is that it simply goes into the default case. Is there anything else that I should do, or am I missing something?
I'm pretty new to how Windows sems work, and I cannot find a concrete example
of how they work between multiple processes (no threads). If anyone can give any suggestions, It would be much appreciated.
Here is some code:
Create the file mapping
// create the semaphore here
semaphore = CreateSemaphore(
NULL,
10,
10,
SEMAPHORE_NAME
);
// some semaphore error checking
if (semaphore == NULL) {
printf("Error occured creating semaphore %d\n", GetLastError());
return -1;
}
//create mapping object
mappedFileHandle = CreateFileMapping (
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
BUFFER_SIZE,
MEMORY_MAPPING_NAME
);
if (mappedFileHandle == NULL) {
printf("Error creating a mapped file: %d", GetLastError());
return -1;
}
// map view of a file into address space of a calling process
buffer = (LPCTSTR) MapViewOfFile (
mappedFileHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
BUFFER_SIZE
);
if (buffer == NULL) {
printf("Could not map view");
CloseHandle(mappedFileHandle);
return -1;
}
CopyMemory(buffer, str, (_tcslen(str) * sizeof(TCHAR))); // problem!!
UnmapViewOfFile(buffer);
CloseHandle(mappedFileHandle);
// CloseHandle(semaphore);
Process code that gets the data
// try open the semahore
semaphore = OpenSemaphore (
SEMAPHORE_ALL_ACCESS,
NULL,
SEMAPHORE_NAME
);
// some error checking
if (semaphore == NULL) {
printf("Could not open semaphore %d\n", GetLastError());
return -1;
}
waitResult = WaitForSingleObject(
semaphore,
-1 // block
);
// try to open the file mapping -- SHOULD BE DONE ATOMICALLY
// ======================================================================
switch (waitResult) {
case WAIT_OBJECT_0:
printf("Got in wait_result0");
mappedFileHandle = OpenFileMapping (
FILE_MAP_ALL_ACCESS,
FALSE,
MEMORY_MAPPING_NAME
);
if (mappedFileHandle == NULL) {
printf("Could not open file mapping");
return errorForJavaProgram;
}
// read data here, must be a critical region
buffer = (LPTSTR) MapViewOfFile(
mappedFileHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
BUFFER_SIZE
);
if (buffer == NULL) {
printf("Could not map view");
CloseHandle(mappedFileHandle);
return errorForJavaProgram;
}
message = (*env)->NewStringUTF(env, buffer);
if (!ReleaseSemaphore(semaphore, 1, NULL)) {
printf("An error occured releasing the semaphore: %d\n", GetLastError());
return -1;
}
default:
printf("Got to default \n");
} //switch
Your switch statement is subject to fall through. For one of the many discussions that can be found here on Stack Overflow, see Does case-switch work like this?.
Your code executes the WAIT_OBJECT_0 and then simply continues to the default case. You need to add a break or a return at the very end of the WAIT_OBJECT_0 case.

How to Send IOCTL's to all drivers on windows in C

Can someone provide me with a sample C code that list´s all device Names that i can open with Createfile()? i always get error code 3 : path does not exist
sample code that doesnt works:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include <regstr.h>
#include <devioctl.h>
#include <usb.h>
#include <usbiodef.h>
#include <usbioctl.h>
#include <usbprint.h>
#include <setupapi.h>
#include <devguid.h>
#include <wdmguid.h>
#pragma comment(lib, "Setupapi.lib")
int main(void){
HDEVINFO deviceInfoList;
deviceInfoList = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (deviceInfoList != INVALID_HANDLE_VALUE)
{
SP_DEVINFO_DATA deviceInfoData;
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (DWORD i = 0; SetupDiEnumDeviceInfo(deviceInfoList, i, &deviceInfoData); i++)
{
LPTSTR buffer = NULL;
DWORD buffersize = 0;
while (!SetupDiGetDeviceInstanceIdA(deviceInfoList, &deviceInfoData, buffer, buffersize, &buffersize))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
if (buffer) delete buffer;
buffer = new TCHAR[buffersize];
}
else
{
printf("%ls\n", "error");
break;
}
}
HANDLE hFile = CreateFileA(buffer,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("InvalidHandle, error code: %d\n", GetLastError());
}
CloseHandle(hFile);
printf("%s\n", buffer);
if (buffer) { delete buffer; buffer = NULL; }
}
}
getchar();
}
my Goal is to print all valid device Names and try to get a valid handle on it that i can later user for sending ioctl`s
thx
EDIT:
ok abhineet so thats what i got now :
DWORD EnumerateDevices(){
DWORD dwResult = 0;
HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);// DIGCF_ALLCLASSES
/*HDEVINFO hdev =SetupDiGetClassDevs(NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES); */
if (INVALID_HANDLE_VALUE != hdev) {
for (int idev = 0; idev < 100; idev++)
{
SP_DEVICE_INTERFACE_DATA did = { 0 };
did.cbSize = sizeof(did);
if (SetupDiEnumDeviceInterfaces(hdev, NULL, &GUID_DEVCLASS_BATTERY, idev, &did))
{
DWORD cbRequired = 0;
SetupDiGetDeviceInterfaceDetail(hdev,
&did,
NULL,
0,
&cbRequired,
0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, cbRequired);
if (pdidd) {
pdidd->cbSize = sizeof(*pdidd);
if (SetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, cbRequired, &cbRequired, 0)) {
wprintf(L"%s\n", pdidd->DevicePath);
HANDLE hBattery = CreateFile(pdidd->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE != hBattery)
{
printf("Successfully opened Handle\n");
CloseHandle(hBattery);
}
else{
wprintf(L"CreateFile(%s) failed %d\n", pdidd->DevicePath, GetLastError());
}
}
else{
printf("SetupDiGetDeviceInterfaceDetail() failed %d\n", GetLastError());
}
LocalFree(pdidd);
}
}
else{
printf("SetupDiGetDeviceInterfaceDetail() failed %d\n", GetLastError());
}
}
else if (ERROR_NO_MORE_ITEMS == GetLastError())
{
printf("-NoMoreItems-");
break; // Enumeration failed - perhaps we're out of items
}
}
SetupDiDestroyDeviceInfoList(hdev);
}
else{
printf("SetupDiGetClassDevs() failed %d\n", GetLastError());
}
return dwResult;
}
i ripped the most from here : https://msdn.microsoft.com/en-us/library/windows/desktop/bb204769(v=vs.85).aspx
and my Output is :
\\?\acpi#pnp0c0a#1#{72631e54-78a4-11d0-bcf7-00aa00b7b32a}
Successfully opened Handle
-NoMoreItems-
at least i got a valid handle!
so i wanna do this an all devices avaible on the System , how to do that?
IMHO, I don't think, you can do a CreateFile on InstanceID. To do a CreateFile, you need the symbolic name of the device. You can use the following SetupAPIs,
SetupDiEnumDeviceInterfaces
SetupDiGetDeviceInterfaceDetail
The Remark section of both APIs state that,
SetupDiEnumDeviceInterfaces:: DeviceInterfaceData points to a structure that identifies a requested
device interface. To get detailed information about an interface, call
SetupDiGetDeviceInterfaceDetail. The detailed information includes the
name of the device interface that can be passed to a Win32 function
such as CreateFile (described in Microsoft Windows SDK documentation)
to get a handle to the interface.
SetupDiGetDeviceInterfaceDetail:: The interface detail returned by this function consists of a device path that can be passed to Win32
functions such as CreateFile. Do not attempt to parse the device path
symbolic name. The device path can be reused across system starts.
This might be of your use, how to get DevicePath from DeviceID

Read specific sector on hard drive using C language on windows

i have tried this code it works when i read a sector from an USB flash drive but it does'nt work with any partiton on hard drive , so i want to know if it's the same thing when you try to read from usb or from hard drive
int ReadSector(int numSector,BYTE* buf){
int retCode = 0;
BYTE sector[512];
DWORD bytesRead;
HANDLE device = NULL;
device = CreateFile("\\\\.\\H:", // Drive to open
GENERIC_READ, // Access mode
FILE_SHARE_READ, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL); // Handle to template
if(device != NULL)
{
SetFilePointer (device, numSector*512, NULL, FILE_BEGIN) ;
if (!ReadFile(device, sector, 512, &bytesRead, NULL))
{
printf("Error in reading disk\n");
}
else
{
// Copy boot sector into buffer and set retCode
memcpy(buf,sector, 512);
retCode=1;
}
CloseHandle(device);
// Close the handle
}
return retCode;}
The problem is the sharing mode. You have specified FILE_SHARE_READ which means that nobody else is allowed to write to the device, but the partition is already mounted read/write so it isn't possible to give you that sharing mode. If you use FILE_SHARE_READ|FILE_SHARE_WRITE it will work. (Well, provided the disk sector size is 512 bytes, and provided the process is running with administrator privilege.)
You're also checking for failure incorrectly; CreateFile returns INVALID_HANDLE_VALUE on failure rather than NULL.
I tested this code successfully:
#include <windows.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
int retCode = 0;
BYTE sector[512];
DWORD bytesRead;
HANDLE device = NULL;
int numSector = 5;
device = CreateFile(L"\\\\.\\C:", // Drive to open
GENERIC_READ, // Access mode
FILE_SHARE_READ|FILE_SHARE_WRITE, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL); // Handle to template
if(device == INVALID_HANDLE_VALUE)
{
printf("CreateFile: %u\n", GetLastError());
return 1;
}
SetFilePointer (device, numSector*512, NULL, FILE_BEGIN) ;
if (!ReadFile(device, sector, 512, &bytesRead, NULL))
{
printf("ReadFile: %u\n", GetLastError());
}
else
{
printf("Success!\n");
}
return 0;
}

Resources