Re: Cannot Use GUID in map
"Hendrik Schober" <SpamTrap@gmx.de> wrote in message
news:ufkDYCizIHA.5716@TK2MSFTNGP04.phx.gbl...
Giovanni Dicanio <giovanni.dicanio@invalid.com> wrote:
"David Wilkinson" <no-reply@effisols.com> ha scritto nel messaggio
news:uRtQ2LhzIHA.5892@TK2MSFTNGP02.phx.gbl...
Igor Tandetnik wrote:
Map keys have to be comparable. By default, map tries to use built-in
less-than (<) operator, but that doesn't work with GUIDs. You need to
define your own comparator, and pass it as the third template
parameter.
Igor:
You can define operator <() for GUID's, no?
GUIDs are just arrays of bytes... so I think one could define an
operator<
considering byte-by-byte comparison (kind of char[] comparison,
char-by-char, like done in strcmp). Maybe it could be possible to convert
GUID to ANSI string and just use operator< for ANSI string (or strcmp).
I'm curious if there are better ways.
What about 'memcmp()'?
Giovanni
Schobi
--
SpamTrap@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
A small reservation. memcmp "assumes" there is nothing hidden in the data
structure. You're "assuming" things about packing. They might be different
on a different platform by which time you have moved on and some poor
maintenance programmer is stuck with the problem. Better is to define an
operator< (if a meaningful one can be defined) or convert to strings and
compare (and having operators to convert to/from strings is useful anyway.
/////////Include file
class GuidC
{
public:
GuidC(GUID &aGuid);
GuidC(TCHAR *sGuid);
//
// Count the instances of a device defined by GUID.
//
bool Count(unsigned &nDevices)const;
//
// Open an instance of a device defined by GUID.
//
bool Open(const DWORD InterfaceNumber, HANDLE &hDevice)const;
friend ostream& operator<<(ostream &os, const GuidC &v);
private:
GUID m_Guid;
LoggerC m_Logger;
};
//
// Output a readable representation of a GUID.
// {b61b0040-50d2-11dd-ae16-0800200c9a66}
//
ostream& operator<<(ostream &os, const GUID &v);
//
// Input a readable represetation of a GUID.
// {b61b0040-50d2-11dd-ae16-0800200c9a66} or
b61b0040-50d2-11dd-ae16-0800200c9a66
//
istream & operator>>(istream &Stream, GUID &aGuid);
///////////// cpp file
#include "stdafx.h"
#pragma comment(lib,"setupapi.lib")
GuidC::GuidC(GUID &aGuid):
m_Guid(aGuid), m_Logger(TheLogger)
{
}
GuidC::GuidC(TCHAR *sGuid):
m_Guid(), m_Logger(TheLogger)
{
istrstream is(sGuid);
is >> m_Guid;
ASSERT( ! is.fail() );
}
ostream& operator<<(ostream &os, const GuidC &v)
{
return os << v.m_Guid;
}
bool GuidC::Count(unsigned &nDevices)const
{
LPCGUID pGUID = &m_Guid;
HDEVINFO hwDeviceInfo = SetupDiGetClassDevs(pGUID,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if ( hwDeviceInfo == INVALID_HANDLE_VALUE )
{
const LastErrorC LastError;
LOGERROR("SetupDiGetClassDevs(" << *pGUID << ",,,): " << LastError);
return false;
}
bool Result;
for(nDevices=0;;++nDevices)
{
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
if ( ! SetupDiEnumDeviceInterfaces(hwDeviceInfo, 0, pGUID, nDevices,
&DeviceInterfaceData) )
{
const LastErrorC LastError;
if ( LastError.GetLastError() == ERROR_NO_MORE_ITEMS )
{
Result = true;
break;
}
else
{
LOGERROR("SetupDiEnumDeviceInterfaces(,," << *pGUID << ",,): " <<
LastError);
Result = false;
break;
}
}
} // Next device
(void)SetupDiDestroyDeviceInfoList(hwDeviceInfo);
return Result;
}
bool GuidC::Open(const DWORD InterfaceNumber, HANDLE &hDevice)const
{
LPCGUID pGUID = &m_Guid;
bool Success = false;
//
// Make hDevice NULL so no further action is required on an error exit.
// If CreateFile() fails, we reset it to NULL from INVALID_HANDLE_VALUE.
//
hDevice = NULL;
HDEVINFO hwDeviceInfo = SetupDiGetClassDevs(pGUID,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if ( hwDeviceInfo != INVALID_HANDLE_VALUE )
{
//
// Do not return now without calling SetupDiDestroyDeviceInfoList()
// to free a resource.
//
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
if ( SetupDiEnumDeviceInterfaces(hwDeviceInfo,0,pGUID, InterfaceNumber,
&DeviceInterfaceData) )
{
// cout << "SetupDiEnumDeviceInterfaces() worked\n";
ULONG requiredLength = 0;
(void)SetupDiGetDeviceInterfaceDetail( hwDeviceInfo,
&DeviceInterfaceData,
NULL,
0,
&requiredLength,
NULL);
const ULONG predictedLength = requiredLength;
assert(predictedLength >= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) );
UCHAR *pRawAllocation = new UCHAR[predictedLength];
if ( pRawAllocation )
{
SP_DEVICE_INTERFACE_DETAIL_DATA &DeviceInterfaceDetailData =
*(PSP_INTERFACE_DEVICE_DETAIL_DATA)pRawAllocation;//lint !e826 : pointer
size is OK
DeviceInterfaceDetailData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SP_DEVINFO_DATA devInfoData;
devInfoData.cbSize = sizeof(devInfoData);
if ( SetupDiGetDeviceInterfaceDetail( hwDeviceInfo,
&DeviceInterfaceData,
&DeviceInterfaceDetailData,
predictedLength,
&requiredLength,
&devInfoData))
{
// cout << "SetupDiGetInterfaceDeviceDetail() worked\n";
hDevice = CreateFile(DeviceInterfaceDetailData.DevicePath,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if ( hDevice == INVALID_HANDLE_VALUE )
{
const DWORD LastError = GetLastError();
LOGERROR("CreateFile(" << DeviceInterfaceDetailData.DevicePath << "): " <<
LastError);
hDevice = NULL; // We use NULL to indicate an invalid handle.
}
else
{
//
// "Do not attempt to parse the device path symbolic name"
//
LOGINFO("Opened: " << DeviceInterfaceDetailData.DevicePath);
Success = true;
}
}
else
{
const LastErrorC LastError;
LOGERROR("SetupDiGetInterfaceDeviceDetail(): " << LastError);
}
delete [] pRawAllocation;
}
else
{
LOGERROR("Insufficient memory (wanted " << MemorySizeC(predictedLength) << "
bytes)");
}
}
else
{
const LastErrorC LastError;
if ( LastError.GetLastError() == ERROR_NO_MORE_ITEMS )
LOGERROR("Interface number " << InterfaceNumber << " does not exist")
else
LOGERROR("SetupDiEnumDeviceInterfaces():" << LastError);
}
(void)SetupDiDestroyDeviceInfoList(hwDeviceInfo);
}
else
{
const LastErrorC LastError;
cerr << "SetupDiGetClassDevs():" << LastError << endl;
}
return Success;
}
ostream& operator<<(ostream &os, const GUID &v)
{
IoSaverC IoSaver(os);
//
// {f618a337-2b7a-4115-aeaf-578a16a66677}
//
os << hex << noshowbase
<< '{' << v.Data1
<< '-' << v.Data2
<< '-' << v.Data3
<< '-' ;
for(size_t i=0;i<ENTRIES(v.Data4);++i)
{
if ( i == 2 )
os << '-';
os << setw(2) << setfill('0') << (unsigned)v.Data4[i];
}
return os << '}';
}
istream & operator>>(istream &Stream, GUID &aGuid)
{
//
// Extract GUID in either of the forms:
// {e0317cca-bb7c-4e2a-9f28-a698e60ede99} or
// e0317cca-bb7c-4e2a-9f28-a698e60ede99
//
IoSaverC SaveAndRestoreStreamState(Stream);
//
// Set this when an error occurs. Inhibits assignment to aGuid and
// causes an error bit to be set in the stream.
//
bool Error = false;
//
// We read into this temporary, making the assigment to the user only if we
// are successful.
//
GUID Guid;
if ( Stream.peek() == _T('{') )
{
TCHAR c;
Stream >> c; // Loose the opening brace.
if ( _istxdigit(Stream.peek()) )
{
//
// Recursive call to deal with the rest.
//
Stream >> Guid;
if ( Stream.peek() == _T('}') )
{
Stream >> c; // Loose the closing brace.
}
else
{
Error = true;
}
}
else
Error = true;
}
else
{
TCHAR c0, c1, c2;
const TCHAR Dash = _T('-');
Stream >> Guid.Data1 >> c0 >> Guid.Data2 >> c1 >> Guid.Data3 >> c2;
if ( (c0 != Dash) || (c1 != Dash) || (c2 != Dash) ) Error = true;
for(unsigned i=0;i<ENTRIES(Guid.Data4) && !Error;++i)
{
if ( i==2 )
{
//
// e0317cca-bb7c-4e2a-9f28-a698e60ede99
// We are here:-----------^
//
Stream >> c0;
if ( c0!= Dash ) Error = true;
}
Stream >> c0 >> c1;
if ( ! _istxdigit(c0) || ! _istxdigit(c1) )
Error = true;
else
Guid.Data4[i] = HexToBin(c0,c1);
}
}
if ( Error || Stream.fail() )
(void)Stream.setf(ios::failbit);
else
{
//lint -esym(644, Guid) : Guid is initialised here
aGuid = Guid;
}
return Stream;
}