I made an actual attempt to fix Windows support, and while I didn't get it working and probably can't, I think I made some useful progress.
Here is a summary of what I did. Unless noted otherwise the changes were made to dfinstancewindows.cpp
* I removed a stray include of non-existent memorysegment.h
* Wide strings were used in several places, even though the API functions it uses use regular strings. I changed those to regular strings.
* There were a handful of incorrect types (such as const uint instead of VIRTADDR) and missing casts.
* I redefined PID from int to DWORD in dfinstance.h
* enumWindowsProc was completely broken - I think it had never been finished. I fixed it. This fixed finding DwarfFortress.exe and determining its PID.
* I made DFInstanceWindows::get_last_error static to help with the above. I don't think it makes any difference to anything else. It looks to me like it could and maybe should be a free function, but I didn't want to make bigger changes than necessary.
* DFInstanceWindows::calculate_checksum generates checksums from the .exe timestamp, and it was confused by 64-bit timestamps in 64-bit executables, creating checksums padded with 32 bits worth of zeros (e.g. 0x00000000abcdefab instead of 0xabcdefab) which falsely tested as not equal to normal checksums. I adjusted it to skip the zeros. It would probably be better to fix the presentation and comparison logic for checksums but I couldn't figure it out.
* I added error logging to memory reads. A debugging aid, but I see no reason not to include it.
The current state is that DT builds, launches, connects to DF, picks the correct memory map, but disconnects immediately after that after a memory read fails. I'm afraid I am not able to take this any further. Hopefully this is of some use.
Diff:
diff --git a/src/dfinstance.h b/src/dfinstance.h
index 0b79825..acc36cd 100644
--- a/src/dfinstance.h
+++ b/src/dfinstance.h
@@ -31,7 +31,8 @@ THE SOFTWARE.
#include <QPointer>
#ifdef Q_OS_WIN
-typedef int PID;
+#include <windows.h>
+typedef DWORD PID;
#else
#include <unistd.h>
typedef pid_t PID;
diff --git a/src/dfinstancewindows.cpp b/src/dfinstancewindows.cpp
index dda65f6..071e91c 100644
--- a/src/dfinstancewindows.cpp
+++ b/src/dfinstancewindows.cpp
@@ -36,7 +36,6 @@ THE SOFTWARE.
#include "utils.h"
#include "gamedatareader.h"
#include "memorylayout.h"
-#include "memorysegment.h"
#include "dwarftherapist.h"
DFInstanceWindows::DFInstanceWindows(QObject* parent)
@@ -50,13 +49,13 @@ DFInstanceWindows::~DFInstanceWindows() {
}
QString DFInstanceWindows::get_last_error() {
- LPWSTR bufPtr = NULL;
+ LPSTR bufPtr = NULL;
DWORD err = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, err, 0, (LPWSTR)&bufPtr, 0, NULL);
- const QString result = bufPtr ? QString::fromWCharArray(bufPtr).trimmed()
+ NULL, err, 0, bufPtr, 0, NULL);
+ const QString result = bufPtr ? bufPtr
: QString("Unknown Error %1").arg(err);
LocalFree(bufPtr);
return result;
@@ -65,10 +64,10 @@ QString DFInstanceWindows::get_last_error() {
QString DFInstanceWindows::calculate_checksum(const IMAGE_NT_HEADERS &pe_header) {
time_t compile_timestamp = pe_header.FileHeader.TimeDateStamp;
LOGI << "Target EXE was compiled at " << QDateTime::fromTime_t(compile_timestamp).toString(Qt::ISODate);
- return hexify(compile_timestamp).toLower();
+ return QString("0x") + hexify(compile_timestamp).toLower().right(8);
}
-QString DFInstanceWindows::read_string(const uint &addr) {
+QString DFInstanceWindows::read_string(VIRTADDR addr) {
USIZE len = read_int(addr + memory_layout()->string_length_offset());
USIZE cap = read_int(addr + memory_layout()->string_cap_offset());
VIRTADDR buffer_addr = addr + memory_layout()->string_buffer_offset();
@@ -122,8 +121,12 @@ USIZE DFInstanceWindows::read_raw(VIRTADDR addr, USIZE bytes,
void *buffer) {
ZeroMemory(buffer, bytes);
USIZE bytes_read = 0;
- ReadProcessMemory(m_proc, reinterpret_cast<LPCVOID>(addr), buffer,
- bytes, reinterpret_cast<SIZE_T*>(&bytes_read));
+ if(!ReadProcessMemory(m_proc, reinterpret_cast<LPCVOID>(addr), buffer,
+ bytes, reinterpret_cast<SIZE_T*>(&bytes_read)))
+ {
+ LOGE << "Memory read failed: " << get_last_error();
+ }
+
return bytes_read;
}
@@ -138,42 +141,42 @@ USIZE DFInstanceWindows::write_raw(VIRTADDR addr, USIZE bytes, const void *buffe
static const QSet<QString> df_window_classes{"OpenGL", "SDL_app"};
-BOOL CALLBACK static enumWindowsProc(HWND hWnd, LPARAM lParam) {
+BOOL CALLBACK enumWindowsProc(HWND hWnd, LPARAM lParam) {
auto pids = reinterpret_cast<QSet<PID> *>(lParam);
- WCHAR classNameW[8];
- if (!GetClassName(hWnd, classNameW, sizeof(classNameW))) {
- LOGE << "GetClassName failed:" << get_last_error();
+ CHAR className[8];
+ if (!GetClassName(hWnd, className, sizeof(className))) {
+ LOGE << "GetClassName failed: " << DFInstanceWindows::get_last_error();
return false;
}
- if (!className && wcscmp(className, L"OpenGL") && wcscmp(className, L"SDL_app"))
+ if (!className && strcmp(className, "OpenGL") && strcmp(className, "SDL_app"))
return true;
- WCHAR windowName[16];
- if (!GetWindowName(hWnd, windowName, sizeof(windowName))) {
- LOGE << "GetWindowName failed:" << get_last_error();
- return false;
- }
+ CHAR windowName[16] = {0};
+ GetWindowText(hWnd, windowName, sizeof(windowName));
Q_ASSERT(windowName);
- if (wcscmp(windowName, L"Dwarf Fortress"))
+ if (strcmp(windowName, "Dwarf Fortress"))
return true;
+ PID pid;
+
GetWindowThreadProcessId(hWnd, &pid);
if (!pid) {
LOGE << "could not get PID for hwnd";
return false;
}
- pids << pid;
+ *pids << pid;
return true;
+
}
bool DFInstanceWindows::set_pid(){
QSet<PID> pids;
- if (!EnumWindows(enumWindowsProc, &pids)) {
+ if (!EnumWindows(enumWindowsProc, (LPARAM)&pids)) {
LOGE << "error enumerating windows";
return false;
}
@@ -191,7 +194,7 @@ bool DFInstanceWindows::set_pid(){
return false;
do {
- if (!_tcscmp(&pe32.szExeFile, _T("Dwarf Fortress.exe")))
+ if (!strcmp(pe32.szExeFile, "Dwarf Fortress.exe"))
pids << pe32.th32ProcessID;
} while (Process32Next(snapshot, &pe32));
@@ -235,7 +238,7 @@ void DFInstanceWindows::find_running_copy() {
LOGE << "Error enumerating modules!" << get_last_error();
return;
} else {
- VIRTADDR base_addr = me32.modBaseAddr;
+ VIRTADDR base_addr = (VIRTADDR)me32.modBaseAddr;
IMAGE_DOS_HEADER dos_header;
read_raw(base_addr, sizeof(dos_header), &dos_header);
if(dos_header.e_magic != IMAGE_DOS_SIGNATURE){
diff --git a/src/dfinstancewindows.h b/src/dfinstancewindows.h
index eb74dc6..2fad948 100644
--- a/src/dfinstancewindows.h
+++ b/src/dfinstancewindows.h
@@ -39,7 +39,7 @@ public:
void find_running_copy();
bool df_running();
- QString get_last_error();
+ static QString get_last_error();
USIZE read_raw(VIRTADDR addr, USIZE bytes, void *buffer);
QString read_string(VIRTADDR addr);
@@ -61,4 +61,6 @@ protected:
bool set_pid();
};
+
+
#endif // DFINSTANCE_H