I am trying to open a device driver in order to send it an ioctl. There are many examples on SO and elsewhere but virtually all address opening "\\.\PhysicalDrive0" or the like. But I am trying to open a non-disk driver, compiled from Microsoft sample code at GitHub "Windows-driver-samples", namely "simgpio". It appears to have installed correctly but I don't know what "\\.\name" to use. I tried "\\.\simgpio" with no joy. Suggestions?
For reference, I've included the driver's .INF file below.
;/*++
;
;Copyright (c) Microsoft Corporation. All rights reserved.
;
;Module Name:
;
; SIMGPIO.INF
;
;Abstract:
; INF file for installing Simulated GPIO Client Driver.
;
;--*/
[Version]
Signature="$WINDOWS NT$"
Class=System
ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}
Provider=%ProviderName%
DriverVer = 06/30/2020,15.29.58.35
CatalogFile=gpiosamples.cat
[SourceDisksNames]
3426=windows cd
[SourceDisksFiles]
simgpio.sys = 3426
[DestinationDirs]
DefaultDestDir = 12
[ControlFlags]
BasicDriverOk = *
ExcludeFromSelect = *
;******************************************
; SIMGPIO Client driver Install Section
;******************************************
[Manufacturer]
%ManufacturerName%=Standard,NTx86
[Standard.NTx86]
%GPIO.DeviceDesc% = GPIO_Inst,ACPI\TEST0001
[GPIO_Inst.NT]
Copyfiles = GPIOCopyFiles
[GPIOCopyFiles]
simgpio.sys,,,0x100
[GPIO_Inst.NT.Services]
AddService = simgpio,%SPSVCINST_ASSOCSERVICE%,GPIO_Service_Inst
[GPIO_Service_Inst]
DisplayName = %GPIO.SvcDesc%
ServiceType = %SERVICE_KERNEL_DRIVER%
StartType = %SERVICE_DEMAND_START%
ErrorControl = %SERVICE_ERROR_NORMAL%
ServiceBinary = %12%\simgpio.sys
[strings]
; localizable strings
ProviderName = "TODO-Set-Provider"
ManufacturerName = "TODO-Set-Manufacturer"
GPIO.DeviceDesc = "Simulated GPIO Client Driver"
GPIO.SvcDesc = "Simulated GPIO Client Driver"
; non-localizable strings
SPSVCINST_TAGTOFRONT = 0x00000003
SPSVCINST_ASSOCSERVICE = 0x00000002
SERVICE_KERNEL_DRIVER = 1
SERVICE_BOOT_START = 0
SERVICE_SYSTEM_START = 1
SERVICE_DEMAND_START = 3
SERVICE_ERROR_NORMAL = 1
SERVICE_ERROR_IGNORE = 0
SERVICE_ERROR_CRITICAL = 3
REG_EXPAND_SZ = 0x00020000
REG_DWORD = 0x00010001
REG_SZ = 0x00000000
Thanks to comment by #Eryk, I was able to open a driver. I include a sample program below. All error checking was omitted for clarity. I used the CDROM driver class in this example. The real challenge is finding the elusive GUID to use - you must do some deep digging in the SDK, DDK, include files or your driver.
// enumdevices.c - enumerate and open device(s)
#pragma warning( disable : 4090 )
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <setupapi.h>
#include <cfgmgr32.h>
int
main( int argc,char** argv)
{
#define ALLOC(size) GlobalAlloc( GPTR, size)
SP_DEVINFO_DATA *devData;
HANDLE devSet;
HANDLE hDev;
SP_DEVICE_INTERFACE_DATA *devIfData;
SP_DEVICE_INTERFACE_DETAIL_DATA *Details;
GUID *devGuid;
DWORD needed;
DWORD unused;
int count; // count of enumerated devices
DWORD idev; // device index
DWORD iface; // interface index
char deviceID[200]; // device id string
int IDSize;
BOOL ok;
devData = ALLOC( sizeof(SP_DEVINFO_DATA) );
devData->cbSize = sizeof(SP_DEVINFO_DATA);
// GET SET OF DEVICE INTERFACES PRESENT OF SPECIFIED devGuid
devGuid = &GUID_DEVINTERFACE_CDROM; // set dev class guid to enumerate
devSet = SetupDiGetClassDevs( devGuid, NULL, NULL, DIGCF_DEVICEINTERFACE|DIGCF_PRESENT );
// OUTER LOOP
idev = 0;
count = 0;
while( TRUE ) {
// GET DEVICE INFO DATA
ok = SetupDiEnumDeviceInfo( devSet, idev, devData );
if (!ok) break;
// GET ID SIZE
devData->cbSize = sizeof(SP_DEVINFO_DATA);
CM_Get_Device_ID_Size( &IDSize, devData->DevInst, 0 );
// GET DEVICE ID
CM_Get_Device_ID( devData->DevInst, deviceID, 200, 0 );
printf("Device Instance #%d: deviceId = \"%s\"\n", devData->DevInst, deviceID ); // print it
count++;
devIfData = ALLOC( sizeof(SP_DEVICE_INTERFACE_DATA) );
devIfData->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
iface = 0; // init index
while ( TRUE ) { // loop over all interfaces in set
// GET DEVICE INTERFACE DATA index=iface
ok = SetupDiEnumDeviceInterfaces(
devSet, // handle to interface set
devData,
devGuid, //&GUID_DEVINTERFACE_USB_DEVICE,
iface, // interface index
devIfData);
if( !ok ) break;
// GET NEEDED BUFFER SIZE
devIfData->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
ok = SetupDiGetDeviceInterfaceDetail(
devSet,
devIfData,
NULL,
0,
&needed,
0 );
Details = ALLOC( needed );
Details->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); // IMPORTANT!
// GET DEVICE DETAILS
ok = SetupDiGetDeviceInterfaceDetail(
devSet, // device set
devIfData, // device info data
Details, // detail data
needed, // size of Details
&unused, // unused
NULL ); // device info data (can be NULL)
printf("%s\n", Details->DevicePath); // announce
// OPEN DEVICE
hDev = CreateFile(Details->DevicePath,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if( hDev != INVALID_HANDLE_VALUE ) {
printf( "Device successfully opened\n" );
// DO SOMETHING WITH DEVICE HANDLE (e.g., DeviceIoControl)...
CloseHandle(hDev);
}
iface++;
}
idev++; // next device
}
printf("\nenumerated %d device interfaces\n", count);
fprintf(stderr, "Press any key to exit...\n");
_getch();
}
Here are some other GUIDs you can use:
static GUID GUID_DEVINTERFACE_DISK =
{ 0x4d36e967L, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
static GUID GUID_DEVINTERFACE_USB_DEVICE =
{ 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
static GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER =
{ 0x3abf6f2d, 0x71c4, 0x462a, {0x8a, 0x92, 0x1e, 0x68, 0x61, 0xe6, 0xaf, 0x27} };
static GUID GUID_DEVINTERFACE_USB_HUB =
{ 0xf18a0e88, 0xc30c, 0x11d0, {0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8} };
Related
I need to detect when a gamepad is plugged in for my game (I'm not using a higher-level input API for reasons), how can I do this? I've already enumerated all HID devices and opened files on them (except keyboard, mouse ofc) and can get all the info on the device, but what info do I want? What value(s) will tell me right away that this is an xbox controller, for example, and where are these values?
My code for enumerating over the devices (very messy atm :p):
DWORD required_size = 0, determined_size;
SP_DEVICE_INTERFACE_DATA device_interface_data;
device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
PSP_DEVICE_INTERFACE_DETAIL_DATA device_interface_detail_data;
HANDLE current_device;
PHIDP_PREPARSED_DATA preparsed_data;
WCHAR product_string[128];
for (int i = 0; ; ++i) /* Enumerate HID devices */
{
rv = SetupDiEnumDeviceInterfaces(device_enumeration, NULL, &interface_guid, i, &device_interface_data); /* Does the actual enumeration,
each time we increase index i
to get the next device */
error = GetLastError();
if (error == ERROR_NO_MORE_ITEMS) /* If there are no more devices, break */
break;
else if (!rv && error != ERROR_NO_MORE_ITEMS) /* Otherwise, we have a legit error */
{
cr_print_error(GetLastError());
return EXIT_FAILURE;
}
SetupDiGetDeviceInterfaceDetail(device_enumeration, &device_interface_data, NULL, 0, &required_size, NULL); /* Probing call only to get buffer size,
so error code (122) ignored */
/* Allocate new device detail struct using buffer size we obtained */
determined_size = required_size;
device_interface_detail_data = cr_safe_malloc(required_size);
device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
/* Get detailed info about device */
rv = SetupDiGetDeviceInterfaceDetail(device_enumeration, &device_interface_data, device_interface_detail_data, determined_size, &required_size, NULL);
if (!rv)
{
cr_print_error(GetLastError());
return EXIT_FAILURE;
}
cr_printf("FOUNDD DEVICE: %s\n\n", device_interface_detail_data->DevicePath);
current_device = cr_open_device(device_interface_detail_data->DevicePath);
if (!current_device && GetLastError() == ERROR_ACCESS_DENIED)
goto Done;
cr_printf("OPENED DEVICE: %s\n\n", device_interface_detail_data->DevicePath);
preparsed_data = HidD_GetPreparsedData(current_device, &preparsed_data);
if (!preparsed_data)
{
cr_print_error(GetLastError());
return EXIT_FAILURE;
}
HidD_GetProductString(current_device, product_string, sizeof(product_string));
cr_printf("PRODUCT STRING: %S\n\n", product_string);
HidD_FreePreparsedData(&preparsed_data);
DeleteFile(device_interface_detail_data->DevicePath);
Done:
cr_safe_free(&device_interface_detail_data);
}
SetupDiDestroyDeviceInfoList(device_enumeration);
As you can see I've found the product string, which tells me what the device actually is, but maybe comparing product strings is not the best way to do PnP?
Check if the device ID contains "IG_". If it does, then it's an XInput device.
More info on that. But which device corresponds to which XInput dwUserIndex is more difficult question...
Also you can try to check for XUSB interface:
// {EC87F1E3-C13B-4100-B5F7-8B84D54260CB}
DEFINE_GUID(XUSB_INTERFACE_CLASS_GUID, 0xEC87F1E3, 0xC13B, 0x4100, 0xB5, 0xF7, 0x8B, 0x84, 0xD5, 0x42, 0x60, 0xCB);
I am using a PIC18F26K80 and an XC8 compiler. I am trying to initialise an SD card and create a file. I have simply formatted the SD card on Windows to have a "FAT32" file system and an "Allocation unit size" of 512 bytes. The capacity of the SD card is 2GB. I am using the MDD library from the MLA Legacy version. My main is the following:
FSFILE * file;
char sendBuffer[22] = "This is test string 1";
//**************************************************
// main function
//**************************************************
int main()
{
initIO();
LATBbits.LATB0 = 0;
// Initialise SPI and SD-card
while ( !MDD_MediaDetect() );
// Initialize the device
while ( !FSInit() );
// Initialize
#ifdef ALLOW_WRITES
// Create a new file
file = FSfopenpgm ( "FILE.TXT", "w" );
if ( file == NULL )
while(1);
// Write 21 1-byte objects from sendBuffer into the file
if ( FSfwrite ( (void *) sendBuffer, 1, 21, file ) != 21 )
while(1);
// Close the file
if ( FSfclose ( file ) )
while(1);
#endif
LATBbits.LATB0 = 1; //LED
while(1) {}
return (0);
}
The program gets stuck inside the function "FSInit()" and the error I get from the function is "CE_BAD_PARTITION", which means "The boot record is bad".
The "initIO()" function is the following:
//==============================================================================
// void initIO( void );
//==============================================================================
// Sets the pins on the PIC to input or output and determines the speed of the
// internal oscilaltor
// input: none
// return: none
//==============================================================================
void initIO()
{
OSCCON = 0x75; // Clock speed = 32MHz (4x8Mhz)
TRISA = 0;
TRISB = 0;
TRISC = 0;
TRISBbits.TRISB0 = 0; //LED
TRISCbits.TRISC3 = 0; // set SCL pin as output
TRISCbits.TRISC4 = 1; // set RC4 pin as input
TRISCbits.TRISC5 = 0;
TRISAbits.TRISA5 = 0;
}
I am using an ACR122U NFC reader to password protect an NTAG213 NFC label. I think I have managed to set the password correctly, but I cannot authenticate and change the label afterward. My code for authenticating looks like this:
#include <winscard.h>
#include <iostream>
#pragma comment(lib, "winscard.lib")
const char *ReaderName = "ACS ACR122 0";
unsigned Password = 0x12345678;
int main()
{
//Establish context
SCARDCONTEXT hContext;
DWORD SCard_Status1 = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hContext);
if(SCard_Status1 != SCARD_S_SUCCESS)
return 1;
//connect to the card
SCARDHANDLE hCardHandle;
DWORD Protocol;
DWORD SCard_Status2 = SCardConnect(hContext, ReaderName, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &hCardHandle, &Protocol);
if(SCard_Status2 != SCARD_S_SUCCESS)
{
SCardReleaseContext(hContext);
return 1;
}
SCARD_IO_REQUEST Request;
Request.dwProtocol = Protocol;
Request.cbPciLength = sizeof(SCARD_IO_REQUEST);
BYTE TxData[] =
{
0xFF, //CLA
0x00, //INS
0x00, //P1
0x00, //P2
0x08, //LC
0xD4,
0x40,
0x01,
0x1B, //PWD_AUTH (See data sheet)
Password,
Password >> 8,
Password >> 16,
Password >> 24,
};
BYTE RxData[254];
unsigned long RxLength = sizeof(RxData);
DWORD SCard_Status3 = SCardTransmit(hCardHandle, &Request, TxData, sizeof(TxData), NULL, RxData, &RxLength);
std::cout << "SCard_Status = " << SCard_Status3 << std::endl;
std::cout << "RxLength = " << RxLength << std::endl;
SCardDisconnect(hCardHandle, SCARD_EJECT_CARD);
SCardReleaseContext(hContext);
return 0;
}
This should send the PWD_AUTH command to the NTAG213 with the Pwd. I expected to receive an error if the password is wrong or two bytes with the PACK if the password is correct. But SCard_Status is SCARD_S_SUCCESS and RxLength is 0 afterwards. And if I try to write to the label I get an error.
I am having trouble finding any examples showing how to do this. Can anyone see what I am doing wrong?
I am going to answer this myself. I managed to make it work by changing TxData to this:
BYTE TxData[] =
{
0xFF, //CLA
0x00, //INS
0x00, //P1
0x00, //P2
0x07, //LC
0xD4, 0x42, //InCommunicateThru
0x1B, //PWD_AUTH (See data sheet)
Password,
Password >> 8,
Password >> 16,
Password >> 24,
};
I found the command InCommunicateThru (D4 42) as a replacement for InDataExchange (D4 40) in the data sheet for the PN532, which is the NFC processor inside the ACR122U.
I am developing a multi-platform game that runs on iOS as well as desktops (Windows, Mac, Linux). I want the game to be able to resize certain UI elements depending on the resolution of the screen in inches. The idea is that if a button should be, say, around 1/2 inch across in any interface, it will be scaled automatically that size.
Now for iOS devices this problem is reasonably well solvable using brute force techniques. You can look up the type of the device and use a hard-coded table to determine the screen size in inches for each device. Not the most elegant solution, but sufficient.
Desktops are the tricky ones. What I wish and hope exists is a mechanism by which (some?) monitors report to operating systems their actual screen size in inches. If that mechanism exists and I can access it somehow, I can get good numbers at least for some monitors. But I've never come across any such concept in any of the major OS APIs.
Is there a way to ask for the screen size in inches in Win32? If so, are there monitors that actually provide this information?
(And if the answer is no: Gosh, doesn't this seem awfully useful?)
For Windows, first see SetProcessDPIAware() for a discussion on turning off automatic scaling, and then call GetDeviceCaps( LOGPIXELSX ) and GetDeviceCaps( LOGPIXELSY ) on your HDC to determine the monitor's DPI. Divide the screen resolution on your active monitor by those settings and you've got the size.
Also see this article for a similar discussion on DPI aware apps.
Here is a method I found at the web address "https://ofekshilon.com/2011/11/13/reading-monitor-physical-dimensions-or-getting-the-edid-the-right-way/".
Authour says that measurement is in millimeters.
Does not give you the precise width and height but better approximation than HORSIZE and VERTSIZE. In which I tried on two different monitors and got a max difference of 38 cm (measured screen size - calculated screen size).
#include <SetupApi.h>
#pragma comment(lib, "setupapi.lib")
#define NAME_SIZE 128
const GUID GUID_CLASS_MONITOR = {0x4d36e96e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18};
// Assumes hDevRegKey is valid
bool GetMonitorSizeFromEDID(const HKEY hDevRegKey, short& WidthMm, short& HeightMm)
{
DWORD dwType, AcutalValueNameLength = NAME_SIZE;
TCHAR valueName[NAME_SIZE];
BYTE EDIDdata[1024];
DWORD edidsize=sizeof(EDIDdata);
for (LONG i = 0, retValue = ERROR_SUCCESS; retValue != ERROR_NO_MORE_ITEMS; ++i)
{
retValue = RegEnumValueA ( hDevRegKey, i, &valueName[0],
&AcutalValueNameLength, NULL, &dwType,
EDIDdata, // buffer
&edidsize); // buffer size
if (retValue != ERROR_SUCCESS || 0 != strcmp(valueName,"EDID"))
continue;
WidthMm = ((EDIDdata[68] & 0xF0) << 4) + EDIDdata[66];
HeightMm = ((EDIDdata[68] & 0x0F) << 8) + EDIDdata[67];
return true; // valid EDID found
}
return false; // EDID not found
}
// strange! Authour requires TargetDevID argument but does not use it
bool GetSizeForDevID(const char *TargetDevID, short& WidthMm, short& HeightMm)
{
HDEVINFO devInfo = SetupDiGetClassDevsExA(
&GUID_CLASS_MONITOR, //class GUID
NULL, //enumerator
NULL, //HWND
DIGCF_PRESENT, // Flags //DIGCF_ALLCLASSES|
NULL, // device info, create a new one.
NULL, // machine name, local machine
NULL);// reserved
if (NULL == devInfo) return false;
bool bRes = false;
for (ULONG i=0; ERROR_NO_MORE_ITEMS != GetLastError(); ++i)
{
SP_DEVINFO_DATA devInfoData;
memset(&devInfoData,0,sizeof(devInfoData));
devInfoData.cbSize = sizeof(devInfoData);
if (SetupDiEnumDeviceInfo(devInfo,i,&devInfoData))
{
HKEY hDevRegKey = SetupDiOpenDevRegKey(devInfo,&devInfoData,DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if(!hDevRegKey || (hDevRegKey == INVALID_HANDLE_VALUE)) continue;
bRes = GetMonitorSizeFromEDID(hDevRegKey, WidthMm, HeightMm);
RegCloseKey(hDevRegKey);
}
}
SetupDiDestroyDeviceInfoList(devInfo);
return bRes;
}
int main(int argc, CHAR* argv[])
{
short WidthMm, HeightMm;
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
DWORD dev = 0; // device index
int id = 1; // monitor number, as used by Display Properties > Settings
char DeviceID[1024];
bool bFoundDevice = false;
while (EnumDisplayDevices(0, dev, &dd, 0) && !bFoundDevice)
{
DISPLAY_DEVICE ddMon = {sizeof(ddMon)};
DWORD devMon = 0;
while (EnumDisplayDevices(dd.DeviceName, devMon, &ddMon, 0) && !bFoundDevice)
{
if (ddMon.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP &&
!(ddMon.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
{
sprintf(DeviceID,"%s", ddMon.DeviceID+8);
for(auto it=DeviceID; *it; ++it)
if(*it == '\\') { *it = 0; break; }
bFoundDevice = GetSizeForDevID(DeviceID, WidthMm, HeightMm);
}
devMon++;
ZeroMemory(&ddMon, sizeof(ddMon));
ddMon.cb = sizeof(ddMon);
}
ZeroMemory(&dd, sizeof(dd));
dd.cb = sizeof(dd);
dev++;
}
return 0;
}
Here's the code using GetOpenFileNameW:
import core.sys.windows.windows;
import std.stdio, std.string, std.utf;
pragma(lib, "comdlg32");
// Fill in some missing holes in core.sys.windows.windows.
extern (Windows) DWORD CommDlgExtendedError();
enum OFN_FILEMUSTEXIST = 0x001000;
void main()
{
auto buf = new wchar[1024];
OPENFILENAMEW ofn;
ofn.lStructSize = ofn.sizeof;
ofn.lpstrFile = buf.ptr;
ofn.nMaxFile = buf.length;
ofn.lpstrInitialDir = null;
ofn.Flags = OFN_FILEMUSTEXIST;
BOOL retval = GetOpenFileNameW(&ofn);
if (retval == 0) {
// Get 0x3002 for W and 0x0002 for A. ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms646916(v=vs.85).aspx )
throw new Exception(format("GetOpenFileName failure: 0x%04X.", CommDlgExtendedError()));
}
writeln(buf);
}
This results in FNERR_INVALIDFILENAME, but I don't see any non-optional strings that I haven't filled in. And here's the code (only differences shown) for GetOpenFileNameA:
auto buf = new char[1024];
OPENFILENAMEA ofn;
// ...
BOOL retval = GetOpenFileNameA(&ofn);
This results in CDERR_INITIALIZATION, and the only elaboration MSDN gives me is
The common dialog box function failed during initialization.
This error often occurs when sufficient memory is not available.
This is on Windows 7 64 bit, DMD v2.059.
buf has to be zeroed completely. The problem here is that wchar.init == wchar.max (for error detection reasons), so your array is essentially 1024 instances of wchar.max. A simple buf[] = 0; should fix that.