Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.9.173] |
|
Сообщ.
#1
,
|
|
|
Есть код для работы с WMI (получение тем-ры процессора):
HRESULT GetCpuTemperature(LPLONG pTemperature) { if (pTemperature == NULL) return E_INVALIDARG; *pTemperature = -1; HRESULT ci = CoInitialize(NULL); // needs comdef.h HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); if (SUCCEEDED(hr)) { IWbemLocator* pLocator; // needs Wbemidl.h & Wbemuuid.lib hr = CoCreateInstance(CLSID_WbemAdministrativeLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)& pLocator); if (SUCCEEDED(hr)) { IWbemServices* pServices; BSTR ns = SysAllocString(L"root\\WMI"); hr = pLocator->ConnectServer(ns, NULL, NULL, NULL, 0, NULL, NULL, &pServices); pLocator->Release(); SysFreeString(ns); if (SUCCEEDED(hr)) { BSTR query = SysAllocString(L"SELECT * FROM MSAcpi_ThermalZoneTemperature"); BSTR wql = SysAllocString(L"WQL"); IEnumWbemClassObject* pEnum; hr = pServices->ExecQuery(wql, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum); SysFreeString(wql); SysFreeString(query); pServices->Release(); if (SUCCEEDED(hr)) { IWbemClassObject* pObject; ULONG returned; hr = pEnum->Next(WBEM_INFINITE, 1, &pObject, &returned); pEnum->Release(); if (SUCCEEDED(hr)) { BSTR temp = SysAllocString(L"CurrentTemperature"); VARIANT v; VariantInit(&v); hr = pObject->Get(temp, 0, &v, NULL, NULL); pObject->Release(); SysFreeString(temp); if (SUCCEEDED(hr)) { *pTemperature = V_I4(&v); } VariantClear(&v); } } } if (ci == S_OK) { CoUninitialize(); } } } return hr; } Зачем здесь нужны SysAllocString и SysFreeString ? Код и без них же работает. |
Сообщ.
#2
,
|
|
|
Сообщ.
#3
,
|
|
|
ЫукпШ, я искал, но нормального объяснения как-то не находил. Инфа про формат строки (что он предваряется размером) – интересная. Хотя не факт, что она используется, ибо вариант:
hr = pLocator->ConnectServer((BSTR)L"root\\WMI", NULL, NULL, NULL, 0, NULL, NULL, &pServices); Добавлено Хотя есть много примеров (в основном на VB), где используются обычные строки. Там (в VB) они в том же формате что ли хранятся, интересно? |
Сообщ.
#4
,
|
|
|
Цитата Jin X @ Хотя не факт, что она используется, ибо вариант: hr = pLocator->ConnectServer((BSTR)L"root\\WMI", NULL, NULL, NULL, 0, NULL, NULL, &pServices); У меня твой пример вообще никак не заработал. Но я не специалист по этому вопросу, первый раз про WMI слышу. --- Ошибка происходит тут: hr = pEnum->Next(WBEM_INFINITE, 1, &pObject, &returned); --- WBEM_E_NOT_SUPPORTED. И на домашнем компе, и на работе. |
Сообщ.
#5
,
|
|
|
Цитата Jin X @ Это потому, что сервер использует то же представление, что и твой клиент. Вот был сервер написан на VB или там Delphi, пример прекрасно бы не заработал. Да и не только, достаточно, чтоб сервер заюзал обобщённые интерфейсы для BSTR. Инфа про формат строки (что он предваряется размером) – интересная. Хотя не факт, что она используется, ибо вариант: hr = pLocator->ConnectServer((BSTR)L"root\\WMI", NULL, NULL, NULL, 0, NULL, NULL, &pServices); Добавлено Цитата Jin X @ Нет. Там скорее Дельфёвый формат. У дельфи, кстати, форматов тоже не один-единственный. Там (в VB) они в том же формате что ли хранятся, интересно? |
Сообщ.
#6
,
|
|
|
Цитата Jin X @ Зачем здесь нужны SysAllocString и SysFreeString ? Действительно, есть ещё более удобный вариант. Возьмём отрезок: BSTR ns = SysAllocString(L"root\\WMI"); hr = pLocator->ConnectServer(ns, NULL, NULL, NULL, 0, NULL, NULL, &pServices); SysFreeString(ns); и изменим его так: bstr_t ns ("root\\WMI"); hr = pLocator->ConnectServer(ns, NULL, NULL, NULL, 0, NULL, NULL, &pServices); Сильно полегчает. Если подсмотреть, что это такое: ... #define bstr_t _bstr_t ... ////////////////////////////////////////////////////////////////////////////// // // Wrapper class for BSTR // ////////////////////////////////////////////////////////////////////////////// class _bstr_t { public: // Constructors // _bstr_t() throw(); _bstr_t(const _bstr_t& s) throw(); // с любыми строками будет работать правильно: _bstr_t(const char* s) ; _bstr_t(const wchar_t* s) ; ... |
Сообщ.
#7
,
|
|
|
Цитата ЫукпШ @ Надо запускать из-под админа.У меня твой пример вообще никак не заработал. Но эту канитель BIOS должен поддерживать, там через SMBIOS работа идёт вроде, как я понимаю. Цитата Qraizer @ Если брать Delphi'овый WideString, то он, по сути, такой же, как и BSTR: 4-мя байтами ранее указателя – кол-во (DWORD) байт в строке (без учёта нуля), далее ASCIIZ-строка в Unicode. В UnicodeString (он же String в Unicode-версии Delphi, т.е. 2009+) всё то же самое, только размер не в байтах, а в символах.Нет. Там скорее Дельфёвый формат. У дельфи, кстати, форматов тоже не один-единственный. А в VB ? Добавлено Вот как даже в Delphi описано, я сейчас нашёл: TBStr = POleStr; POleStr = PWideChar; Добавлено А там просто ASCIIZ-строка в Unicode, никаких размеров нет. Странно как-то это всё. Конечно, если строку выделить через SysAllocString, то она будет в нужном формате и её можно вставить в SysFreeString, а вот если вставить обычную PWideChar-строку в метод какого-нибудь интерфейса (без её создания через SysAllocString), то синтаксически Delphi будет видеть, что всё ок и скомпилит, но по факту это будет не BSTR. Почему же POleStr не WideString? Ведь при работе с WideString используются системные функции работы с памятью (SysAllocStringLen, SysReAllocStringLen, SysFreeString) |
Сообщ.
#8
,
|
|
|
Цитата ЫукпШ @ Ништяк!bstr_t ns ("root\\WMI"); hr = pLocator->ConnectServer(ns, NULL, NULL, NULL, 0, NULL, NULL, &pServices); Даже вот так лучше: hr = pLocator->ConnectServer(bstr_t(L"root\\WMI"), NULL, NULL, NULL, 0, NULL, NULL, &pServices); |
Сообщ.
#9
,
|
|
|
Цитата Jin X @ Размер может быть по отрицательному смещению. -2 или -4. А сам поинтер указывает на собственно строку. Библиотечные функции об этом в курсе, знают об отрицательных смещениях с длиной и эффективно используют. И меняют при необходимости, подразумевая, что там есть место под длину.А там просто ASCIIZ-строка в Unicode, никаких размеров нет. Странно как-то это всё. Формально тут дело даже не в языке. Если OLE-партнёр с той стороны не будет использовать это поле, то и простой ASCIIZ- или UNICODEZ-строки будет достаточно, но ты не можешь быть уверен, что прохляет. |
Сообщ.
#10
,
|
|
|
Цитата Qraizer @ Цитата Jin X @ Размер может быть по отрицательному смещению.А там просто ASCIIZ-строка в Unicode, никаких размеров нет. Странно как-то это всё. Как это может быть - не понятно. Возможно, всё просто. BSTR - это структура. С полем для строки, а затем полем для размера. Таким образом, размер фактически может быть за хвостом строки. Если функции, использующие этот тип, достаточно интеллектуальны, они программно могут разбираться с содержимым и даже форматом строки. Т.е. отличать ASCII от UNICODE. Добавлено Цитата Jin X @ Даже вот так лучше: Продолжим фантазировать. Возможно, таких программ придётся делать много. Обернём классом переменные: IWbemLocator* pILocator ; IWbemServices* pIServices ; IEnumWbemClassObject* pIEnumObject ; IWbemClassObject* pIClassObject ; А заодно и CoInitialize/CoUninitialize. В результате молучим приблизительно это: Скрытый текст // .h - файл //--------------------------------------------------------------------------- // file MWmiTool.h 2019.12.16 //--------------------------------------------------------------------------- #ifndef __MWmiTool_H__ #define __MWmiTool_H__ //--------------------------------------------------------------------------- #define _WIN32_DCOM #include <comdef.h> #include <Wbemidl.h> #include <objbase.h> #include "TypeDebugString.h" //--------------------------------------------------------------------------- #pragma comment (lib, "OLE32.LIB") #pragma comment (lib, "Wbemuuid.lib") //--------------------------------------------------------------------------- // DbgStr::TypeDebugString(const TCHAR* pFmt,...); // DbgStr::TypeDebugString(_T("%s"), _T(__FUNCTION__)); //--------------------------------------------------------------------------- class MWmiTool { private: protected: public: HRESULT hr; IWbemLocator* pILocator ; IWbemServices* pIServices ; IEnumWbemClassObject* pIEnumObject ; IWbemClassObject* pIClassObject ; WINAPI MWmiTool (void); virtual WINAPI ~MWmiTool (void); BOOL WINAPI Free (void); void WINAPI operator=(IWbemLocator* p); WINAPI operator IWbemLocator* (); WINAPI operator IWbemLocator** (); WINAPI operator LPVOID* (); BOOL WINAPI FreeIWbemLocator(void); void WINAPI operator=(IWbemServices* p); WINAPI operator IWbemServices* (); WINAPI operator IWbemServices** (); BOOL WINAPI FreeIWbemServices(void); void WINAPI operator=(IEnumWbemClassObject* p); WINAPI operator IEnumWbemClassObject* (); WINAPI operator IEnumWbemClassObject** (); BOOL WINAPI FreeIEnumWbemClassObject(void); void WINAPI operator=(IWbemClassObject* p); WINAPI operator IWbemClassObject* (); WINAPI operator IWbemClassObject** (); BOOL WINAPI FreeIWbemClassObject(void); }; //--------------------------------------------------------------------------- #endif // .cpp файл // -------------------------------------------------------------------------- // FILE MWmiTool.cpp 2019.12.16 // -------------------------------------------------------------------------- #define _WIN32_DCOM #include "stdafx.h" #include "MWmiTool.h" //--------------------------------------------------------------------------- WINAPI MWmiTool::MWmiTool (void) : pILocator (NULL), pIServices (NULL), pIEnumObject (NULL), pIClassObject (NULL), hr (S_FALSE) { hr = ::CoInitializeEx(NULL,COINIT_MULTITHREADED); } // -------------------------------------------------------------------------- WINAPI MWmiTool::~MWmiTool (void) { Free(); } //--------------------------------------------------------------------------- BOOL WINAPI MWmiTool::Free(void) { BOOL RetC=TRUE; RetC &= FreeIWbemLocator(); RetC &= FreeIWbemServices(); RetC &= FreeIEnumWbemClassObject(); RetC &= FreeIWbemClassObject(); if(hr==S_OK) { ::CoUninitialize(); hr=S_FALSE;} // S_OK The COM library was initialized successfully on this thread. // S_FALSE The COM library is already initialized on this thread. // RPC_E_CHANGED_MODE // A previous call to CoInitializeEx specified the concurrency model for //this thread as multithread apartment (MTA). //If running Windows 2000, this could also mean that //a change from neutral-threaded apartment to single-threaded //apartment occurred return RetC; } //--------------------------------------------------------------------------- BOOL WINAPI MWmiTool::FreeIWbemLocator(void) { BOOL RetC=TRUE; if(pILocator) { pILocator->Release(); pILocator=NULL; } return RetC; } //--------------------------------------------------------------------------- void WINAPI MWmiTool::operator=(IWbemLocator* p) { FreeIWbemLocator(); pILocator=p; } //--------------------------------------------------------------------------- WINAPI MWmiTool::operator IWbemLocator* () { return pILocator; } //--------------------------------------------------------------------------- WINAPI MWmiTool::operator IWbemLocator** () { return &pILocator; } //--------------------------------------------------------------------------- WINAPI MWmiTool::operator LPVOID* () { return (LPVOID*) &pILocator; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- BOOL WINAPI MWmiTool::FreeIWbemServices(void) { BOOL RetC=TRUE; if(pIServices) { pIServices->Release(); pIServices=NULL; } return RetC; } //--------------------------------------------------------------------------- void WINAPI MWmiTool::operator=(IWbemServices* p) { FreeIWbemServices(); pIServices=p; } //--------------------------------------------------------------------------- WINAPI MWmiTool::operator IWbemServices* () { return pIServices; } //--------------------------------------------------------------------------- WINAPI MWmiTool::operator IWbemServices** () { return &pIServices; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- BOOL WINAPI MWmiTool::FreeIEnumWbemClassObject(void) { BOOL RetC=TRUE; if(pIEnumObject) { pIEnumObject->Release(); pIEnumObject=NULL; } return RetC; } //--------------------------------------------------------------------------- void WINAPI MWmiTool::operator=(IEnumWbemClassObject* p) { FreeIEnumWbemClassObject(); pIEnumObject=p; } //--------------------------------------------------------------------------- WINAPI MWmiTool::operator IEnumWbemClassObject* () { return pIEnumObject; } //--------------------------------------------------------------------------- WINAPI MWmiTool::operator IEnumWbemClassObject** () { return &pIEnumObject; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- BOOL WINAPI MWmiTool::FreeIWbemClassObject(void) { BOOL RetC=TRUE; if(pIClassObject) { pIClassObject->Release(); pIClassObject=NULL; } return RetC; } //--------------------------------------------------------------------------- void WINAPI MWmiTool::operator=(IWbemClassObject* p) { FreeIWbemClassObject(); pIClassObject=p; } //--------------------------------------------------------------------------- WINAPI MWmiTool::operator IWbemClassObject* () { return pIClassObject; } //--------------------------------------------------------------------------- WINAPI MWmiTool::operator IWbemClassObject** () { return &pIClassObject; } //--------------------------------------------------------------------------- Это позволит переписать твою процедуру приблизительно так: Скрытый текст // -------------------------------------------------------------------------- // если плохо - break int GetCpuTemperature(LPLONG pTemperature) { int RetC=-1; MWmiTool wT; for(int ii=0;ii==0;++ii,RetC=0) { if(pTemperature == NULL) break; *pTemperature = -1; HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); if(FAILED(hr)) {RetC=-2;break;} hr = ::CoCreateInstance(CLSID_WbemAdministrativeLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, wT); if(FAILED(hr)) {RetC=-3;break;} bstr_t ns (_T("root\\WMI")); hr = wT.pILocator->ConnectServer(ns, NULL, NULL, NULL, 0, NULL, NULL, wT); if(FAILED(hr)) {RetC=-4;break;} bstr_t query (_T("Select * from MSAcpi_ThermalZoneTemperature")); bstr_t wql (_T("WQL")); hr = wT.pIServices->ExecQuery(wql, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, wT); if(FAILED(hr)) {RetC=-5;break;} ULONG returned=0; hr = wT.pIEnumObject->Next(WBEM_INFINITE, 1, wT, &returned); if(FAILED(hr)) { RetC=-6; break; } bstr_t temp (_T("CurrentTemperature")); VARIANT v; VariantInit(&v); hr = wT.pIClassObject->Get(temp, 0, &v, NULL, NULL); if(FAILED(hr)) {RetC=-7;break;} *pTemperature = V_I4(&v); VariantClear(&v); } return RetC; } |
Сообщ.
#11
,
|
|
|
Цитата Qraizer @ Нет. В WideString и UnicodeString есть, а PWideChar – это просто указатель.Размер может быть по отрицательному смещению. Даже если написать var X: TBSTR; ... X := WideString('Hello'); всё равно будет просто Unicode-строка и Z в конце. Цитата Qraizer @ Вот именно.но ты не можешь быть уверен, что прохляет. Цитата ЫукпШ @ В BSTR (и WideString, UnicodeString) именно так, в -4. Только в UnicodeString кол-во символов, а не размер.Как это может быть - не понятно. И там везде Unicode. Ты ж сам ссылку с поиска прислал (вторую) Цитата ЫукпШ @ Наоборот усложнил код Продолжим фантазировать. Цитата ЫукпШ @ do { ... } while(false); ? for(int ii=0;ii==0;++ii,RetC=0) |
Сообщ.
#12
,
|
|
|
Цитата Jin X @ Цитата ЫукпШ @ Наоборот усложнил код Продолжим фантазировать. Как это ? Наоборот, убрал все и разнообразные Cleanup-ы в разных точках выхода из процедуры. Сделал их один раз и навсегда. Вот пример из MSDN - понятно, что это только пример. Но делать так в реальной программе очень не удобно: Скрытый текст #define _WIN32_DCOM #include <iostream> using namespace std; #include <comdef.h> #include <Wbemidl.h> # pragma comment(lib, "wbemuuid.lib") int main(int argc, char **argv) { HRESULT hres; // Step 1: -------------------------------------------------- // Initialize COM. ------------------------------------------ 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 ------------------------ hres = CoInitializeSecurity( NULL, -1, // COM authentication NULL, // Authentication services NULL, // Reserved RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation NULL, // Authentication info EOAC_NONE, // Additional capabilities NULL // Reserved ); if (FAILED(hres)) { cout << "Failed to initialize security. Error code = 0x" << hex << hres << endl; CoUninitialize(); return 1; // Program has failed. } // Step 3: --------------------------------------------------- // Obtain the initial locator to WMI ------------------------- IWbemLocator *pLoc = NULL; hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc); 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 Win32_OperatingSystem"), 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; while (pEnumerator) { HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); if(0 == uReturn) { break; } VARIANT vtProp; // Get the value of the Name property hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); wcout << " OS Name : " << vtProp.bstrVal << endl; VariantClear(&vtProp); pclsObj->Release(); } // Cleanup // ======== pSvc->Release(); pLoc->Release(); pEnumerator->Release(); pclsObj->Release(); CoUninitialize(); return 0; // Program successfully completed. } Убираем "под капот" и забываем навсегда об этих мероприятиях. ----- bstr_t делает нечто похожее со строками - только своё, специфичное. Он тоже следит за правильностью получения/возвращения ресурсов, что удобно и надёжно. |
Сообщ.
#13
,
|
|
|
Цитата ЫукпШ @ Проще – это если не учитывать MWmiTool.h или если работу с WMI не разово нужно делать Наоборот, убрал все и разнообразные Cleanup-ы |
Сообщ.
#14
,
|
|
|
Цитата Jin X @ Цитата ЫукпШ @ Проще – это если не учитывать MWmiTool.h или если работу с WMI не разово нужно делать Наоборот, убрал все и разнообразные Cleanup-ы Не совсем так. Будущее вообще не известно, что потребуется не понятно. --- Нужда в подобных классах, сделанных по одному образцу, в принципе много. Поскольку программирование для такой системы как Виндус, содержит множество разнообразно потребляемых ресурсов. Первое что приходит в голову: Handle, socket, hmodule, hobject. SC_HANDLE, HWINSTA. Много ещё, лень лазить по исходникам. "Мало ли в Бразилии Педров - и не сосчитаешь !" (с) А вот ещё: HCRYPTHASH, HCRYPTKEY, HCRYPTPROV, HCERTSTORE. --- MWmiTool.h - Это не затраты, это практически copy/paste. |