Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Doing a QList::append while using KBDLLHOOKSTRUCT (WinAPI) results in segmentation fault. :(
QtWS25 Last Chance

Doing a QList::append while using KBDLLHOOKSTRUCT (WinAPI) results in segmentation fault. :(

Scheduled Pinned Locked Moved Unsolved General and Desktop
crashsigsegvwinapiqt 5.7
6 Posts 3 Posters 3.3k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    Thynome
    wrote on last edited by Thynome
    #1

    Hello dear Qt community,

    as a little exercise, I wanted to write a class which logs every key press made on the keyboard (No, I'm really not planning to do illegal stuff with it.). Because I didn't like Qt's way, I decided to use the WinAPI code of this guy here to catch the strokes: https://www.youtube.com/watch?v=O0C4V6JmlNw.
    But now I have a persistent crash when appending my gained information to a QList in the KeyBoardProc function. Showing it with qDebug() works though.

    This is the error I get from the debugger:

    template <typename T>
    Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &t)
    {
            if  (d->ref.isShared()) {
            Node *n = detach_helper_grow(INT_MAX, 1);
            QT_TRY {
                node_construct(n, t);
            } 
    [...]
    }
    

    (The yellow arrow of the debugger points to the fourth line (QList.h, line 577).)

    I already found out that it doesn't matter what kind of variable I'm trying to append or if I even append a constant value; it crashes when using append. Well, of course I noticed that obviously some reference is shared which isn't supposed to be shared. So instead of plain appending, I tried to make something like this

    append(QList()<<value)
    

    but that just gave me another error message:

    template <typename T>
    Q_OUTOFLINE_TEMPLATE QList<T> &QList<T>::operator+=(const QList<T> &l)
    {
        if (!l.isEmpty()) {
            if (d == &QListData::shared_null) {
                *this = l;
            }
    [...]
    }
    

    (This time, the yellow arrow of the debugger points to the fifth line (QList.h, line 938).)

    Well, to be honest I'm at the end of my knowledge of Qt. I just know that I seem to not be allowed to pass a certain reference and because I violate against this rule, shit goes down. Trying to make a deep copy via temporary saving the data in another variable doesn't work either. Well, the assignment works but the appending fucks it up lets it crash again.

    So, here's the simplified code of my class. I hope you can find a solution! Thanks

    KeyLog.h

    #ifndef KEYLOG_H
    #define KEYLOG_H
    
    #include <iostream>
    #include <QCoreApplication>
    #include <QDateTime>
    #include <QDebug>
    #include <windows.h>
    
    
    namespace WindowsAction
    {
        class KeyLog : public QObject
        {
            Q_OBJECT
    
        protected:
        //Variablen
            bool Active_;               //loggen (true) oder inaktiv sein (false)
            HHOOK hHook;                //Hook (Low-Level-Verbindung mit der Tastatur)
            QList<QDateTime> DTLog_;    //Log (DateTime)
            QList<int>  NrLog_;         //Log (Key-Nummer)
            QStringList NameLog_;       //Log (Key-Name)
    
        //Funktionen
            LRESULT CALLBACK KeyBoardProc(int nCode, WPARAM wParam, LPARAM lParam);  //Hook-Funktion
    
        public:
            KeyLog(const bool& Active=true);
            ~KeyLog();
    
            QList<QDateTime> DTLog   ()             const;
            QDateTime        DTLog   (const int& i) const;
            bool             isActive()             const;
            bool             isEmpty ()             const;
            QList<int>       NrLog   ()             const;
            int              NrLog   (const int& i) const;
            QStringList      NameLog ()             const;
            QString          NameLog (const int& i) const;
    
        signals:
            void KeyPressed (QString Name, int Nr, QDateTime DT) const;
            void KeyReleased(QString Name, int Nr, QDateTime DT) const;
            void activated()                                     const;
            void deactivated()                                   const;
    
        public slots:
            void activate();        //aktiviere loggen
            void clear();           //lösche Logs
            void deactivate();      //deaktiviere loggen
            void toggle();          //ändere log_
        };
    }
    
    #endif // KEYLOG_H
    

    KeyBoardProc.h

    #include "KeyLog.h"
    
    
    LRESULT CALLBACK WindowsAction::KeyLog::KeyBoardProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
        KBDLLHOOKSTRUCT cKey=*((KBDLLHOOKSTRUCT*)wParam);
    
        wchar_t buffer[5];
        BYTE keyboard_state[256];
    
        [...]
    
        //get key name
        char lpszName[0x100]={0};
    
        [...]
    
        GetKeyNameText(dwMsg, (LPTSTR)lpszName, 255);
    
        //try to convert the key info
        ToUnicodeEx(cKey.vkCode,
                    cKey.scanCode,
                    keyboard_state,
                    buffer,
                    4,
                    0,
                    keyboard_layout);
        buffer[4]=L'\0';
    
    
    
        qDebug()<<"key: "<<cKey.vkCode<<" "<<QString::fromUtf16((ushort*)buffer)<<" "<<QString::fromUtf16((ushort*)lpszName);
    
    //*****SHIT GOES DOWN HERE*****
        DTLog_.append(QDateTime::currentDateTime());
        NrLog_.append(QList<int>()<<cKey.vkCode);
        if(QString::fromUtf16((ushort*)buffer).isEmpty()==false) NameLog_.append(QString::fromUtf16((ushort*)buffer));
        else NameLog_.append(QString::fromUtf16((ushort*)lpszName));
    
        return CallNextHookEx(hHook, nCode, wParam, lParam);
    }
    
    //Quelle WinAPI-Zeugs: https://www.youtube.com/watch?v=O0C4V6JmlNw
    

    KeyLog.cpp

    #include "KeyLog.h"
    
    
    //public:
    WindowsAction::KeyLog::KeyLog(const bool& Active)
    {
        if(Active==true) activate();
    }
    
    WindowsAction::KeyLog::~KeyLog()
    {
        if(Active_==true) deactivate();
    }
    
    [...]
    
    //public slots
    void WindowsAction::KeyLog::activate()
    {
        hHook=SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)&KeyBoardProc, NULL, 0);
    
        if(hHook!=NULL)
        {
            Active_=true;
            emit activated();
        }
        else
        {
            Active_=false;
        }
    }
    
    [...]
    
    void WindowsAction::KeyLog::deactivate()
    {
        hHook=NULL;
    
        Active_=false;
        emit deactivated();
    }
    
    [...]
    

    That's all for now. I'm open to any suggestion and really hope this can get fixed quickly. :) Thanks again!

    Felix

    kshegunovK 1 Reply Last reply
    0
    • T Thynome

      Hello dear Qt community,

      as a little exercise, I wanted to write a class which logs every key press made on the keyboard (No, I'm really not planning to do illegal stuff with it.). Because I didn't like Qt's way, I decided to use the WinAPI code of this guy here to catch the strokes: https://www.youtube.com/watch?v=O0C4V6JmlNw.
      But now I have a persistent crash when appending my gained information to a QList in the KeyBoardProc function. Showing it with qDebug() works though.

      This is the error I get from the debugger:

      template <typename T>
      Q_OUTOFLINE_TEMPLATE void QList<T>::append(const T &t)
      {
              if  (d->ref.isShared()) {
              Node *n = detach_helper_grow(INT_MAX, 1);
              QT_TRY {
                  node_construct(n, t);
              } 
      [...]
      }
      

      (The yellow arrow of the debugger points to the fourth line (QList.h, line 577).)

      I already found out that it doesn't matter what kind of variable I'm trying to append or if I even append a constant value; it crashes when using append. Well, of course I noticed that obviously some reference is shared which isn't supposed to be shared. So instead of plain appending, I tried to make something like this

      append(QList()<<value)
      

      but that just gave me another error message:

      template <typename T>
      Q_OUTOFLINE_TEMPLATE QList<T> &QList<T>::operator+=(const QList<T> &l)
      {
          if (!l.isEmpty()) {
              if (d == &QListData::shared_null) {
                  *this = l;
              }
      [...]
      }
      

      (This time, the yellow arrow of the debugger points to the fifth line (QList.h, line 938).)

      Well, to be honest I'm at the end of my knowledge of Qt. I just know that I seem to not be allowed to pass a certain reference and because I violate against this rule, shit goes down. Trying to make a deep copy via temporary saving the data in another variable doesn't work either. Well, the assignment works but the appending fucks it up lets it crash again.

      So, here's the simplified code of my class. I hope you can find a solution! Thanks

      KeyLog.h

      #ifndef KEYLOG_H
      #define KEYLOG_H
      
      #include <iostream>
      #include <QCoreApplication>
      #include <QDateTime>
      #include <QDebug>
      #include <windows.h>
      
      
      namespace WindowsAction
      {
          class KeyLog : public QObject
          {
              Q_OBJECT
      
          protected:
          //Variablen
              bool Active_;               //loggen (true) oder inaktiv sein (false)
              HHOOK hHook;                //Hook (Low-Level-Verbindung mit der Tastatur)
              QList<QDateTime> DTLog_;    //Log (DateTime)
              QList<int>  NrLog_;         //Log (Key-Nummer)
              QStringList NameLog_;       //Log (Key-Name)
      
          //Funktionen
              LRESULT CALLBACK KeyBoardProc(int nCode, WPARAM wParam, LPARAM lParam);  //Hook-Funktion
      
          public:
              KeyLog(const bool& Active=true);
              ~KeyLog();
      
              QList<QDateTime> DTLog   ()             const;
              QDateTime        DTLog   (const int& i) const;
              bool             isActive()             const;
              bool             isEmpty ()             const;
              QList<int>       NrLog   ()             const;
              int              NrLog   (const int& i) const;
              QStringList      NameLog ()             const;
              QString          NameLog (const int& i) const;
      
          signals:
              void KeyPressed (QString Name, int Nr, QDateTime DT) const;
              void KeyReleased(QString Name, int Nr, QDateTime DT) const;
              void activated()                                     const;
              void deactivated()                                   const;
      
          public slots:
              void activate();        //aktiviere loggen
              void clear();           //lösche Logs
              void deactivate();      //deaktiviere loggen
              void toggle();          //ändere log_
          };
      }
      
      #endif // KEYLOG_H
      

      KeyBoardProc.h

      #include "KeyLog.h"
      
      
      LRESULT CALLBACK WindowsAction::KeyLog::KeyBoardProc(int nCode, WPARAM wParam, LPARAM lParam)
      {
          KBDLLHOOKSTRUCT cKey=*((KBDLLHOOKSTRUCT*)wParam);
      
          wchar_t buffer[5];
          BYTE keyboard_state[256];
      
          [...]
      
          //get key name
          char lpszName[0x100]={0};
      
          [...]
      
          GetKeyNameText(dwMsg, (LPTSTR)lpszName, 255);
      
          //try to convert the key info
          ToUnicodeEx(cKey.vkCode,
                      cKey.scanCode,
                      keyboard_state,
                      buffer,
                      4,
                      0,
                      keyboard_layout);
          buffer[4]=L'\0';
      
      
      
          qDebug()<<"key: "<<cKey.vkCode<<" "<<QString::fromUtf16((ushort*)buffer)<<" "<<QString::fromUtf16((ushort*)lpszName);
      
      //*****SHIT GOES DOWN HERE*****
          DTLog_.append(QDateTime::currentDateTime());
          NrLog_.append(QList<int>()<<cKey.vkCode);
          if(QString::fromUtf16((ushort*)buffer).isEmpty()==false) NameLog_.append(QString::fromUtf16((ushort*)buffer));
          else NameLog_.append(QString::fromUtf16((ushort*)lpszName));
      
          return CallNextHookEx(hHook, nCode, wParam, lParam);
      }
      
      //Quelle WinAPI-Zeugs: https://www.youtube.com/watch?v=O0C4V6JmlNw
      

      KeyLog.cpp

      #include "KeyLog.h"
      
      
      //public:
      WindowsAction::KeyLog::KeyLog(const bool& Active)
      {
          if(Active==true) activate();
      }
      
      WindowsAction::KeyLog::~KeyLog()
      {
          if(Active_==true) deactivate();
      }
      
      [...]
      
      //public slots
      void WindowsAction::KeyLog::activate()
      {
          hHook=SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)&KeyBoardProc, NULL, 0);
      
          if(hHook!=NULL)
          {
              Active_=true;
              emit activated();
          }
          else
          {
              Active_=false;
          }
      }
      
      [...]
      
      void WindowsAction::KeyLog::deactivate()
      {
          hHook=NULL;
      
          Active_=false;
          emit deactivated();
      }
      
      [...]
      

      That's all for now. I'm open to any suggestion and really hope this can get fixed quickly. :) Thanks again!

      Felix

      kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by
      #2

      @Thynome
      Hi,
      My "educated" guess is that you have dereferenced an invalid address. Something of the type:

      MyClass * var;
      var->method();
      

      As long as method() doesn't touch anything class-related (i.e. acts as a static function) you'll probably get away with that. Provide a stack trace ('cause that QList reference doesn't mean much) and it will (most probably) get clearer why the crash is occurring.

      Kind regards.

      Read and abide by the Qt Code of Conduct

      1 Reply Last reply
      0
      • mrjjM Offline
        mrjjM Offline
        mrjj
        Lifetime Qt Champion
        wrote on last edited by
        #3

        @Thynome said:

        hHook=SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)&KeyBoardProc, NULL, 0);

        Hi
        Im wondering if SetWindowsHookEx likes a callback that lives in a class ?

        https://msdn.microsoft.com/da-dk/library/windows/desktop/ms644990(v=vs.85).aspx
        "Type: HOOKPROC
        A pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a DLL. Otherwise, lpfn can point to a hook procedure in the code associated with the current process."

        Normally for callback its plain "c" functions/ non member or at least a static member function.

        kshegunovK 1 Reply Last reply
        2
        • mrjjM mrjj

          @Thynome said:

          hHook=SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)&KeyBoardProc, NULL, 0);

          Hi
          Im wondering if SetWindowsHookEx likes a callback that lives in a class ?

          https://msdn.microsoft.com/da-dk/library/windows/desktop/ms644990(v=vs.85).aspx
          "Type: HOOKPROC
          A pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a DLL. Otherwise, lpfn can point to a hook procedure in the code associated with the current process."

          Normally for callback its plain "c" functions/ non member or at least a static member function.

          kshegunovK Offline
          kshegunovK Offline
          kshegunov
          Moderators
          wrote on last edited by
          #4

          @mrjj
          Whaddaya know, I turned out more educated than I expected ... good catch sir, I was too lazy to actually trace the code!

          Read and abide by the Qt Code of Conduct

          1 Reply Last reply
          1
          • T Offline
            T Offline
            Thynome
            wrote on last edited by
            #5

            Thanks for your answer, @kshegunov and @mrjj.

            I moved the function outside of my class and made it a friend so I still have permission to access protected class members. But now I have the problem that I must provide the object to the function... I thought about somehow passing the this pointer to the function but couldn't figure out how. :/ Passing it via parameter is not possible due to the weird function calling and my tries with a (semi) global variable didn't work either..

            Do you have an idea? I would be very happy about any suggestion. :)

            Felix

            kshegunovK 1 Reply Last reply
            0
            • T Thynome

              Thanks for your answer, @kshegunov and @mrjj.

              I moved the function outside of my class and made it a friend so I still have permission to access protected class members. But now I have the problem that I must provide the object to the function... I thought about somehow passing the this pointer to the function but couldn't figure out how. :/ Passing it via parameter is not possible due to the weird function calling and my tries with a (semi) global variable didn't work either..

              Do you have an idea? I would be very happy about any suggestion. :)

              Felix

              kshegunovK Offline
              kshegunovK Offline
              kshegunov
              Moderators
              wrote on last edited by kshegunov
              #6

              @Thynome
              Hi,
              Well, you're stuck with C when working with the WinApi. It sucks, I know, but you need to transfer the context (the object) through a global variable. You can look here for some inspiration - WindowsCtrlDispatcher::instance is the context that's transferred to the VOID WINAPI ServiceMain(DWORD, LPTSTR *) function. I hope that helps.

              Kind regards.

              Read and abide by the Qt Code of Conduct

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved