|
What are the values of your input parameters, they are not shown above? Please also use <pre> tags round your code so it is more readable.
One of these days I'm going to think of a really clever signature.
|
|
|
|
|
I've just tested it and got also FALSE returned when requesting the size. The returned error is 122 / ERROR_INSUFFICIENT_BUFFER . So it seems that this is intentional.
But you must check the error code (e.g. when passing NULL for PropertyBuffer and a value greater NULL for PropertyBufferSize , code 87 / ERROR_INVALID_PARAMETER is set and the returned size is set to the passed value).
If you got other errors like ERROR_INVALID_DATA , check your parameters. Note that the size member of the DeviceInfoData parameter must be initialized:
SP_DEVINFO_DATA DevInfoData;
::ZeroMemory(&DevInfoData, sizeof(SP_DEVINFO_DATA));
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
|
|
|
Here is some of the "calling code", still in test development.( I know it is a mess. sorry)
If I just use this property DWORD Property = SPDRP_DEVICEDESC;
I still get error when looking for the buffewr size only,
but get the size OK.
Than I get another error - something "the parameter passed to the system is too small". I am trying to find some explanation for this error just for the SetupDiGetDeviceRegistryProperty.There are tons of posts about this error , but nothing specific for this function I found so far.
What bugs me is that ewerybody is copying the original MS device iteration sample code and set the buffer to value and when it fails ( allegedly for Win2000 only ) they increase it. That tells me that the setting for finding the buffer size may not really work, hence all these errors.
Thanks for all you help, appreciate it.
bool C_USB::C_Enumerate_All()
{
TRACE("\nbool C_USB::C_Enumerate_All()");
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
CString strLabel = "Friendly name ";
DWORD i;
TRACE("\nCreate a HDEVINFO with all present devices");
TRACE("\nSetupDiGetClassDevs... Create a HDEVINFO with all present devices");
hDevInfo = SetupDiGetClassDevs(
NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES);
if (INVALID_HANDLE_VALUE == hDevInfo)
{
TRACE("\nINVALID_HANDLE_VALUE == hDevInfo");
// Insert error handling here.
return 1;
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
TRACE("\nSetupDiEnumDeviceInfo...Enumerate through all devices in Set");
/*
DeviceInfoSet [in]
A handle to the device information set for which to return an SP_DEVINFO_DATA
structure that represents a device information element.
MemberIndex [in]
A zero-based index of the device information element to retrieve.
DeviceInfoData [out]
A pointer to an SP_DEVINFO_DATA structure to receive information about
an enumerated device information element. The caller must
set DeviceInfoData.cbSize to sizeof(SP_DEVINFO_DATA).
*/
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++)
{
//LPTSTR buffer = NULL;
//DWORD buffersize = 0;
//TRACE("\nShow property using friendly name flag");
TRACE("\nTest show device description ");
DWORD Property = SPDRP_DEVICEDESC;
C_TestPrintProperty(
hDevInfo,
DeviceInfoData,
strLabel,
Property);
/* enumerate all properties test
do
{
C_TestPrintProperty(
hDevInfo,
DeviceInfoData,
strLabel,
Property);
// Property++;
TRACE("\nEnumerate property counter %i", Property);
}while (Property++ != SPDRP_MAXIMUM_PROPERTY);
*/
TRACE("\nEnumerate progress counter %i", i);
}
void C_USB::C_TestPrintProperty(
HDEVINFO hDevInfo,
SP_DEVINFO_DATA DeviceInfoData,
CString strLabel,
DWORD Property)
{
TRACE("\n void C_USB::C_TestPrintProperty(CString strLabel)");
DWORD DataT;
LPTSTR buffer = NULL;
DWORD buffersize = 2048; // 0;
int iCounter = 0;
bool bResult = false;
//buffer = (LPTSTR)LocalAlloc(LPTR, buffersize * 2);
TRACE("\nSetupDiGetDeviceRegistryProperty...");
TRACE("\nReturn required buffer size only ");
// Property = 0; //SPDRP_FRIENDLYNAME; // SPDRP_DEVTYPE; // SPDRP_COMPATIBLEIDS; // SPDRP_CLASS;
bResult = SetupDiGetDeviceRegistryProperty(
hDevInfo, // _In_ HDEVINFO DeviceInfoSet,
&DeviceInfoData, // _In_ PSP_DEVINFO_DATA DeviceInfoData
Property, // _In_ DWORD Property,
&DataT, // _Out_opt_ PDWORD PropertyRegDataType,
NULL, // get size with NULL (PBYTE)buffer, // _Out_opt_ PBYTE PropertyBuffer,
0, // get size with 0 buffersize,
&buffersize); // fills buffer size
// check result
if(!bResult)
{
TRACE("\nMFC Error dialog ");
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
0, // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
MessageBox( (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
goto TEMP;
}
if(buffersize)
{
TRACE("\nFill buffer with property data ");
bResult = SetupDiGetDeviceRegistryProperty(
hDevInfo, // _In_ HDEVINFO DeviceInfoSet,
&DeviceInfoData, // _In_ PSP_DEVINFO_DATA DeviceInfoData
Property, // _In_ DWORD Property,
&DataT, // _Out_opt_ PDWORD PropertyRegDataType,
(PBYTE)buffer, // _Out_opt_ PBYTE PropertyBuffer,
buffersize,
&buffersize); // fills buffer size
// check result
if(!bResult)
{
TRACE("\nMFC Error dialog ");
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
0, // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
MessageBox( (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
}
}
TEMP:
TRACE("\nBuffer %s ",buffer);
TRACE("\nProperty %i ",Property);
return;
|
|
|
|
|
I did not look up all the code (hint: format it as code to improve readability). But I recognized that you print the error message using FormatMessage() . SetupAPI messages are a little bit special. To get the correct error message you must use the macro HRESULT_FROM_SETUPAPI() to pass error codes to FormatMessage() .
See the Guidelines for Using SetupAPI[^]. It also mentions that querying buffer sizes fails with ERROR_INSUFFICIENT_BUFFER (I did not remember when answering first).
|
|
|
|
|
Here is another try.
It is true that the sizing of the buffer will fail as poited out in the sample code which I copied / modified.
I have no problem getting readable messages using MFC code, but I made a mistake asking for the error message twice. Also got sidetracked by the error - I guess I was looking for something about buffer size.
All this aside - when I ask for buffer using SPDRP_DEVICEDESC it sort-off works,
but I did not looked up what exactly SPDRP_DEVICEDESC should contain. I am interested in friendly name for now.
But when I use SPDRP_FRIENDLYNAME , the sizing of buffer fails with "Data is invalid" and the buffer is still 0;
PS I copy my code into here with "code" selected and do preview and it looks formated to me. I have no clue if you guys do not see same format as me. SOrry.
// display list of all (installed) hardware devices
bool C_USB::C_DeviceList()
{
TRACE("\nbool C_USB::C_DeviceList()");
TRACE("\ndisplay list of all (installed) hardware devices");
TRACE("\nEnumerator test ");
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(
NULL,
"USB", //NULL,
NULL,
DIGCF_ALLCLASSES | DIGCF_PRESENT);
TRACE("\nSetupDiGetClassDevs.. USB devices ");
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES );
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;
DWORD Property = SPDRP_FRIENDLYNAME;
// SPDRP_DEVICEDESC;SPDRP_FRIENDLYNAME
// retrieve a REG_SZ string that contains the friendly name of a device.
//
// 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_DEVICEDESC, //Property,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
{
TRACE("\nMFC Error dialog ");
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
0, // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
// The data area passed to a system call is too
// small.
MessageBox( (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
// Change the buffer size.
/*
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = LocalAlloc(LPTR,buffersize * 2);
*/
buffersize = buffersize*2;
// do it again with larger buffer
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
Property,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
{
TRACE("\nMFC Error dialog ");
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
0, // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
// The data area passed to a system call is too
// small.
MessageBox( (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
// Change the buffer size.
/*
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = LocalAlloc(LPTR,buffersize * 2);
*/
//buffersize = buffersize*2;
}
}
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.
// CCCC buffer = LocalAlloc(LPTR,buffersize * 2);
}
else
{
// Insert error handling here.
break;
}
}
printf("Result:[%s]\n",buffer);
if (buffer) LocalFree(buffer);
}
if ( GetLastError()!=NO_ERROR &&
GetLastError()!=ERROR_NO_MORE_ITEMS )
{
// Insert error handling here.
return 1;
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
|
|
|
To get closer, try using a fixed buffer with size 1024 byte. This is sufficient for the requested information (resulting in max.length of 511 Unicode characters).
To format code, use the 'code' link just above the edit window. You can apply code formatting also to your existing posts:
- Choose the 'Edit' link below your post
- Select the text that should be formatted
- Move the mouse over the 'code' link and choose 'C++'
The result is a code block with fixed font and syntax coloring.
|
|
|
|
|
Here is yet another attempt.I stopped using MFC error printout, but the error reporting is still same.
It appears that the function will always fail - returns 0 when
buffer = NULL;
buffersize = 0;
And when buffersize returned is 0 the last error is always ERROR_INVALID_DATA.
When buffersize != 0 and I double it - in next function call I still get ERROR_INVALID_DATA.
I must be using the function incorrectly, but I did follow the sample code.
BTW - setting the buffer size initially > 0 gives same results - ERROR_INVALID_DATA
And I do use "code" when I copy my code here.
I am basically stuck and I AM using this enumeration to learn how to output to USB device. I like to learn how to use the API's, the "wrapper" samples ( copy and play) in CodeProject do not interest me, but I'll take another look at them.
Thanks for all your help.
Cheers Vaclav
// display list of all (installed) hardware devices
bool C_USB::C_DeviceList()
{
TRACE("\nbool C_USB::C_DeviceList()");
TRACE("\ndisplay list of all (installed) hardware devices");
TRACE("\nEnumerator test ");
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(
NULL,
"USB", //NULL,
NULL,
DIGCF_ALLCLASSES | DIGCF_PRESENT);
TRACE("\nSetupDiGetClassDevs.. USB devices ");
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES );
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 buffer = NULL;
DWORD buffersize = 0;
DWORD Property = SPDRP_DEVICEDESC; // SPDRP_FRIENDLYNAME;
bool bResult;
//buffersize = 2048;
//Property = SPDRP_FRIENDLYNAME;
for (Property = SPDRP_DEVICEDESC /* SPDRP_FRIENDLYNAME*/ ; Property != SPDRP_MAXIMUM_PROPERTY; Property++)
{
buffer = NULL;
buffersize = 0;
bResult = SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
Property,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize);
LONG lError = GetLastError();
TRACE("\nProperty %i ", Property);
switch(lError)
{
case ERROR_INSUFFICIENT_BUFFER :
{
TRACE("\nResize buffer ");
buffersize *=2;
bResult = SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
Property,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize);
LONG lError = GetLastError();
switch(lError)
{
case ERROR_INVALID_DATA:
{
TRACE("\nERROR_INVALID_DATA");
break;
}
default:
{
TRACE("\nResize buffer ");
break;
}
}
break;
}
case ERROR_INVALID_DATA:
{
TRACE("\n ERROR_INVALID_DATA");
break;
}
default:
TRACE("\nUnknown ");
}
|
|
|
|
|
As already noted, there must be something else wrong when you get other error codes.
This is extracted from existing working code to enumerate serial ports (note also how it looks compared to your posts):
#include <WinIoCtl.h> // Pre-defined GUIDs
DWORD nNumDev = 0;
SP_DEVINFO_DATA DevInfoData;
::ZeroMemory(&DevInfoData, sizeof(SP_DEVINFO_DATA));
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
HDEVINFO hDevInfo = ::SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT,
NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
BOOL bResult = (INVALID_HANDLE_VALUE != hDevInfo);
while (bResult)
{
bResult = ::SetupDiEnumDeviceInfo(hDevInfo, nNumDev++, &DevInfoData);
if (!bResult)
{
if (ERROR_NO_MORE_ITEMS == ::GetLastError())
bResult = TRUE;
break;
}
DWORD dwDataType = 0;
DWORD dwReqSize = 0;
BYTE lpszBuf[1024]; bResult = ::SetupDiGetDeviceRegistryProperty(
hDevInfo, &DevInfoData, SPDRP_FRIENDLYNAME, &dwDataType,
lpszBuf, sizeof(lpszBuf), &dwReqSize);
}
if (!bResult)
{
HRESULT hRes = HRESULT_FROM_SETUPAPI(::GetLastError());
}
Please note this cite from the Guidelines link I have posted:
Quote: If a SetupAPI function returns successfully, your code must not call GetLastError.
That means that the error condition has to be checked by return values, and not by the value returned by GetLastError() !
|
|
|
|
|
Thanks,
I think I can figure it now.
I have deleted the GUID_DEVINTERFACE_COMPORT, it is for time being udefined. It should work wiht NULL per this:
[in] An optional pointer to a class GUID for a setup class or an interface class. If the DIGCF_DEVICEINTERFACE flag is set, ClassGuid represents an interface class; otherwise, ClassGuid represents a setup class.
If the DIGCF_ALLCLASSES flag is set, this parameter is ignored and the resulting list contains devices of all installed classes.
But I do not follow the last "list contains devices of all installed classes" part since they say "setup class or an interface class" in the beginning.
Maybe that is my problem - which "class" it returns when - setup or interface-
"DIGCF_ALLCLASSES flag is set" ?? Maybe I need to have DIGCF_DEVICEINTERFACE
I'll play with that for now.
|
|
|
|
|
Just a last note. You are passing 'USB' as class. But the MSDN[^] mentions 'USBDevice'. You may also try using the GUID for USB devices:
const GUID GUID_DEVINTERFACE_USB =
{ 0x88BAE032, 0x5A81, 0x49f0, { 0xBC, 0x3D, 0xA4, 0xFF, 0x13, 0x82, 0x16, 0xD6 }};
|
|
|
|
|
Thanks,
I'll try that.
Even when it fails in one way or another - it generally "returns" GUID ( I am not that far in my coding effords to identify the GUID ) when I ask for all devices.
I also folowed your advice ( and MS) to use
// Pass hRes to FormatMessage() to retrieve the error message
HRESULT hRes = HRESULT_FROM_SETUPAPI(::GetLastError());
and it did not change the error formated message.
Thanks for your help, it is much appreciated.
|
|
|
|
|
Recheck if you are compiling Unicode or not. The in/out size parameter is in bytes, not TCHARs, so you should LocalAlloc (AFAIK) with the returned size and cast to LPTSTR.
Nuclear launch detected
|
|
|
|
|
<pre lang="text">
Thanks Cristian,
I have actually given up on figuring it out, but here is the latest ( with lots of development comments) and it does work as advertized.
NULL, // (PBYTE)buf, // get size with NULL (PBYTE)buffer, // _Out_opt_ PBYTE PropertyBuffer,
0, // sizeof(buf),
With these two parameters set this way , the function fails and returns / sets the &nSize.
I am not checking the errors anymore and just run the same function again with results and it returns true.
The rest of it is just an execise to see the “properties” . And it works.
I am going to check my original code , it is possible that I did forget the cast (PBYTE) buffer, but it is such a mess I am really not looking forward to do that. I was just hoping to delete all the commented out attempts a be done with it. I'll check for unicode too.
Thanks
</pre>
bool C_HWDetect::C_Enumerate()
{
TRACE("\nbool C_HWDetect::C_Enumerate()");
WPARAM wParam; // event wiht parameters !!
CString szClass = "";
/* this monitors changes
DWORD dwFlag = DBT_DEVICEARRIVAL != wParam ?
DIGCF_ALLCLASSES : (DIGCF_ALLCLASSES | DIGCF_PRESENT);
*/
DWORD dwFlag = DIGCF_ALLCLASSES | DIGCF_PRESENT;
HDEVINFO hDevInfo = SetupDiGetClassDevs(NULL,"USB", /* szClass,*/ NULL,dwFlag);
if( INVALID_HANDLE_VALUE == hDevInfo ) {
/*
AfxMessageBox(CString("SetupDiGetClassDevs(): ")
+ _com_error(GetLastError()).ErrorMessage(), MB_ICONEXCLAMATION);
*/
return false;
}
CString szDevId;
SP_DEVINFO_DATA spDevInfoData;
if ( C_FindDevice(hDevInfo, szDevId, spDevInfoData) ) {
DWORD DataT ;
TCHAR buf[MAX_PATH];
DWORD nSize = 0;
bool bResult = SetupDiGetDeviceRegistryProperty(
hDevInfo, // _In_ HDEVINFO DeviceInfoSet,
&spDevInfoData, // _In_ PSP_DEVINFO_DATA DeviceInfoData
SPDRP_DEVICEDESC, // _In_ DWORD Property,
&DataT, // _Out_opt_ PDWORD PropertyRegDataType,
NULL, // (PBYTE)buf, // get size with NULL (PBYTE)buffer, // _Out_opt_ PBYTE PropertyBuffer,
0, // sizeof(buf), // get size with 0 buffersize,
&nSize); // fills buffer size
bResult = SetupDiGetDeviceRegistryProperty(
hDevInfo, // _In_ HDEVINFO DeviceInfoSet,
&spDevInfoData, // _In_ PSP_DEVINFO_DATA DeviceInfoData
SPDRP_DEVICEDESC, // _In_ DWORD Property,
&DataT, // _Out_opt_ PDWORD PropertyRegDataType,
(PBYTE)buf, // get size with NULL (PBYTE)buffer, // _Out_opt_ PBYTE PropertyBuffer,
sizeof(buf), // get size with 0 buffersize,
&nSize); // fills buffer size
for (int iProperty = 0; iProperty != SPDRP_MAXIMUM_PROPERTY; iProperty++)
{
bResult = SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData,
iProperty /* SPDRP_DEVICEDESC*/ , &DataT, (PBYTE)buf, sizeof(buf), &nSize);
TRACE("\nBuffer Property %i %s ",iProperty, buf);
}
// get Friendly Name or Device Description
if ( SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData,
SPDRP_DEVICEDESC, &DataT, (PBYTE)buf, sizeof(buf), &nSize) ) {
TRACE("\nBuffer SPDRP_DEVICEDESC %s ",buf);
} else if ( SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData,
SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buf, sizeof(buf), &nSize) ) {
TRACE("\nBuffer SPDRP_FRIENDLYNAME %s ",buf);
} else {
lstrcpy(buf, _T("Unknown"));
}
There is one unanswered question - this function <b>SetupDiGetDeviceRegistryProperty</b>either returns description or friendly name. How am I suppose to know which one is really valid to ask for???
SetupDiGetDeviceRegistryProperty
|
|
|
|
|
Let me clean the dust from some old source folder to see if I can get a sample. (If you see I don't reply today, please ping me with another message, thanks).
Nuclear launch detected
|
|
|
|
|
Ok, I found a piece of code inside of one of my projects (I wrote it some 2 years ago, and worked at that time).
class devenum {
private:
devenum();
~devenum();
devenum(const devenum&);
devenum& operator=(const devenum&);
public:
static bool get(vector_t< pair_t< string_t<wchar_t>, string_t<wchar_t> > > & info) {
HDEVINFO hdevinfo = ::SetupDiGetClassDevs(NULL, 0, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES);
if(hdevinfo == INVALID_HANDLE_VALUE) {
return false;
}
SP_DEVINFO_DATA did = {0};
did.cbSize = sizeof(did);
for(DWORD i = 0; ::SetupDiEnumDeviceInfo(hdevinfo, i, &did); i++) {
string_t<wchar_t> desc;
if(getDescription(hdevinfo, &did, desc)) {
info += pair_t< string_t<wchar_t>, string_t<wchar_t> >(L"description", desc);
}
string_t<wchar_t> hwid;
if(getHardwareID(hdevinfo, &did, hwid)) {
info += pair_t< string_t<wchar_t>, string_t<wchar_t> >(L" hardware-id", hwid);
}
string_t<wchar_t> clas;
if(getClass(hdevinfo, &did, clas)) {
info += pair_t< string_t<wchar_t>, string_t<wchar_t> >(L" class", clas);
}
string_t<wchar_t> classGuid;
if(getClassGuid(hdevinfo, &did, classGuid)) {
info += pair_t< string_t<wchar_t>, string_t<wchar_t> >(L" class-guid", classGuid);
}
string_t<wchar_t> address;
if(getAddress(hdevinfo, &did, address)) {
info += pair_t< string_t<wchar_t>, string_t<wchar_t> >(L" address", address);
}
string_t<wchar_t> busnumber;
if(getBusNumber(hdevinfo, &did, busnumber)) {
info += pair_t< string_t<wchar_t>, string_t<wchar_t> >(L" bus-number", busnumber);
}
string_t<wchar_t> bustypeguid;
if(getBusTypeGuid(hdevinfo, &did, bustypeguid)) {
info += pair_t< string_t<wchar_t>, string_t<wchar_t> >(L" bus-type-guid", bustypeguid);
}
}
::SetupDiDestroyDeviceInfoList(hdevinfo);
return true;
}
static bool getDescription(HDEVINFO hdevinfo, SP_DEVINFO_DATA* pdid, string_t<wchar_t>& str) {
return getString(hdevinfo, pdid, SPDRP_DEVICEDESC, str);
}
static bool getHardwareID(HDEVINFO hdevinfo, SP_DEVINFO_DATA* pdid, string_t<wchar_t>& str) {
return getString(hdevinfo, pdid, SPDRP_HARDWAREID, str);
}
static bool getClass(HDEVINFO hdevinfo, SP_DEVINFO_DATA* pdid, string_t<wchar_t>& str) {
return getString(hdevinfo, pdid, SPDRP_CLASS, str);
}
static bool getClassGuid(HDEVINFO hdevinfo, SP_DEVINFO_DATA* pdid, string_t<wchar_t>& str) {
return getString(hdevinfo, pdid, SPDRP_CLASSGUID, str);
}
static bool getAddress(HDEVINFO hdevinfo, SP_DEVINFO_DATA* pdid, string_t<wchar_t>& str) {
return getDWORD(hdevinfo, pdid, SPDRP_ADDRESS, str);
}
static bool getBusNumber(HDEVINFO hdevinfo, SP_DEVINFO_DATA* pdid, string_t<wchar_t>& str) {
return getDWORD(hdevinfo, pdid, SPDRP_BUSNUMBER, str);
}
static bool getBusTypeGuid(HDEVINFO hdevinfo, SP_DEVINFO_DATA* pdid, string_t<wchar_t>& str) {
return getByte(hdevinfo, pdid, SPDRP_BUSTYPEGUID, str);
}
static bool getString(HDEVINFO hdevinfo, SP_DEVINFO_DATA* pdid, DWORD propid, string_t<wchar_t>& str) {
DWORD type = 0;
DWORD bufsiz = 0;
LPWSTR pw = NULL;
bool ok = true;
do {
if(::SetupDiGetDeviceRegistryPropertyW(hdevinfo, pdid, propid,
&type, (PBYTE)pw, bufsiz, &bufsiz)) {
ok = true;
break;
}
if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
ok = true;
if(pw != NULL) {
::LocalFree(pw);
}
pw = (LPWSTR)LocalAlloc(LPTR, bufsiz * 2 + 1);
if(pw == NULL) {
break;
}
}
else {
ok = false;
break;
}
#pragma warning(disable: 4127)
} while(true);
#pragma warning(default: 4127)
if(ok) {
if(pw != NULL) {
str = pw;
}
}
else {
ok = true;
str = L"";
}
if(pw != NULL) {
::LocalFree(pw);
}
return ok;
}
static bool getDWORD(HDEVINFO hdevinfo, SP_DEVINFO_DATA* pdid, DWORD propid, string_t<wchar_t>& str) {
DWORD type = 0;
DWORD bufsiz = 0;
DWORD v = 0;
if(!::SetupDiGetDeviceRegistryPropertyW(hdevinfo, pdid, propid,
&type, (PBYTE)&v, sizeof(DWORD), &bufsiz)) {
str = L"";
return true;
}
WCHAR sz[40] = L"";
swprintf_s(sz, _countof(sz), L"0x%8.8x", v);
str = sz;
return true;
}
static bool getByte(HDEVINFO hdevinfo, SP_DEVINFO_DATA* pdid, DWORD propid, string_t<wchar_t>& str) {
DWORD type = 0;
DWORD bufsiz = 0;
LPBYTE pb = NULL;
bool ok = true;
do {
if(::SetupDiGetDeviceRegistryPropertyW(hdevinfo, pdid, propid,
&type, (PBYTE)pb, bufsiz, &bufsiz)) {
ok = true;
break;
}
if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
ok = true;
if(pb != NULL) {
::LocalFree(pb);
}
pb = (LPBYTE)LocalAlloc(LPTR, bufsiz * 2);
if(pb == NULL) {
break;
}
}
else {
ok = false;
break;
}
#pragma warning(disable: 4127)
} while(true);
#pragma warning(default: 4127)
if(ok) {
if(bufsiz == sizeof(GUID)) {
GUID* guid = (GUID *)pb;
WCHAR sz[40] = L"";
memset(&sz[0], 0, _countof(sz) * sizeof(WCHAR));
int rez = ::StringFromGUID2(*guid, sz, _countof(sz) - 1);
if(rez != 0) {
str = sz;
ok = true;
}
}
}
else {
ok = true;
str = L"";
}
if(pb != NULL) {
::LocalFree(pb);
}
return ok;
}
};
The string_t is a string class, but you can replace it with std::wstring (or a LPWSTR* output variable as well). Same for vector_t, pair_t - you can replace them with STL counterparts std::vector, std::pair with minimal or no changes.
The getDescription is what you are looking for, which in turn calls getString - this is the core of business.
The usage - in my project - is:
vector_t< pair_t< string_t<wchar_t>, string_t<wchar_t> > > info;
devenum::get(info);
I can post somewhere the entire project but the message form does not support attachments. Maybe I will post the entire project here as an article soon.
Regards,
Cristian
Nuclear launch detected
|
|
|
|
|
Cristian,
thanks for the code.
I may "borrow" it if you do not mind.
Am I correct that the property (string) may not be defined , hence one has to check for all possible property or just check for one of interest?
I still do not get the reason for letting the SetupDiGetDeviceRegistryProperty function get the buffer size and still return false. Seems illogical- the function did perform correctly.
|
|
|
|
|
You can use the code, sure - that's why I posted it.
A property string may or may not be defined, although I suppose to do not have description sounds odd from a vendor. SetupDiGetDeviceRegistryProperty can return FALSE, as the documentation says: SetupDiGetDeviceRegistryProperty returns the ERROR_INVALID_DATA error code if the requested property does not exist for a device or if the property data is not valid.
Nuclear launch detected
|
|
|
|
|
Hi,
I shred a file with the implementation of Peter Gutmann's algorithm in C++
but I can't shred a folder yet.
please instuct.
|
|
|
|
|
MehdiHazrati wrote: but I can't shred a folder yet. Why not? Is the code giving an error?
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous
|
|
|
|
|
The code is resposing well, but it is usefull for file shreding, it uses WriteFile() to overwrite on the file.
For shredding a folder I must search the space of the folder & iterate this procedure for all files, and about the subfolder we need a recursive code to traverse them.
Is there any better solution to wipe a folder of shred a whole drive?
Thanks.
|
|
|
|
|
You cannot 'shred' folders in this way, as they are not writable in the same way that files are.
One of these days I'm going to think of a really clever signature.
|
|
|
|
|
I thinked that the files of the folder could be deleted in this way and finally the empty folder that is not important can be deleted from the system instructions.
This idea is feasible, but the only concern is about the complexity for the huge folders with various subfolders; it is time consuming.
|
|
|
|
|
MehdiHazrati wrote: it is time consuming. That's why we write programs.
One of these days I'm going to think of a really clever signature.
|
|
|
|
|
Is there alternative solution to do this?
Specially for wiping a drive
|
|
|
|
|
MehdiHazrati wrote: Specially for wiping a drive Format it, perhaps?
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous
|
|
|
|
|