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); }

In reply to Enumeratng Windows CDROM devices by tlhackque
in thread Generating a windows Device Interface Path in perl? SOLVED! by cmv

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.