QT + WinApi, Callback function return bad pointer address
-
Hello. I'm writing a program on QT (5.14.2), to work with Windows I had to use WinAPI, namely the function of notification of changes in the status of the service - NotifyServiceStatusChangeA
Faced with the following problem:
In function NotifyServiceStatusChangeA I transfer as parameter pNotifyBuffer where in pNotifyBuffer.pContext the pointer this (on current class) is established. The mechanism is such that the callback function onStatusChanged (PVOID p) as an argument returns a pointer void * p, this pointer should point to the area of memory that was written in pNotifyBuffer as pContext, but in QT it is not! The pointer p indicates an area of memory other than the transmitted one. This can be seen in the console (after running program below):Service man opened
pcontext address 0x113fb34
void * p address 0x113fb50That is, when you try to convert the pointer void * to the type MainWindow * and call any member of the class - there will be an exception Exception at 0x5085466c, code: 0xc0000005: read access violation at: 0x4, flags = 0x0 (first chance)
I checked the function in Visual Studio - there are no such problems without QT.
I'm stuck on this problem, I don't want to learn WinAPI to write the interface, and I don't know of any other way to work with Windows services other than WinAPI. Thanks in advance for the help!Below a code of simple program what demonstrate a problem:
pro file:
QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 DEFINES += QT_DEPRECATED_WARNINGS SOURCES += \ main.cpp \ mainwindow.cpp HEADERS += \ mainwindow.h FORMS += \ mainwindow.ui qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target win32: LIBS += -lAdvAPI32
MainWindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <Windows.h> #include <winsvc.h> #include <QDebug> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); QString m_test_string = "look it"; SERVICE_NOTIFY_2A pNotifyBuffer; SC_HANDLE service_man; SC_HANDLE service; static void CALLBACK onStatusChanged(PVOID p); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); service_man = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS); //open service manager handler if(service_man == NULL) { qDebug() << "Error open service`s manager, code" << GetLastError(); throw "Error open service`s manager"; } qDebug() << "Service man opened"; service = OpenServiceA(service_man, "bthserv", SERVICE_ALL_ACCESS); //open service bthserv handler pNotifyBuffer.pContext = this; //set the pointer to the current object qDebug() << "pcontext address" << pNotifyBuffer.pContext; pNotifyBuffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; pNotifyBuffer.pfnNotifyCallback = &onStatusChanged; //set the callback function. NotifyServiceStatusChangeA(service, SERVICE_NOTIFY_STOPPED, &pNotifyBuffer); //run notify function and subscribe to notify when service is stopped } MainWindow::~MainWindow() { delete ui; } void MainWindow::onStatusChanged(PVOID p) { qDebug() << "void *p address" << p; MainWindow* ptr_mainWindow = static_cast<MainWindow*>(p); qDebug() << ptr_mainWindow->m_test_string; }
main.cpp
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
-
Hi, welcome to the forum.
From the docs: "The callback function receives a pointer to the SERVICE_NOTIFY structure provided by the caller."
So you should rather cast that pointer toSERVICE_NOTIFY_2A*
and then cast itspContext
member toMainWindow*
. -
@Chris-Kawa
wow, so simple :)
and so fast answer!! woooow
Thank you very much!
Its works!void MainWindow::onStatusChanged(PVOID p) { qDebug() << "void *p address" << p; SERVICE_NOTIFY_2A* temp_pNotifyBuffer = static_cast<SERVICE_NOTIFY_2A*>(p); //MainWindow* ptr_mainWindow = static_cast<MainWindow*>(p); //qDebug() << ptr_mainWindow->m_test_string; qDebug() << temp_pNotifyBuffer->pContext; qDebug() << static_cast<MainWindow*>(temp_pNotifyBuffer->pContext)->m_test_string; }
Service man opened
pcontext address 0x8ff6a0
void *p address 0x8ff6bc
0x8ff6a0
"look it"I was misled that in Visual studio the example with "direct" transformation worked. And I went the wrong way ..