Я просмотрел сообщения, пытающиеся решить эту ошибку, но в каждом случае я уже делаю то, что они предложили.
Мой результат компиляции:
main.obj: -1: ошибка: LNK2019: неразрешенный внешний символ "public: __thiscall KeyLogger :: ~ KeyLogger (void)" (?? 1KeyLogger @@QAE @XZ), на который ссылается функция _main
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();
}
Вы получаете ошибку связи, где компоновщик не может найти файл obj с конструктором и деструктором. Это означает, что keylogger.cpp либо не скомпилирован, либо линкер не может найти свой obj файл. Проверьте настройки своего проекта.