-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
217 lines (190 loc) · 8.58 KB
/
main.cpp
File metadata and controls
217 lines (190 loc) · 8.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
//Hi!
// ============================================================
// main.cpp – Entry point, config parsing, adapter selector
// Zero-Latency Network Video Fuser
// ============================================================
#include "NetworkFuser.h"
#include "Logger.h"
#include "ConfigUI.h"
#include "Sender.h"
#include "Receiver.h"
// ─────────────────────────────────────────────────────────────
// FuserUtil implementations
// ─────────────────────────────────────────────────────────────
namespace FuserUtil
{
// Minimal INI reader – no external deps
std::string ReadIniString(const std::string& path,
const std::string& section,
const std::string& key,
const std::string& defaultVal)
{
char buf[1024]{};
DWORD ret = GetPrivateProfileStringA(
section.c_str(), key.c_str(), defaultVal.c_str(),
buf, sizeof(buf), path.c_str());
return std::string(buf, ret);
}
int ReadIniInt(const std::string& path,
const std::string& section,
const std::string& key,
int defaultVal)
{
return static_cast<int>(GetPrivateProfileIntA(
section.c_str(), key.c_str(), defaultVal, path.c_str()));
}
void Log(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
// Route through Logger so every existing call goes to the log file
Logger::WriteV(LogLevel::Info, fmt, args);
va_end(args);
}
void ElevateProcessPriority()
{
if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS))
FuserUtil::Log("[Main] SetPriorityClass REALTIME failed: %u\n", GetLastError());
if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
FuserUtil::Log("[Main] SetThreadPriority TIME_CRITICAL failed: %u\n", GetLastError());
}
void PinThreadToCore(DWORD coreIndex)
{
DWORD_PTR mask = static_cast<DWORD_PTR>(1) << coreIndex;
SetThreadAffinityMask(GetCurrentThread(), mask);
}
}
// ─────────────────────────────────────────────────────────────
// Config loader
// ─────────────────────────────────────────────────────────────
static FuserConfig LoadConfig(const std::string& iniPath)
{
FuserConfig cfg;
std::string mode = FuserUtil::ReadIniString(iniPath, "Fuser", "Mode", "receiver");
cfg.isSender = (mode == "sender");
cfg.localIP = FuserUtil::ReadIniString(iniPath, "Fuser", "LocalIP", "0.0.0.0"); //
cfg.remoteIP = FuserUtil::ReadIniString(iniPath, "Fuser", "RemoteIP", "192.168.50.1"); //
cfg.port = static_cast<uint16_t>(
FuserUtil::ReadIniInt(iniPath, "Fuser", "Port",
static_cast<int>(FUSER_PORT)));
cfg.adapterIndex = FuserUtil::ReadIniInt(iniPath, "Fuser", "AdapterIndex", -1);
cfg.captureMonitor= FuserUtil::ReadIniInt(iniPath, "Fuser", "CaptureMonitor", 0);
return cfg;
}
// ─────────────────────────────────────────────────────────────
// Generate a default config.ini if none exists
// ─────────────────────────────────────────────────────────────
static void WriteDefaultIni(const std::string& iniPath)
{
FILE* f = nullptr;
if (fopen_s(&f, iniPath.c_str(), "wx") != 0 || !f)
return; // already exists
fprintf(f,
"; Knox Fuser – config.ini\n"
"; Mode: sender (second PC, captures + transmits overlay)\n"
"; receiver (main gaming PC, receives + renders overlay)\n"
"[Fuser]\n"
"Mode = receiver\n"
"LocalIP = 0.0.0.0\n"
"RemoteIP = 192.168.50.2\n"
"Port = %u\n"
"AdapterIndex = -1\n"
"CaptureMonitor = 0\n",
static_cast<unsigned>(FUSER_PORT));
fclose(f);
FuserUtil::Log("[Main] Wrote default config.ini\n");
}
// ─────────────────────────────────────────────────────────────
// WinMain
// ─────────────────────────────────────────────────────────────
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
// ── Initialise Logger first – catches crashes from this point on ──
{
char exePathBuf[MAX_PATH]{};
GetModuleFileNameA(nullptr, exePathBuf, MAX_PATH);
std::string exeDir(exePathBuf);
auto sl = exeDir.find_last_of("\\/");
if (sl != std::string::npos) exeDir = exeDir.substr(0, sl + 1);
std::string logDir = exeDir + "Logs";
Logger::Init(logDir);
Logger::Info("[Main] Knox Fuser starting. Log dir: %s", logDir.c_str());
}
// Initialise Winsock2 early
WSADATA wsa{};
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
Logger::Fatal("[Main] WSAStartup failed. GLE=%u", GetLastError());
MessageBoxW(nullptr, L"WSAStartup failed.", L"Knox Fuser", MB_ICONERROR);
return 1;
}
// ── Show the configuration UI ────────────────────────────
// The UI reads the existing config.ini (if present) to pre-fill
// fields, lets the user edit everything, then writes back on
// "Launch". If the user closes the window, we exit cleanly.
FuserConfig cfg;
if (!ShowConfigUI(cfg))
{
// User dismissed the window without launching
WSACleanup();
return 0;
}
// ── Allocate a debug console (after the UI closes) ───────
AllocConsole();
FILE* dummy = nullptr;
freopen_s(&dummy, "CONOUT$", "w", stdout);
freopen_s(&dummy, "CONOUT$", "w", stderr);
Logger::Info("[Main] --- Configuration ---");
Logger::Info("[Main] Mode : %s", cfg.isSender ? "SENDER" : "RECEIVER");
Logger::Info("[Main] LocalIP : %s", cfg.localIP.c_str());
Logger::Info("[Main] RemoteIP : %s", cfg.remoteIP.c_str());
Logger::Info("[Main] Port : %u", cfg.port);
Logger::Info("[Main] Monitor : %d", cfg.captureMonitor);
Logger::Info("[Main] Log file : %s", Logger::GetLogPath().c_str());
// ── Branch: Sender ───────────────────────────────────────
if (cfg.isSender)
{
FuserUtil::ElevateProcessPriority();
SenderModule sender(cfg);
if (!sender.Init())
{
Logger::Fatal("[Main] Sender init failed!");
WSACleanup();
return 1;
}
// Run on a dedicated high-priority thread
std::thread senderThread([&sender]
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
FuserUtil::PinThreadToCore(0);
sender.Run();
});
FuserUtil::Log("[Main] Sender running. Close the console to stop.\n");
// Keep main thread pumping messages until console is closed
MSG msg;
while (GetMessageW(&msg, nullptr, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
sender.Stop();
if (senderThread.joinable())
senderThread.join();
}
// ── Branch: Receiver ─────────────────────────────────────
else
{
ReceiverModule receiver(cfg);
if (!receiver.Init())
{
Logger::Fatal("[Main] Receiver init failed!");
WSACleanup();
return 1;
}
receiver.Run(); // blocking – exits when overlay window is destroyed
}
WSACleanup();
Logger::Info("[Main] Exiting cleanly.");
Logger::Shutdown();
return 0;
}