port remaining windows backend from qtmobility.
[qt:qtsystems.git] / src / systeminfo / windows / qwmihelper_win.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtSensors module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #ifndef Q_CC_MINGW
42 #define _WIN32_DCOM
43
44 #include "qwmihelper_win_p.h"
45
46 #include <QDebug>
47 #include <ObjBase.h>
48 #include <Wbemidl.h>
49 #include <Oleauto.h>
50 #include <QStringList>
51 #include <QUuid>
52 #include <comutil.h>
53
54 QT_BEGIN_NAMESPACE
55
56 Q_GLOBAL_STATIC(WMIHelper, wmihelper)
57
58 WMIHelper::WMIHelper(QObject * parent)
59         : QObject(parent),initialized(0)
60 {
61    m_conditional = QString();
62 }
63
64 WMIHelper::~WMIHelper()
65 {
66     CoUninitialize();
67 }
68
69 WMIHelper *WMIHelper::instance()
70 {
71     return wmihelper();
72 }
73
74 QVariant WMIHelper::getWMIData()
75 {
76 //    qDebug() << Q_FUNC_INFO << m_wmiNamespace << m_className << m_classProperties;
77
78    if (!m_wmiNamespace.isEmpty() && !m_className.isEmpty() && !m_classProperties.isEmpty()) {
79       return getWMIData(m_wmiNamespace, m_className, m_classProperties);
80    }
81    return QVariant();
82 }
83
84 void WMIHelper::initializeWMI(const QString &wmiNamespace)
85 {
86     if (initialized) {
87         wbemLocator = 0;
88     }
89     HRESULT hres;
90     wbemLocator = 0;
91
92     QUuid wbemLocatorClsid = "4590f811-1d3a-11d0-891f-00aa004b2e24";
93     QUuid wbemLocatorIid = "dc12a687-737f-11cf-884d-00aa004b2e24";
94
95     hres = CoCreateInstance(wbemLocatorClsid,0,CLSCTX_INPROC_SERVER,
96                             wbemLocatorIid, (LPVOID *) &wbemLocator);
97
98     if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
99         CoInitializeEx(0, COINIT_MULTITHREADED);
100         hres = CoCreateInstance(wbemLocatorClsid,0,CLSCTX_INPROC_SERVER,
101                                 wbemLocatorIid, (LPVOID *) &wbemLocator);
102     }
103
104     if (hres != S_OK) {
105        qWarning() << "Failed to create IWbemLocator object." << hres;
106         return ;
107     }
108     wbemServices = 0;
109      const OLECHAR *ole = reinterpret_cast<const OLECHAR *>(wmiNamespace.utf16());
110     hres = wbemLocator->ConnectServer(::SysAllocString(ole),0,0,0,0,0,0,&wbemServices);
111
112     if (hres != WBEM_S_NO_ERROR){
113         qWarning() << "Could not connect";
114         return ;
115     }
116
117     hres = CoSetProxyBlanket( wbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, 0,
118                               RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, 0, EOAC_NONE );
119
120     if (hres != S_OK) {
121        qWarning() << "Could not set proxy blanket" << hres;
122         return ;
123     }
124     initialized = true;
125 }
126
127 QVariant WMIHelper::getWMIData(const QString &wmiNamespace, const QString &className, const QStringList &classProperty)
128 {
129     initializeWMI(wmiNamespace);
130     HRESULT hres;
131     QVariant returnVariant;
132
133       wbemEnumerator = 0;
134
135     if (!m_conditional.isEmpty()) {
136         if (m_conditional.left(1).compare(QLatin1String(" "))) {
137             m_conditional = QLatin1String(" ") + m_conditional;
138         }
139     }
140
141     QString aString = "SELECT * FROM " + className + m_conditional;
142     BSTR bstrQuery;
143     const OLECHAR *oleStr = reinterpret_cast<const OLECHAR *>(aString.utf16());
144
145     bstrQuery = ::SysAllocString(oleStr);
146
147     hres = wbemServices->ExecQuery(L"WQL", bstrQuery,
148             WBEM_FLAG_BIDIRECTIONAL | WBEM_FLAG_RETURN_IMMEDIATELY,0,&wbemEnumerator);
149
150     if (hres != WBEM_S_NO_ERROR){
151         qWarning() << "WMI Query failed.";
152         wbemLocator->Release();
153         wbemEnumerator->Release();
154         return returnVariant;
155     }
156
157     ::SysFreeString(bstrQuery);
158
159     wbemCLassObject = 0;
160     ULONG result = 0;
161
162     wmiVariantList.clear();
163     while (wbemEnumerator) {
164         HRESULT hr = wbemEnumerator->Next(WBEM_INFINITE, 1,&wbemCLassObject, &result);
165         if (0 == result){
166             break;
167         }
168
169         foreach (const QString property, classProperty) {
170             VARIANT msVariant;
171             CIMTYPE variantType;
172             hr = wbemCLassObject->Get(reinterpret_cast<const wchar_t *>(property.utf16()), 0, &msVariant, &variantType, 0);
173             returnVariant = msVariantToQVariant(msVariant, variantType);
174             wmiVariantList << returnVariant;
175
176             VariantClear(&msVariant);
177
178         }
179
180         wbemCLassObject->Release();
181     }
182
183     wbemEnumerator->Release();
184     wbemLocator->Release();
185     wbemServices->Release();
186     return returnVariant;
187 }
188
189 QVariant WMIHelper::msVariantToQVariant(VARIANT msVariant, CIMTYPE variantType)
190 {
191     QVariant returnVariant;
192     switch (variantType) {
193     case CIM_STRING:
194     case CIM_CHAR16:
195         {
196             QString str((QChar*)msVariant.bstrVal, wcslen(msVariant.bstrVal));
197             QVariant vs(str);
198             returnVariant = vs;
199         }
200         break;
201     case CIM_BOOLEAN:
202         {
203             QVariant vb(msVariant.boolVal);
204             returnVariant = vb;
205         }
206         break;
207     case CIM_UINT8:
208         {
209             QVariant vb(msVariant.uintVal);
210             returnVariant = vb;
211         }
212         break;
213     case CIM_UINT16:
214         {
215             QVariant vb(msVariant.uintVal);
216             returnVariant = vb;
217         }
218     case CIM_UINT32:
219         {
220             QVariant vb(msVariant.uintVal);
221             returnVariant = vb;
222         }
223         break;
224     case CIM_UINT64:
225         {
226             QVariant vb(msVariant.uintVal);
227             returnVariant = vb;
228         }
229         break;
230     };
231     VariantClear(&msVariant);
232     return returnVariant;
233 }
234
235   void WMIHelper::setWmiNamespace(const QString &wmiNamespace)
236 {
237    m_wmiNamespace = wmiNamespace;
238 }
239
240    void WMIHelper::setClassName(const QString &className)
241 {
242    m_className = className;
243 }
244
245 void WMIHelper::setClassProperty(const QStringList &classProperties)
246 {
247    m_classProperties = classProperties;
248 }
249
250 void WMIHelper::setConditional(const QString &conditional)
251 {
252    m_conditional = conditional;
253 }
254
255 void WMIHelper::setupNotfication(const QString &wmiNamespace,const QString &className, const QStringList &/*classProperties*/)
256 {
257     initializeWMI(wmiNamespace);
258     HRESULT hres;
259
260     IUnsecuredApartment* pUnsecApp = NULL;
261
262     QUuid clsidUnsecuredApartment = "49bd2028-1523-11d1-ad79-00c04fd8fdff";
263     QUuid iidUnsecuredApartment = "1cfaba8c-1523-11d1-ad79-00c04fd8fdff";
264
265      hres = CoCreateInstance(clsidUnsecuredApartment, NULL,
266          CLSCTX_LOCAL_SERVER,iidUnsecuredApartment,
267          (void**)&pUnsecApp);
268
269      if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
270          qDebug() << "not initialized";
271          CoInitializeEx(0, COINIT_MULTITHREADED);
272          hres = CoCreateInstance(clsidUnsecuredApartment,0,CLSCTX_INPROC_SERVER,
273                                  iidUnsecuredApartment, (LPVOID *) &pUnsecApp);
274      }
275
276      if (hres != S_OK) {
277         qDebug() << "Failed to create IWbemLocator object." << hres;
278          return ;
279      }
280
281      EventSink* pSink = new EventSink;
282
283      pSink->AddRef();
284
285      IUnknown* pStubUnk = NULL;
286      pUnsecApp->CreateObjectStub(pSink, &pStubUnk);
287
288      IWbemObjectSink* pStubSink = NULL;
289      QUuid iidWbemObjectSink = "7c857801-7381-11cf-884d-00aa004b2e24";
290
291      pStubUnk->QueryInterface(iidWbemObjectSink,(void **) &pStubSink);
292
293      QString aString = className;//"SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE (TargetInstance ISA 'Win32_LogicalDisk') AND (TargetInstance.DriveType = 5 OR TargetInstance.DriveType = 2)";
294
295      BSTR bstrQuery;
296
297      const OLECHAR *oleStr = reinterpret_cast<const OLECHAR *>(aString.utf16());
298
299      bstrQuery = ::SysAllocString(oleStr);
300
301      hres = wbemServices->ExecNotificationQueryAsync(
302          L"WQL",
303          bstrQuery,
304          WBEM_FLAG_SEND_STATUS,
305          NULL,
306          pStubSink);
307
308      if (FAILED(hres)) {
309          printf("ExecNotificationQueryAsync failed "
310              "with = 0x%X\n", hres);
311          wbemLocator->Release();
312          wbemEnumerator->Release();
313          pUnsecApp->Release();
314          pStubUnk->Release();
315          pSink->Release();
316          pStubSink->Release();
317          CoUninitialize();
318          return;
319      }
320 }
321
322 void WMIHelper::emitNotificationArrived()
323 {
324     emit wminotificationArrived();
325 }
326
327 ULONG EventSink::AddRef()
328 {
329     return InterlockedIncrement(&m_lRef);
330 }
331
332 ULONG EventSink::Release()
333 {
334     LONG lRef = InterlockedDecrement(&m_lRef);
335     if (lRef == 0)
336         delete this;
337     return lRef;
338 }
339
340 HRESULT EventSink::QueryInterface(REFIID riid, void** ppv)
341 {
342     QUuid iidWbemObjectSink = "7c857801-7381-11cf-884d-00aa004b2e24";
343
344     if (riid == IID_IUnknown || riid == iidWbemObjectSink){
345         *ppv = (IWbemObjectSink *) this;
346         AddRef();
347         return WBEM_S_NO_ERROR;
348     }
349     else return E_NOINTERFACE;
350 }
351
352
353 HRESULT EventSink::Indicate(long lObjectCount,
354     IWbemClassObject ** /*apObjArray*/)
355 {
356     for (int i = 0; i < lObjectCount; i++){
357         WMIHelper::instance()->emitNotificationArrived();
358
359 //        _variant_t msVariant;
360 //        CIMTYPE variantType;
361 //        QVariant returnVariant;
362 //        IWbemClassObject *obj = apObjArray[0];
363
364 //        HRESULT hr = obj->Get(L"TargetInstance", 0, &msVariant, 0, 0);
365 //        if (hr == S_OK) {
366 //            IUnknown *str = msVariant;
367 //            VariantClear(&msVariant);
368
369 //            IWbemClassObject *obj;
370 //            hr = str->QueryInterface(IID_IWbemClassObject, reinterpret_cast<void **>(&obj));
371 //            if (hr == S_OK) {
372 //                _variant_t var2;
373 //                hr = obj->Get(L"__Class", 0, &var2, 0, 0);
374 //                _bstr_t classname = var2;
375 //                VariantClear(&var2);
376 //                if (classname == _bstr_t(L"Win32_LogicalDisk")) {
377 //                    _variant_t var3;
378 //       //             qDebug() << obj->Availability;
379 //                    hr = obj->Get(L"Availability", 0, &var3, &variantType, 0);
380 //                    if (hr == S_OK) {
381 //                        //uint av = var3;
382 //                        //returnVariant = WMIHelper::msVariantToQVariant(msVariant, variantType);
383
384 //                        printf("variant type: 0x%X\n", variantType);
385
386 // //                       int value = var3.intVal;
387
388 //                       qDebug() <<"Availability" << var3.uintVal << var3.vt << var3.uiVal << var3.iVal;
389 //                        //var3.uintVal;//<<returnVariant << returnVariant.toUInt();
390 //                        VariantClear(&var3);
391 //                    } else {
392 //                        qDebug() << hr << GetLastError();
393 //                        printf("Error foo. hr = 0x%X\n", hr);
394
395 //                    }
396 //                } else {
397 //                    qDebug() << hr << GetLastError();
398 //                    printf("Error 2. hr = 0x%X\n", hr);
399
400 //                }
401 //            }
402 //        } else {
403 //            qDebug() << hr << GetLastError();
404 //            printf("Error. hResult = 0x%X\n", hr);
405 //        }
406     }
407
408     return WBEM_S_NO_ERROR;
409 }
410
411 HRESULT EventSink::SetStatus(
412            LONG lFlags,
413            HRESULT hResult,
414            BSTR /*strParam*/,
415            IWbemClassObject __RPC_FAR * /*pObjParam*/)
416 {
417     if (lFlags == WBEM_STATUS_COMPLETE) {
418         printf("Call complete. hResult = 0x%X\n", hResult);
419     } else if (lFlags == WBEM_STATUS_PROGRESS) {
420         printf("Call in progress.\n");
421     }
422
423     return WBEM_S_NO_ERROR;
424 }    // end of EventSink.cpp
425
426 #include "moc_qwmihelper_win_p.cpp"
427
428 QT_END_NAMESPACE
429 #endif