in reply to Re: Generating a windows Device Interface Path in perl?
in thread Generating a windows Device Interface Path in perl? SOLVED!

This code was very helpful. It does have some drawbacks, such as casting pointers to and from int, and not enumerating interfaces.

Below is a require file that builds on the ideas and exports a single function, which I use to provide a sensible UI for CDROM devices. Of course, it can be modified for other uses. I don't claim it's perfect, but I thought that in exchange for the excellent starting point, I should give back. Note that it is customized for CDROMs; for other disks, you'll want to retrieve the partition number and for non-storage, do something else...

The code may be freely used and modified - no warranty, but please follow the usual rules: credit the source, add a comment if you make any modifications, and do not remove the copyright. Enjoy.

# CD drive information # Copyright (C) 2018 Timothe Litt litt _at acm ddot org # # This code may be freely used and modified. There is no # warranty - use at your own risk. You may not remove # the copyright. If you make any changes, add a comment # identifying yourself and the change. # use 5.10.0; use warnings; use strict; package CdInfo; our $VERSION = '1.001'; my $gitid = '$Format:%H$'; our $cdate = '$Format:%cD$'; $VERSION .= ", commit $gitid" if( $gitid !~ /^\044Format:.*\$$/ ); use Exporter; our @ISA = qw/Exporter/; our @EXPORT_OK = qw/cdinfo/; use File::Find; my $libpath; my $incpath; $libpath = '' unless( $libpath ); $incpath = '' unless( $incpath ); BEGIN { find( { wanted => sub { /^libsetupapi\.a$/i && ($libpath ||= $File::Find::dir); /^setupapi\.h$/i && ($incpath ||= $File::Find::dir); }, follow => 1, follow_skip => 2 }, @INC ); die( "No MinGW libsetupapi $libpath $incpath\n" ) unless( $libpath && $incpath ); } use Inline( C => Config => libs => "-L$libpath -lSetupAPI", INC => "-I$incpath", # print_info => 1, # BUILD_NOISY => 1, ); use Inline 'C'; Inline->init; 1; __DATA__ __C__ #include <windows.h> #include <stdio.h> #include <initguid.h> #include <devguid.h> #include <regstr.h> #include <setupapi.h> #include <WinioCtl.h> /* Error codes can be looked-up at * https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v +=vs.85).aspx */ /* Returns an array that may be suitable for initializing a hash. * Each CDROM device returns two elements. * The second is always the "Friendly" name of the device. * item selects the first: * 0 - The storage device number (note: not persisted across reboots) * 1 - The device path (suitable for calling CreateFile) * * '' is returned if he value can't be obtained or item is out of rang +e. * Multiple errors will, of course, be replaced by the last entry if * used as a hash initializer. In that case, to get all the errors, * inspect the array. */ void cdinfo( int item ) { INLINE_STACK_VARS; HDEVINFO hDevInfo; SP_DEVINFO_DATA DeviceInfoData; DWORD i, n = 0, DataT; INLINE_STACK_RESET; static GUID GUID_DEVINTERFACE_CDROM = { 0x53F56308, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B } }; /* Create a set of all present CDROM devices. */ hDevInfo = SetupDiGetClassDevs( &GUID_DEVINTERFACE_CDROM, NULL, NU +LL, DIGCF_PRESENT | DIGCF_DEVICEINTERF +ACE ); if( hDevInfo == INVALID_HANDLE_VALUE) { char buf[132]; sprintf( buf, "cdinfo: SetupDiGetClassDevs error %08x", GetLast +Error() ); croak( buf ); } /* Enumerate all devices in set. */ memset( &DeviceInfoData, 0, sizeof(DeviceInfoData ) ); DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); i = 0; while( SetupDiEnumDeviceInfo( hDevInfo, i++, &DeviceInfoData ) ) { SP_DEVICE_INTERFACE_DATA ifdata; DWORD j = 0; memset( &ifdata, 0, sizeof( ifdata )); ifdata.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); while( SetupDiEnumDeviceInterfaces( hDevInfo, &DeviceInfoData, &GUID_DEVINTERFACE_CDROM, +j++, &ifdata ) ) { PSP_DEVICE_INTERFACE_DETAIL_DATA detail = NULL; LPTSTR buffer = NULL; DWORD buffersize = 0; SP_DEVINFO_DATA DevInfoData; HANDLE devhandle; STORAGE_DEVICE_NUMBER devnum; DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); /* Obtain device path name (\\?\bus...) */ if( !SetupDiGetDeviceInterfaceDetail( hDevInfo, &ifdata, NULL, 0, &buffersize +, NULL ) && GetLastError() != ERROR_INSUFFICIENT_BUFFER ) { char buf[132]; sprintf( buf, "cdinfo: SetupDiGetDeviceInterfaceDetail erro +r %08x", GetLastError() ); croak( buf ); } detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc( LPTR, buffersize ); detail->cbSize = sizeof( SP_DEVICE_INTERFACE_DETAIL_DATA +); if( !SetupDiGetDeviceInterfaceDetail( hDevInfo, &ifdata, detail, buffersize, + NULL, &DevInfoData ) ) { char buf[132]; sprintf( buf, "cdinfo: SetupDiGetDeviceInterfaceDetail err +or %08x", GetLastError() ); if( detail ) LocalFree( detail ); croak( buf ); } switch( item ) { case 0: devhandle = CreateFile( detail->DevicePath, 0, FILE_SHARE_DELETE|FILE_SHARE_ +READ| FILE_SHARE_ +WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) +; if( devhandle == INVALID_HANDLE_VALUE || ! DeviceIoControl( devhandle, IOCTL_STORAGE_GET_DEVICE_NUMBE +R, NULL, 0, &devnum, sizeof( devn +um ), &buffersize, NULL ) ) { INLINE_STACK_PUSH(sv_2mortal(newSVpv("", 0))); } else { INLINE_STACK_PUSH(sv_2mortal(newSVuv(devnum.Devic +eNumber))); } if( devhandle != INVALID_HANDLE_VALUE ) CloseHandle( devhandle ); break; case 1: INLINE_STACK_PUSH(sv_2mortal(newSVpv(detail->DevicePa +th, 0))); break; default: INLINE_STACK_PUSH(sv_2mortal(newSVpv("", 0))); break; } ++n; LocalFree( detail ); detail = NULL; buffersize = 0; while( !SetupDiGetDeviceRegistryProperty( hDevInfo, &DevInfoData, SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buffer, buffersize, &buffersize)) { if( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { /* Increase the buffer size. */ if( buffer) LocalFree(buffer); buffer = (LPTSTR)LocalAlloc( LPTR, buffersize ); } else { char buf[132]; sprintf( buf, "cdinfo: SetupDiGetDeviceRegistryPropert +y error %08x", GetLastError() ); if( buffer) LocalFree(buffer); croak(buf); } } SetLastError( 0 ); INLINE_STACK_PUSH(sv_2mortal(newSVpv(buffer, 0))); ++n; if( buffer) LocalFree(buffer); buffer = NULL; buffersize = 0; } if( GetLastError() != NO_ERROR && GetLastError() != ERROR_NO_MORE_ITEMS ) { char buf[132]; sprintf( buf, "cdinfo: SetupDiEnumDeviceInterfaces error %08x", GetLastError() ); croak(buf); } } if( GetLastError() != NO_ERROR && GetLastError() != ERROR_NO_MORE_ITEMS ) { char buf[132]; sprintf( buf, "cdinfo: SetupDiEnumDeviceInfo error %08x", GetLastEr +ror() ); croak(buf); } SetupDiDestroyDeviceInfoList(hDevInfo); INLINE_STACK_DONE; INLINE_STACK_RETURN(n); }

Replies are listed 'Best First'.
Re: Enumeratng Windows CDROM devices
by afoken (Chancellor) on Jun 01, 2018 at 20:18 UTC