我到处寻找解决该错误的帖子,但是在每种情况下,我已经在按照他们的建议去做。

我的编译输出:


  main.obj:-1:错误:LNK2019:未解析的外部符号“ public:
  __main函数中引用的__thiscall KeyLogger ::〜KeyLogger(void)“(?? 1KeyLogger @@ QAE @ XZ)
  
  main.obj:-1:错误:LNK2019:未解析的外部符号“ public:
  __thiscall KeyLogger :: KeyLogger(void)“(?? 0KeyLogger @@ QAE @ XZ)在函数_main中引用
  
  debug \ AccipioKeyDemo.exe:-1:错误:LNK1120:2无法解析的外部


我知道这就是说我已经定义了KeyLogger构造函数和析构函数,但未实现,但实际上确实已实现了所有事情。

main.cpp

#include <QCoreApplication>
#include "keylogger.h"

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    KeyLogger k;

    return a.exec();
}


keylogger.h

#ifndef KEYLOGGER_H
#define KEYLOGGER_H

#include <Windows.h>

class KeyLogger {

public:
    KeyLogger();
    ~KeyLogger();

    void start();
    void stop();

private:
    HHOOK hook;

    LRESULT CALLBACK intercept(int code, WPARAM wparam, LPARAM lparam);
};

#endif // KEYLOGGER_H


keylogger.cpp

#include "keylogger.h"
#include <QDebug>

KeyLogger::KeyLogger() : hook(NULL) {
    hook = SetWindowsHookEx(WH_KEYBOARD_LL, intercept, NULL,0);

    if (hook == NULL) {
        qDebug() << "HOOK FAILED";
    } else {
        qDebug() << "HOOK SUCCESS";
    }
}

KeyLogger::~KeyLogger() {

}

void KeyLogger::start() {
    qDebug() << "start";
}

void KeyLogger::stop() {
    qDebug() << "stop";
}

LRESULT CALLBACK KeyLogger::intercept(int code, WPARAM wparam, LPARAM lparam) {
    qDebug() << "Key Pressed";
    return CallNextHookEx(hook, code, wparam, lparam);
}


QT Pro配置

#-------------------------------------------------
#
# Project created by QtCreator 2013-10-10T19:58:51
#
#-------------------------------------------------

QT       += core

QT       -= gui

TARGET = AccipioKeyDemo
CONFIG   += console
CONFIG   -= app_bundle

LIBS += user32.lib

TEMPLATE = app

SOURCES += main.cpp \
    keylogger.cpp

HEADERS += \
    keylogger.h

最佳答案

您的代码已损坏,因为回调方法必须是静态成员-本质上,它们必须是自由函数。由于无法将指向KeyLogger实例的指针传递给拦截回调函数,因此您的钩子必须是类成员,而不是实例成员。如果您后来忘记了自己并尝试在多个线程中实例化KeyLogger,那么用互斥锁保护钩子的想法可能并不坏。

对于您来说,KeyLogger对象是可复制的也是一个错误。在不打算复制的类上使用Q_DISABLE_COPY宏。

您可能要删除构建目录并重新构建项目,但是请记住要修复如下所示的错误,否则将无法正常工作。

下面的最小化版本(只是一个main.cpp文件)可以正常工作并编译。它演示了如何正确处理从事件队列中转储的数据:您必须在拿着互斥锁的同时将一小部分数据复制出队列,然后释放互斥锁,然后再将其转储到其他位置。

#include <QCoreApplication>
#include <QMutex>
#include <QDebug>
#include <QQueue>
#include <QDataStream>
#include <windows.h>

struct KeyLoggerEvent {
   WPARAM event;
   KBDLLHOOKSTRUCT key;
   KeyLoggerEvent(WPARAM ev, KBDLLHOOKSTRUCT k) : event(ev), key(k) {}
};
QDataStream & operator<<(QDataStream & s, const KeyLoggerEvent & kev) {
   s << kev.event
     << (quint32)kev.key.flags << (quint32)kev.key.scanCode
     << (quint32)kev.key.time << (quint32)kev.key.vkCode;
   return s;
}

class KeyLogger {
   Q_DISABLE_COPY(KeyLogger)
   static QMutex m_hookMutex;
   static HHOOK m_hook;
   static QQueue<KeyLoggerEvent> m_events;
   static LRESULT CALLBACK intercept(int code, WPARAM wparam, LPARAM lparam);
public:
   KeyLogger() {
      QMutexLocker lock(&m_hookMutex);
      Q_ASSERT(!m_hook);
      m_hook = SetWindowsHookEx(WH_KEYBOARD_LL, intercept, NULL,0);
      if (!m_hook) qDebug() << "HOOK FAILED";
      lock.unlock();
   }
   ~KeyLogger() {
      QMutexLocker lock(&m_hookMutex);
      if (m_hook) UnhookWindowsHookEx(m_hook);
      m_hook = NULL;
   }
   //! Dumps a bunch of events to the stream. Returns false if no more events remain in the
   //! log. To avoid lock contention, it keeps the queue lock for a very short amount of time.
   bool dump(QDataStream & s) {
      int batchCount = 1000;
      QQueue<KeyLoggerEvent> dumpQueue;
      QMutexLocker lock(&m_hookMutex);
      while (batchCount-- && !m_events.empty()) {
         dumpQueue.enqueue(m_events.dequeue());
      }
      bool more = !m_events.empty();
      lock.unlock();
      // The below could block for a long time, thus it works from a local copy.
      while (! dumpQueue.empty()) s << dumpQueue.dequeue();
      return more;
   }
};

QMutex KeyLogger::m_hookMutex;
HHOOK KeyLogger::m_hook = NULL;
QQueue<KeyLoggerEvent> KeyLogger::m_events;

LRESULT CALLBACK KeyLogger::intercept(int code, WPARAM wparam, LPARAM lparam) {
   qDebug() << "Key Event";
   QMutexLocker lock(&m_hookMutex);
   if (code >= 0) {
      KBDLLHOOKSTRUCT * key = reinterpret_cast<KBDLLHOOKSTRUCT*>(lparam);
      m_events.enqueue(KeyLoggerEvent(wparam, *key));
   }
   HHOOK hook = KeyLogger::m_hook;
   lock.unlock();
   return CallNextHookEx(hook, code, wparam, lparam);
}

int main(int argc, char *argv[])
{
   QCoreApplication a(argc, argv);
   KeyLogger k;
   return a.exec();
}

10-04 20:20