|
|
@ -1,8 +1,12 @@
|
|
|
|
#include <process.h>
|
|
|
|
#include <process.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
#include <TlHelp32.h>
|
|
|
|
#include "steam_api.h"
|
|
|
|
#include "steam_api.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
|
|
const uint32 DFHACK_STEAM_APPID = 2346660;
|
|
|
|
const uint32 DFHACK_STEAM_APPID = 2346660;
|
|
|
|
|
|
|
|
const uint32 DF_STEAM_APPID = 975370;
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL is_running_on_wine() {
|
|
|
|
static BOOL is_running_on_wine() {
|
|
|
|
typedef const char* (CDECL wine_get_version)(void);
|
|
|
|
typedef const char* (CDECL wine_get_version)(void);
|
|
|
@ -32,7 +36,7 @@ static LPCWSTR launch_via_steam_windows() {
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
ZeroMemory(&pi, sizeof(pi));
|
|
|
|
ZeroMemory(&pi, sizeof(pi));
|
|
|
|
|
|
|
|
|
|
|
|
WCHAR steamPath[1024];
|
|
|
|
WCHAR steamPath[1024] = L"";
|
|
|
|
DWORD datasize = 1024;
|
|
|
|
DWORD datasize = 1024;
|
|
|
|
|
|
|
|
|
|
|
|
LONG retCode = RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam",
|
|
|
|
LONG retCode = RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam",
|
|
|
@ -43,16 +47,24 @@ static LPCWSTR launch_via_steam_windows() {
|
|
|
|
|
|
|
|
|
|
|
|
WCHAR commandLine[1024] = L"steam.exe -applaunch 975370";
|
|
|
|
WCHAR commandLine[1024] = L"steam.exe -applaunch 975370";
|
|
|
|
|
|
|
|
|
|
|
|
if (CreateProcessW(steamPath, commandLine,
|
|
|
|
BOOL res = CreateProcessW(steamPath, commandLine,
|
|
|
|
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0)
|
|
|
|
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
|
|
|
|
return L"Could not launch Dwarf Fortress";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (res)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CloseHandle(pi.hProcess);
|
|
|
|
|
|
|
|
CloseHandle(pi.hThread);
|
|
|
|
return NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return L"Could not launch Dwarf Fortress";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// this method doesn't properly attribute Steam playtime metrics to DF,
|
|
|
|
static LPCWSTR launch_direct() {
|
|
|
|
// but that's better than not having DF start at all.
|
|
|
|
|
|
|
|
static BOOL launch_direct() {
|
|
|
|
|
|
|
|
STARTUPINFOW si;
|
|
|
|
STARTUPINFOW si;
|
|
|
|
PROCESS_INFORMATION pi;
|
|
|
|
PROCESS_INFORMATION pi;
|
|
|
|
|
|
|
|
|
|
|
@ -60,31 +72,152 @@ static BOOL launch_direct() {
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
ZeroMemory(&pi, sizeof(pi));
|
|
|
|
ZeroMemory(&pi, sizeof(pi));
|
|
|
|
|
|
|
|
|
|
|
|
return CreateProcessW(L"Dwarf Fortress.exe",
|
|
|
|
BOOL res = CreateProcessW(L"Dwarf Fortress.exe",
|
|
|
|
NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
|
|
|
|
NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (res)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CloseHandle(pi.hProcess);
|
|
|
|
|
|
|
|
CloseHandle(pi.hThread);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return L"Could not launch via non-steam fallback method";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DWORD findDwarfFortressProcess()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
PROCESSENTRY32W entry;
|
|
|
|
|
|
|
|
entry.dwSize = sizeof(PROCESSENTRY32W);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!Process32FirstW(snapshot, &entry))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
CloseHandle(snapshot);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int WINAPI wWinMain(HINSTANCE hi, HINSTANCE hpi, PWSTR cmd, int ns) {
|
|
|
|
do {
|
|
|
|
|
|
|
|
std::wstring executableName(entry.szExeFile);
|
|
|
|
|
|
|
|
if (executableName == L"Dwarf Fortress.exe")
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
CloseHandle(snapshot);
|
|
|
|
|
|
|
|
return entry.th32ProcessID;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (Process32NextW(snapshot, &entry));
|
|
|
|
|
|
|
|
|
|
|
|
if (SteamAPI_RestartAppIfNecessary(DFHACK_STEAM_APPID)) // Replace with your App ID
|
|
|
|
CloseHandle(snapshot);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// initialize steam context
|
|
|
|
|
|
|
|
if (SteamAPI_RestartAppIfNecessary(DFHACK_STEAM_APPID))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!SteamAPI_Init())
|
|
|
|
if (!SteamAPI_Init())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
printf("Fatal Error - Steam must be running to play this game (SteamAPI_Init() failed).\n");
|
|
|
|
// could not initialize steam context, attempt fallback launch
|
|
|
|
return 1;
|
|
|
|
LPCWSTR err = launch_direct();
|
|
|
|
|
|
|
|
if (err != NULL)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
MessageBoxW(NULL, err, NULL, 0);
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool wine = is_running_on_wine();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (wine)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// attempt launch via steam client
|
|
|
|
|
|
|
|
LPCWSTR err = launch_via_steam_posix();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (err != NULL)
|
|
|
|
|
|
|
|
// steam client launch failed, attempt fallback launch
|
|
|
|
|
|
|
|
err = launch_direct();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (err != NULL)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
MessageBoxW(NULL, err, NULL, 0);
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// steam detected and not running in wine
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool df_installed = SteamApps()->BIsAppInstalled(DF_STEAM_APPID);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!df_installed)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Steam DF is not installed. Assume DF is installed in same directory as DFHack and do a fallback launch
|
|
|
|
|
|
|
|
LPCWSTR err = launch_direct();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (err != NULL)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
MessageBoxW(NULL, err, NULL, 0);
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
// obtain DF app path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char buf[2048] = "";
|
|
|
|
|
|
|
|
|
|
|
|
LPCWSTR err = is_running_on_wine() ? launch_via_steam_posix() : launch_via_steam_windows();
|
|
|
|
int b = SteamApps()->GetAppInstallDir(DFHACK_STEAM_APPID, (char*)&buf, 2048);
|
|
|
|
|
|
|
|
std::string dfhack_install_folder = (b != -1) ? std::string(buf) : "";
|
|
|
|
|
|
|
|
|
|
|
|
if (err && !launch_direct()) {
|
|
|
|
int b2 = SteamApps()->GetAppInstallDir(DF_STEAM_APPID, (char*)&buf, 2048);
|
|
|
|
|
|
|
|
std::string df_install_folder = (b != -1) ? std::string(buf) : "";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (df_install_folder != dfhack_install_folder)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// DF and DFHack are not installed in the same library
|
|
|
|
|
|
|
|
MessageBoxW(NULL, L"DFHack and Dwarf Fortress must be installed in the same Steam library.\nAborting.", NULL, 0);
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DWORD df_pid = findDwarfFortressProcess();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (df_pid == -1)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
LPCWSTR err = launch_via_steam_windows();
|
|
|
|
|
|
|
|
if (err != NULL)
|
|
|
|
|
|
|
|
{
|
|
|
|
MessageBoxW(NULL, err, NULL, 0);
|
|
|
|
MessageBoxW(NULL, err, NULL, 0);
|
|
|
|
exit(1);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int counter = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
if (counter++ > 60)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
MessageBoxW(NULL, L"Dwarf Fortress took too long to launch, aborting", NULL, 0);
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Sleep(1000);
|
|
|
|
|
|
|
|
df_pid = findDwarfFortressProcess();
|
|
|
|
|
|
|
|
} while (df_pid == -1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HANDLE hDF = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, df_pid);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// in the future open an IPC connection so that we can proxy SteamAPI calls for the DFSteam module
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// this will eventuallyh need to become a loop with a WaitForMultipleObjects call
|
|
|
|
|
|
|
|
WaitForSingleObject(hDF, INFINITE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CloseHandle(hDF);
|
|
|
|
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|