Reputation: 1765
I have looked around for posts trying to solve this error but in every case I am already doing what they have suggested.
My compile output:
main.obj:-1: error: LNK2019: unresolved external symbol "public: __thiscall KeyLogger::~KeyLogger(void)" (??1KeyLogger@@QAE@XZ) referenced in function _main
main.obj:-1: error: LNK2019: unresolved external symbol "public: __thiscall KeyLogger::KeyLogger(void)" (??0KeyLogger@@QAE@XZ) referenced in function _main
debug\AccipioKeyDemo.exe:-1: error: LNK1120: 2 unresolved externals
I know that this is saying that I have the KeyLogger constructor and destructor defined but not implemented but I actually do have everything implemented.
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 config
#-------------------------------------------------
#
# 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
Upvotes: 0
Views: 2214
Reputation: 98505
Your code is broken because callback methods must be static members - essentially they have to be free functions. Since there's no way to pass the pointer to KeyLogger
instance to the intercepting callback function, your hook must be a class member, not instance member. It's perhaps not that bad of an idea to protect the hook with a mutex, in case you later forgot yourself and tried to instantiate KeyLogger
s in multiple threads.
It's also an error, in your case, for the KeyLogger
object to be copyable. Use Q_DISABLE_COPY
macro on classes that are not meant to be copied.
You may want to delete the build directory and build your project again, but please remember to fix the bugs as shown below or it won't work.
The minimized version below (just a main.cpp
file) works and compiles just fine. It demonstrates how to properly handle dumping data from the event queue: you must copy a small chunk of the data out of the queue while holding the mutex, then release the mutex and only then dump it elsewhere.
#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();
}
Upvotes: 2
Reputation: 1246
You're getting the linkage error, where the linker cannot find an obj file with constructor and destructor. That means keylogger.cpp is either not compiled or linker cannot find its obj file. Check the settings of your project.
Upvotes: 0