From: Wan-Hi on
originated in the java corner, i have some difficulties to adapt the
programming style used in the platform sdk and the ddk. therefore i'd like to
know what you think about the way i handled some things.

1) device interface GUIDs not defined in a global header:
i tried to find the GUID of disc type devices which are part of the mass
storage device group. because i didn't find any, i looked up the GUID value
stored in my registry and defined it in my app. is this a bad habit or can i
assume that this GUID never changes in further versions of ms win?

2) error checking:
SetupDiGetClassDevs and many other functions return a specific value if they
fail. so should i check for failure although such case is impossible? e.g.
SetupDiGetClassDevs with GUID_DEVINTERFACE_VOLUME should never fail. i ask
because useless failure checks make the code unreadable.
From: Don Burn on
Comments inline:

"Wan-Hi" <WanHi(a)discussions.microsoft.com> wrote in message
news:2647E6F7-D684-47A9-B75D-10E7A9407F55(a)microsoft.com...
> originated in the java corner, i have some difficulties to adapt the
> programming style used in the platform sdk and the ddk. therefore i'd like
> to
> know what you think about the way i handled some things.
>
> 1) device interface GUIDs not defined in a global header:
> i tried to find the GUID of disc type devices which are part of the mass
> storage device group. because i didn't find any, i looked up the GUID
> value
> stored in my registry and defined it in my app. is this a bad habit or can
> i
> assume that this GUID never changes in further versions of ms win?

Device Interface GUID's are defined in header files, search for DEFINE_GUID
in the DDK and you will find them all defined.


> 2) error checking:
> SetupDiGetClassDevs and many other functions return a specific value if
> they
> fail. so should i check for failure although such case is impossible? e.g.
> SetupDiGetClassDevs with GUID_DEVINTERFACE_VOLUME should never fail. i ask
> because useless failure checks make the code unreadable.

Never assume that an error can't occur, this will just lead to a bug in the
future. While the current documentation is pretty good for the SDK and DDK,
I still have encountered errors that are not defined in docs. Normally,
these are events that are rare, but at least handling the error (if nothing
else check for it and exit if failure displaying the error code.

What do you mean that failure checks make the code unreadable, show us an
example of what you consider unreadable, and I suspect the group will have a
number of suggestions in coding style that will make things clearer (since
everyones style is different, choose something that works for you).


--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply



From: Wan-Hi on
here are two examples. the first one checks for possible failures:

HDEVINFO hVolInfoSet;
HDEVINFO hDiscInfoSet

// Retrieving the device info set of currently installed
// devices exposing the volume interface.
hVolInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME,
NULL,
NULL,
DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (hVolInfoSet == INVALID_HANDLE_VALUE)
{
ShowErrorMessage(GetLastError());
return false;
}


// Retrieving the device info set of currently installed
devices registered as part of the disc type setup class.
hDiscInfoSet = SetupDiGetClassDevs(&GUID_DEVCLASS_DISKDRIVE,
NULL,
NULL,
DIGCF_PRESENT);
if (hDiscInfoSet == INVALID_HANDLE_VALUE)
{
ShowErrorMessage(GetLastError());
SetupDiDestroyDeviceInfoList(hVolInfoSet);
return false;
}

....

// Iterating through all volumes.
for (DWORD i = 0; ; i++)
{

// Retrieving the interface data of the next entry in the
// device info set of all volumes.
if (SetupDiEnumDeviceInterfaces(hVolInfoSet,
NULL,
&GUID_DEVINTERFACE_VOLUME,
i,
&volInterfaceData) == 0)
{
errorCode = GetLastError();
if (errorCode == ERROR_NO_MORE_ITEMS)
break;
else
{
ShowErrorMessage(errorCode);
continue;
}
}
...
}
....

I think this is very over-secure code because volumes and disc type devices
should always be present. therefore no failure should happen.

the second example leaves out failure checks because a condition is
fulfilled which should make it impossible to fail further API calls:

....
// Examing the device node in the device tree.
ULONG devNodeDepth;
if (CM_Get_Depth(&devNodeDepth, volDevInfoData.DevInst, 0) != CR_SUCCESS)
{
free(pVolDetailData);
ShowErrorMessage(GetLastError());
continue;
}

if (devNodeDepth >= 2)
{
///////////////////////////////////////////////////////
// 1) RETRIEVING DEVICE INSTANCE IDs
DEVINST hDiscClassInst;
DEVINST hUsbClassInst;
ULONG volIdSize;
ULONG discIdSize;
ULONG usbIdSize;
TCHAR *volId;
TCHAR *discId;
TCHAR *usbId;

// Getting the handles of the device interface's parent and
// grandparent.
CM_Get_Parent(&hDiscClassInst, volDevInfoData.DevInst, NULL);
CM_Get_Parent(&hUsbClassInst, hDiscClassInst, NULL);

// Determing memory requirements for the device IDs and
// allocating the required space.
CM_Get_Device_ID_Size(&volIdSize, volDevInfoData.DevInst, 0);
CM_Get_Device_ID_Size(&discIdSize, hDiscClassInst, 0);
CM_Get_Device_ID_Size(&usbIdSize, hUsbClassInst, 0);
volId = (TCHAR*)malloc((volIdSize + 1) * sizeof(TCHAR));
discId = (TCHAR*)malloc((discIdSize + 1) * sizeof(TCHAR));
usbId = (TCHAR*)malloc((usbIdSize + 1) * sizeof(TCHAR));

// Getting the device IDs.
CM_Get_Device_ID(volDevInfoData.DevInst, volId, volIdSize, 0);
CM_Get_Device_ID(hDiscClassInst, discId, discIdSize, 0);
CM_Get_Device_ID(hUsbClassInst, usbId, usbIdSize, 0);
...
(freeing allocated mem)
}
....

I skipped failure checks on CM_Get_Parent because the depth of the device
node tells that the device instance definitely has an sufficient 'amount' of
elders. assuming that CM_Get_Parent wont fail i also skip failure checks on
CM_Get_Device_ID_Size and CM_Get_Device_ID because every device instance must
have a unique ID associated.

by these two examples i tried to explain what kind of programming style i
exercise. i try to check for failures if i haven't have enough information to
assume a successful function call. otherwise, if i have enough information
because i checked specific conditions, i leave the checks out.

is this adequate or unsave?

wan-hi

"Don Burn" wrote:

> Never assume that an error can't occur, this will just lead to a bug in the
> future. While the current documentation is pretty good for the SDK and DDK,
> I still have encountered errors that are not defined in docs. Normally,
> these are events that are rare, but at least handling the error (if nothing
> else check for it and exit if failure displaying the error code.
>
> What do you mean that failure checks make the code unreadable, show us an
> example of what you consider unreadable, and I suspect the group will have a
> number of suggestions in coding style that will make things clearer (since
> everyones style is different, choose something that works for you).
From: Robert Marquardt on
Wan-Hi wrote:

> 2) error checking:
> SetupDiGetClassDevs and many other functions return a specific value if they
> fail. so should i check for failure although such case is impossible? e.g.
> SetupDiGetClassDevs with GUID_DEVINTERFACE_VOLUME should never fail. i ask
> because useless failure checks make the code unreadable.

The error checks only make the code unreadable because MS prefers a
*really* bad style. Excessive return and goto is about as bad as it can
get. A clean if else style and a proper indentation solves that.
From: David J. Craig on
Here is a freebie for those trying to do error checking and avoiding goto's.

K&R say the only legal 'DO ONCE' is done using the for command.

for( ; ; )
{
break; // If OE or ??? warps this, it should be four lines
with this line indented.
}

You can then do tests and do a 'continue' or a 'break' as needed to exit or
restart the loop. You will forget the terminating break especially when
beginning, but it is legal and works. You can add a __finally to handle
terminating cleanup, but I just usually initialize all locals and return
variables before the 'for' block. Then a test and the appropriate cleanup
can be done to free memory, close handles, etc. after exiting the block or
before returning.

If you can't code it clean and easy to follow, you need to go back to school
or find something other than a programming job. No one will live forever,
much less stay in the same job, so be nice to those who follow and write
maintainable code. You can add comments to the 'for' loop to tell anyone
looking that this is a 'do once' block and not to get confused.

"Robert Marquardt" <marquardt(a)codemercs.com> wrote in message
news:%23TSRLUaZFHA.3732(a)TK2MSFTNGP10.phx.gbl...
> Wan-Hi wrote:
>
>> 2) error checking:
>> SetupDiGetClassDevs and many other functions return a specific value if
>> they fail. so should i check for failure although such case is
>> impossible? e.g. SetupDiGetClassDevs with GUID_DEVINTERFACE_VOLUME should
>> never fail. i ask because useless failure checks make the code
>> unreadable.
>
> The error checks only make the code unreadable because MS prefers a
> *really* bad style. Excessive return and goto is about as bad as it can
> get. A clean if else style and a proper indentation solves that.