Wuapi.dll - jak wywołać metodę obiektu COM z parametrem IUnknow

0

Witam,
Borykam się z problemem wyszukania aktualizacji Windows Update. Znalazłem w necie, że można skożystać z biblioteki wuapi.dll.
Inerfejsy i procedury tej biblioteki można znaleźć tu:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa386065(v=vs.85).aspx

searcher->generateDocumentation() podpowia coś takiego:

Public Slots:
IDispatch* BeginSearch(QString criteria, IUnknown* onCompleted, QVariant state);
IDispatch* EndSearch(IDispatch* searchJob);

Member Function Documentation
IDispatch* BeginSearch (QString criteria, IUnknown* onCompleted, QVariant state) [slot]
Starts an asynchronous search using the currently configured search options. 
Connect a signal to this slot:
	QObject::connect(sender, SIGNAL(someSignal(QString, IUnknown*, QVariant)), object, SLOT(BeginSearch(QString, IUnknown*, QVariant)));
Or call the function directly:
	QVariantList params = ...
	QAxObject * result = object->querySubObject("BeginSearch(QString, IUnknown*, QVariant)", params); 

IDispatch* EndSearch (IDispatch* searchJob) [slot]
Completes an asynchronous search. 
Connect a signal to this slot:
	QObject::connect(sender, SIGNAL(someSignal(IDispatch*)), object, SLOT(EndSearch(IDispatch*)));
Or call the function directly:
	QVariantList params = ...
	QAxObject * result = object->querySubObject("EndSearch(IDispatch*)", params); 

Naskrobałem trochę kodu, ale nie mogę przekazać parametrów do QAxObjec->querySubObject(...);

W konstruktorze MainWindow tworzę obiekty QAxObject:

#include <QVariantList>
#include <QAxObject>
#include <QDebug>
#include <QUuid>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow), session(0), searcher(0)
{
    ui->setupUi(this);
    session = new QAxObject("Microsoft.Update.Session", this);
    connect(ui->actionTestuj, &QAction::triggered, [=] (bool) {
        beginSearch();
    });

Następnie chcę odpalić procedurę BeginSearch:

void MainWindow::beginSearch()
{
    searcher = session->querySubObject("CreateUpdateSearcher()");

   // ISearchCompletedCallback *colback = new ISearchCompletedCallback();

    QUuid obj("{00000000-0000-0000-C000-000000000046}");
    QVariant arg(QVariant::Uuid, &obj);
    QString prm = "isInstalled=0 and isHidden=0";
    QVariantList params;
    params.append(prm);
    params.append(colback);
    params.append(NULL);
    QAxObject *job = searcher->querySubObject("BeginSearch(QString, IUnknown*, QVariant", params);
    bool looping = false;
    int sm = QTime::currentTime().minute();
    while(!looping) {
     if(!job) {
        looping = job->property("IsCompleted").toBool();
     };
     QApplication::processEvents();
     int m = QTime::currentTime().minute();
     if ((m-sm) > 2) {
         looping = false;
     }
    }
    setWindowTitle("Gotowe");
}

I teraz dwa problemy:

  1. Jak zaimplementować parametr IUnknown* w BeginSearch(...), który powinien być typu: ISearchCompletedCallback
  2. QVariantList nie przyjmuje mi zmiennej obj, gdy jest typu QAxObject lub QUuid.

Kod który prezentuję jest totalnie skopany, ale w akcie desperacji próbowałem co mi do głowy przyjdzie.
Ma ktoś może pomysł, jak to rozwiązać?
Bardzo dziękuję za pomoc.
Pozdrawiam.

0

Nie znam Qt, ale chyba coś w ten deseń:

params.append( QAxObject(colback).asVariant() );
0

Dzięki za odpowiedź.
Jak pisałem wcześniej, nabadziałem wkodzie. Rozwiązanie Uuid nie ma sensu.
Parametrem przekazywanym w miejsce IUnknow* musi być klasa (chyba QAxObject) definiująca ISearchCompletedCallback z wuapi.h.
Teraz mam problem, jak stworzyć taką klasę, aby ...->querySubObject(BeginSearch(...)) to łyknęło.
Próbowałem tak:

#ifndef CALLBACKCLASS_H
#define CALLBACKCLASS_H
#include <QAxObject>
#include <wuapi.h>
class CallBackClass : public QAxObject , ISearchCompletedCallback
{
    Q_OBJECT
public:
    explicit CallBackClass(QObject *parent = 0);

signals:

public slots:
    int invoke(QAxObject *job, QAxObject *args);
};
#endif // CALLBACKCLASS_H

W .cpp:

#include "callbackclass.h"

CallBackClass::CallBackClass(QObject *parent) : QAxObject(parent)
{

}

int CallBackClass::invoke(QAxObject *job, QAxObject *args)
{
  return 0;
}

ale nie łyka: krzyczy że nie może zaimplementować klasy absrakcyjnej, bla bla bla...

Zapewne trzeba tu coś zakombinować z obsługą interfejsów tej "wuapi.h", ale ja niestety nie mam pojęcia jak.
Może ktoś jeszcze ma pomysł lub wiedzę jak to poprawnie rozwiązać?
Pozdrawiam.

0

Musisz zaimplementować wszystkie metody interfejsu ISearchCompletedCallback, także te, które dziedziczy po IUnknown.

0

Ok. Dałem sobie spokój.
Rozwiązaniem jest uruchomienie w innym wątku, z wykorzystaniem Workera, jak tu:
http://doc.qt.io/qt-5/qthread.html

#include "worker.h"
#include "Windows.h"
#include <QAxObject>

Worker::Worker(QObject *parent) : QObject(parent)
{

}

void Worker::start(bool)
{
  HRESULT res =  CoInitialize(0);
    QAxObject *sch = 0, *result = 0, *updates;
    QAxObject *ses = new QAxObject("Microsoft.Update.Session");
    if(ses) {
         sch = ses->querySubObject("CreateUpdateSearcher()");
    }
    if(sch) {
     QVariantList params;
                 params<<"BrowseOnly=0 and IsInstalled=0 and Type='Software' and IsHidden=0";
      result = sch->querySubObject("Search(QString)", params);
    }
    if(result) {
      updates = result->querySubObject("Updates");
    }
    emit searchResult(updates);
    if(res == S_OK) {
      CoUninitialize();
    }
}

A MainWindow mam:

void MainWindow::onSearchResult(QAxObject *Updates)
{
    int count = Updates->property("Count").toInt();
        ui->tableWidget->setRowCount(count);
    setWindowTitle(QString("Search engine return value:= %1").arg(count));
    QMap<int, QString> prioryty;
         prioryty.insert(1, "Niska"); prioryty.insert(2, "Normalna"); prioryty.insert(3, "Wysoka");
    QAxObject *item = 0, *moreInfo = 0;

    for(int i = 0; i < count; i++){
        item = Updates->querySubObject("Item(int)", i);
        QDate date = item->dynamicCall("LastDeploymentChangeTime").toDate();
              ui->tableWidget->setItem(i, 0, new QTableWidgetItem(date.toString("dd-MM-yyyy")));
              ui->tableWidget->setItem(i, 1, new QTableWidgetItem(item->dynamicCall("Title").toString()));
        moreInfo = item->querySubObject("MoreInfoUrls");
              ui->tableWidget->setItem(i, 2, new QTableWidgetItem(moreInfo->dynamicCall("Item(int)", 0).toString()));
        moreInfo = item->querySubObject("Categories");
        QString categories = "";
          for(int j = 0; j < moreInfo->dynamicCall("Count()").toInt(); j++) {
            categories += moreInfo->querySubObject("Item(int)", j)->property("Name").toString() + " ";
          }
             ui->tableWidget->setItem(i, 3, new QTableWidgetItem(categories));
               int p = item->property("DownloadPriority").toInt();
             ui->tableWidget->setItem(i, 4, new QTableWidgetItem(prioryty.value(p, "Undefined")));
    }
    ui->tableWidget->resizeColumnsToContents();

    srchThrd->quit();
    srchThrd->wait();
}

Tearz rzuca mi ostrzeżeniami, po powrocie do głównego wątku aplikacji:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QAxObject(0x319d840), parent's thread is QThread(0x3166aa0), current thread is QThread(0x4fb8c0)
QAxBase: Unhandled type DECIMAL
QAxBase: Unhandled type DECIMAL
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QAxObject(0x319d840), parent's thread is QThread(0x3166aa0), current thread is QThread(0x4fb8c0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QAxObject(0x319d840), parent's thread is QThread(0x3166aa0), current thread is QThread(0x4fb8c0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QAxObject(0x319d840), parent's thread is QThread(0x3166aa0), current thread is QThread(0x4fb8c0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QAxObject(0x319d840), parent's thread is QThread(0x3166aa0), current thread is QThread(0x4fb8c0)

Czy to znaczy, że źle jest to zaprogramowane, wycieki pamięci lub inne zagrożenia?
Proszę o wasz komentaż.
Dzięki za odpowiedzi.
Pozdrawiam.

0

Przecież masz napisane, co jest błędem: Cannot create children for a parent that is in a different thread. Zgaduje, że chodzi o obiekt Updates, który tworzy jakiegoś "potomka" w innym wątku niż ten, w którym został stworzony.

 item = Updates->querySubObject("Item(int)", i);

Może to?

1 użytkowników online, w tym zalogowanych: 0, gości: 1