Given a device instance ID for a network card, I would like to know its MAC address. Example device instance ID on my system for integrated Intel Gigabit card:
PCI\VEN_8086&DEV_10CC&SUBSYS_00008086&REV_00\3&33FD14CA&0&C8
So far, the algorithm I have used works as follows:
- Call 
SetupDiGetClassDevswithDIGCF_DEVICEINTERFACE. - Call 
SetupDiEnumDeviceInfoto get the returned device in aSP_DEVINFO_DATA. - Call 
SetupDiEnumDeviceInterfaceswithGUID_NDIS_LAN_CLASSto get a device interface. - Call 
SetupDiGetDeviceInterfaceDetailfor this returned device interface. This gets us the device path as a string:\\?\pci#ven_8086&dev_10cc&subsys_00008086&rev_00#3&33fd14ca&0&c8#{ad498944-762f-11d0-8dcb-00c04fc3358c}\{28fd5409-15bd-4c06-b62f-004d3a06f852} - At this point we have an address to the network card driver's interface.  Open it with 
CreateFileusing the result from #4. - Call 
DeviceIoControlwithIOCTL_NDIS_QUERY_GLOBAL_STATSand OID ofOID_802_3_PERMANENT_ADDRESSto get the MAC address. 
This usually works, and has been used successfully on quite a large number of machines.  However, it appears that a very select few machines have network drivers that aren't responding properly to the DeviceIoControl request in step #6; the problem persists even after updating network card drivers to the latest.  These are newer, Windows 7-based computers.  Specifically, DeviceIoControl completes successfully, but returns zero bytes instead of the expected six bytes containing the MAC address.
A clue seems to be on the MSDN page for IOCTL_NDIS_QUERY_GLOBAL_STATS:
This IOCTL will be deprecated in later operating system releases. You should use WMI interfaces to query miniport driver information. For more information see, NDIS Support for WMI.
-- perhaps newer network card drivers are no longer implementing this IOCTL?
So, how should I get this working? Is it possible there's an oversight in my approach and I'm doing something slightly wrong? Or do I need to take a much more different approach? Some alternate approaches seem to include:
- Query 
Win32_NetworkAdapterWMI class: provides needed information but rejected due to horrible performance. See Fast replacement for Win32_NetworkAdapter WMI class for getting MAC address of local computer - Query 
MSNdis_EthernetPermanentAddressWMI class: appears to be the WMI replacement forIOCTL_NDIS_QUERY_GLOBAL_STATSand queries the OID directly from the driver - and this one works on the troublesome network driver. Unfortunately, the returned class instances only provide the MAC address and theInstanceName, which is a localized string likeIntel(R) 82567LM-2 Gigabit Network Connection. QueryingMSNdis_EnumerateAdapteryields a list which relates theInstanceNameto aDeviceName, like\DEVICE\{28FD5409-15BD-4C06-B62F-004D3A06F852}. I'm not sure how to go from theDeviceNameto the plug-and-play device instance ID (PCI\VEN_8086......). - Call 
GetAdaptersAddressesorGetAdaptersInfo(deprecated). The only non-localized identifier I can find in the return value is the adapter name, which is a string like{28FD5409-15BD-4C06-B62F-004D3A06F852}- same as theDeviceNamereturned by the WMI NDIS classes. So again, I can't figure out how to relate it to the device instance ID. I'm not sure if it would work 100% of the time either - e.g. for adapters without TCP/IP protocol configured. - NetBIOS method: requires specific protocols to be set up on the card so won't work 100% of time. Generally seems hack-ish, and not a way to relate to device instance ID anyway that I know of. I'd reject this approach.
 - UUID generation method: rejected for reasons I won't elaborate on here.
 
It seems like if I could find a way to get the "GUID" for the card from the device instance ID, I'd be well on my way with one of the remaining two ways of doing things. But I haven't figured out how yet. Otherwise, the WMI NDIS approach would seem most promising.
Getting a list of network cards and MAC addresses is easy, and there are several ways of doing it. Doing it in a fast way that lets me relate it to the device instance ID is apparently hard...
EDIT: Sample code of the IOCTL call if it helps anyone (ignore the leaked hFile handle):
HANDLE hFile = CreateFile(dosDevice.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
    DWORD err = GetLastError();
    wcout << "GetMACAddress: CreateFile on " << dosDevice << " failed." << endl;
    return MACAddress();
}
BYTE address[6];
DWORD oid = OID_802_3_PERMANENT_ADDRESS, returned = 0;
//this fails too: DWORD oid = OID_802_3_CURRENT_ADDRESS, returned = 0;
if (!DeviceIoControl(hFile, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof(oid), address, 6, &returned, NULL)) {
    DWORD err = GetLastError();
    wcout << "GetMACAddress: DeviceIoControl on " << dosDevice << " failed." << endl;
    return MACAddress();
}
if (returned != 6) {
    wcout << "GetMACAddress: invalid address length of " << returned << "." << endl;
    return MACAddress();
}
The code fails, printing:
GetMACAddress: invalid address length of 0.
So the DeviceIoControl returns non-zero indicating success, but then returns zero bytes.