Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SetWinEvent on a separate Class

Tags:

c++

qt

I have a little problem with Qt , here is my code :

SessionSnatcher.h:

#ifndef SESSIONSNATCHER_H
#define SESSIONSNATCHER_H

#include <Windows.h>
#include <QThread>
#include <QtCore>
#include <QDebug>


class SessionSnatcher : public QThread
{
public:
    SessionSnatcher();
    ~SessionSnatcher();
    void run();
    void SetPID(int pid);
    void SetTID(int tid);
    int GetPID();
    int GetTID();
    HWND GetCOProductControl();

private:

    //HWND GetCOProductControl();
    void CALLBACK SessionSnatcher::handler(HWINEVENTHOOK hook , DWORD event , LONG idChild , LONG idObject , DWORD dwEventThread , DWORD dwmsEventTime);
    HWINEVENTHOOK hook;
    int PID , TID;

};

#endif // SESSIONSNATCHER_H

SessionSnatcher.cpp :

#include "sessionsnatcher.h"

SessionSnatcher::SessionSnatcher()
{

}

SessionSnatcher::~SessionSnatcher()
{
    UnhookWinEvent(hook);
}

void CALLBACK SessionSnatcher::handler(HWINEVENTHOOK hook , DWORD event , LONG idChild , LONG idObject , DWORD dwEventThread , DWORD dwmsEventTime)
{

}

void SessionSnatcher::run()
{
    hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND , EVENT_SYSTEM_FOREGROUND , NULL , &SessionSnatcher::handler , PID , TID , WINEVENT_OUTOFCONTEXT);
}



HWND SessionSnatcher::GetCOProductControl()
{
    HWND TPanel = FindWindow(L"TPanel" , NULL);
    return TPanel;
}

void SessionSnatcher::SetPID(int pid)
{
    PID = pid;
}

void SessionSnatcher::SetTID(int tid)
{
    TID = tid;
}

int SessionSnatcher::GetPID()
{
    return PID;
}

int SessionSnatcher::GetTID()
{
    return TID;
}

And now i keep getting this error :

D:\TT\sessionsnatcher.cpp:25: error: C2664: 'HWINEVENTHOOK SetWinEventHook(DWORD,DWORD,HMODULE,WINEVENTPROC,DWORD,DWORD,DWORD)' : cannot convert argument 4 from 'void (__stdcall SessionSnatcher::* )(HWINEVENTHOOK,DWORD,LONG,LONG,DWORD,DWORD)' to 'WINEVENTPROC'
There is no context in which this conversion is possible

Before this i was using "handler" instead of "&SessionSnatcher::handler" but i had a problem saying it was a member and it cant be used like that. Now i cant work it out. It worked well on Visual Studio When i tried it , all i had to do was cast like (WINEVENTPROC)handler , but i think since im using a separate class i cant do that anymore.

Any tips ?

like image 644
RedZ Avatar asked Sep 05 '26 01:09

RedZ


1 Answers

You have fallen victim to the hidden this parameter in every non-static class methods. A modern solution is to use std::bind, but that won't help you with a C-based API or a C++ API that predates C++11.

The typical solution when std::bind isn't available is a free function or static method that

  1. meets the prototype you need to supply,
  2. maps the callback to the object, and
  3. invokes the desired method on the object found in 2.

Often Win32 API calls have a pointer to a user argument you can use to make this easy: just cast the pointer to SessionSnatcher * and call the function. I don't see a user argument in WinEventProc's parameter list, so you'll have to get creative and map one of the event ids or handles WinEventProc does provide and uniquely identifies a SessionSnatcher.

Or if you only have one SessionSnatcher you can write the function to always use that one SessionSnatcher.

Here is a generic example:

#include <iostream>
#include <map>

typedef int (*funcp)(int id, int p1, int p2);
// using typedef instead of using on purpose because that's what'll be in
// the Windows API

class test
{
private:
    static std::map<int, test*> tests; // our map of id -> test objects
    int id; // this test's id. Only included for proof
public:
    test(int id):id(id)
    {
        tests[id] = this; // put in map. In the real world test for collision first
    }

    // function that will eventually be called
    int func(int p1, int p2)
    {
        (void) p1;
        (void) p2;
        std::cout << "Called func for " << id << std::endl;
        return 0;
    }

    // static method that can be called by API
    static int staticfunc(int id, int p1, int p2)
    {
        // look up object and call non-static method
        // I recommend at() instead of [] because you get a catchable exception
        // rather than a crash over null pointer if id is unknown.
        return tests.at(id)->func(p1, p2);
    }
};

// allocating storage for static map
std::map<int, test*> test::tests;

// function mocking up API. Takes a function and an identifier used by called function
int caller(funcp func,
           int id)
{
    return func(id, 100, 20); // just calls the function
}

// tester
int main(void)
{
    test a(1); // create a test
    test b(2); // create a test

    try
    {
        caller(test::staticfunc, 2); // call test 2 through API
        caller(test::staticfunc, 1); // call test 1 through API
        caller(test::staticfunc, 10); // throw exception over unknown id
    }
    catch (std::exception &e)
    {
        std::cout << "Failed call: " << e.what() << std::endl;
    }
}

Typical output:

Called func for 2
Called func for 1
Failed call: map::at

"map::at" isn't much of an exception message, but it can be converted into a useful log message. At any rate it beats a segfault with no information.

like image 112
user4581301 Avatar answered Sep 07 '26 15:09

user4581301



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!