Подскажите, пожалуйста, как через WIN32 API(или вообще хотя бы как-нибудь) определить серийные номера всех устройств в машине (ИМЕННО ЖЕЛЕЗОК). Я шел двумя путями:
1) Через WMI. Пробовал получить экзмпляры всех классов WMI, производных от CIM_PhysicalElement, но почему-то кроме материнки ни у каких остальных device'ов серийных номеров обнаружено не было (хотя должны были там быть). Вот код:
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
// Note: If you are using Windows 2000, you need to specify —
// the default authentication credentials for a user by using
// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
// parameter of CoInitializeSecurity ------------------------
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (e.g. Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl; pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x"
<< hex << hres << endl; pSvc->Release(); pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM CIM_Phisical"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
cout << "Query for operating system name failed."
<< " Error code = 0x"
<< hex << hres << endl; pSvc->Release(); pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
IWbemClassObject *pclsObj;
ULONG uReturn = 0;
INT i = 0;
2) Через непосредственно WINAPI. Но результатом было только GetLastError = ERROR_INVALID_FUNCTION (Incorrect function) после вызова функции DeviceIoControl. Вот главный кусок кода:
Здравствуйте, vanes, Вы писали:
V>2) Через непосредственно WINAPI. Но результатом было только GetLastError = ERROR_INVALID_FUNCTION (Incorrect function) после вызова функции DeviceIoControl. Вот главный кусок кода:
V>VOID EnumerateExistingDevices(const GUID* guid) V>{ V> HDEVINFO info = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); V> SP_INTERFACE_DEVICE_DATA ifdata; V> ifdata.cbSize = sizeof(ifdata); V> DWORD devindex; V> for (devindex = 0; SetupDiEnumDeviceInterfaces(info, NULL, guid, devindex, &ifdata); ++devindex) V> { V> DWORD needed; V> SetupDiGetDeviceInterfaceDetail(info, &ifdata, NULL, 0, &needed, NULL); V> PSP_INTERFACE_DEVICE_DETAIL_DATA detail = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc(needed); V> detail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); V> SP_DEVINFO_DATA devdata = {sizeof(SP_DEVINFO_DATA)}; V> SetupDiGetDeviceInterfaceDetail(info, &ifdata, detail, needed, NULL, &devdata); V> CString devname = detail->DevicePath; V> HANDLE hDevice = CreateFile (devname, V> GENERIC_READ, // no access to the drive V> FILE_SHARE_READ // share mode V> , V> NULL, // default security attributes V> OPEN_EXISTING, // disposition V> 0, // file attributes V> NULL); // do not copy file attributes
V> if(hDevice != INVALID_HANDLE_VALUE) V> { V> CHANGER_PRODUCT_DATA * product = new CHANGER_PRODUCT_DATA; V> DWORD dwReturn = 0; V> DWORD dwError = GetLastError(); V> OVERLAPPED aOverlapped; V> BOOL bOk =DeviceIoControl ((HANDLE)hDevice, IOCTL_CHANGER_GET_PRODUCT_DATA, NULL, 0, product, V> sizeof(CHANGER_PRODUCT_DATA), &dwReturn, &aOverlapped); V> dwError = GetLastError(); V> if(bOk) V> { V> cout << "SerialNumber: " << product->SerialNumber << "n"; V> } V> else V> { V> cout << "Error: " << GetLastError() << "n"; V> } V> delete product; V> CloseHandle(hDevice); V> }
V> free((PVOID) detail); V> } V> }
V>Очень прошу при возможности привести РАБОТОСПОСОБНЫЙ код в ответе, если можно.
Насколько я понял вы делаете enumerate всех устройств, а запрос им отсылаете, как будто все они FILE_DEVICE_CHANGER. Так нельзя, это специфический запрос. Вам надо либо различать устройства и каждому посылать специфический запрос, либо попробовать вытащить serial number из Device Instance ID который можно получить с помощью функции
CM_Get_Device_ID(devdata.DevInst, strData, sizeof(data), 0);
Но не всегда там присутствует уникальный серийник, а только в том случае если железка имеет этот самый серийник, это можно проверить с помощью