I'm loading my dll into a process and creating an overlay in a new thread.
My idea is to draw into that overlay from the main dll thread.
This is the maindll.cpp code:
uintptr_t mainModule = NULL;
bool visuals = false;
HWND hwndOverlay;
void DoMagic() {
uintptr_t LocalPlayer = *(uintptr_t*)(mainModule + Offsets::dwLocalPlayerPawn);
if (LocalPlayer == 0)
return;
if (GetAsyncKeyState(VK_F1) & 1)
{
visuals = !visuals;
}
if (hwndOverlay) {
HDC hdcOverlay = GetDC(hwndOverlay);
if (visuals) Visuals(mainModule, LocalPlayer, hdcOverlay);
}
Sleep(1);
}
DWORD WINAPI OverlayThread(LPVOID lpParam) {
HMODULE hModule = (HMODULE)lpParam;
hwndOverlay = CreateOverlayWindow(hModule);
if (!hwndOverlay) {
MessageBox(NULL, L"Error creating overlay window", L"Error", MB_ICONERROR);
return 1;
}
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
DWORD WINAPI MainFunc(HMODULE hModule) {
AllocConsole();
FILE* f;
freopen_s(&f, "CONOUT$", "w", stdout);
CloseHandle(CreateThread(nullptr, 0, OverlayThread, hModule, 0, nullptr));
mainModule = (uintptr_t)GetModuleHandle(L"client.dll");
if (hModule)
{
while (!GetAsyncKeyState(VK_END) & 1) DoMagic();
}
else
{
std::cout << "Main module not found, press ENTER to exit..." << std::endl;
getchar();
}
fclose(f);
FreeConsole();
FreeLibraryAndExitThread(hModule, 0);
return 0;
}
This is my CreateOverlayWindow() function which is probably wrong:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
HWND CreateOverlayWindow(HINSTANCE hInstance) {
const wchar_t CLASS_NAME[] = L"OverlayClass";
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0));
wc.lpszClassName = CLASS_NAME;
RegisterClassEx(&wc);
HWND hwndOverlay = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED, CLASS_NAME, L"Overlay",
WS_POPUP, 0, 0, 1920, 1080, nullptr, nullptr, hInstance, nullptr);
SetLayeredWindowAttributes(hwndOverlay, RGB(0, 0, 0), 0, LWA_COLORKEY | LWA_ALPHA);
ShowWindow(hwndOverlay, SW_SHOW);
UpdateWindow(hwndOverlay);
return hwndOverlay;
}
And here is my Visuals() function which I've shortened to avoid useless information, as the coordinates I'm trying to draw are correct:
//Sets the Brush Color
HBRUSH Brush = (playerTeam == localPlayerTeam) ? hBrushGreen : hBrushRed;
COLORREF TextCOLOR = (playerTeam == localPlayerTeam) ? TextColorGreen : TextColorRed;
//Draws the box
DrawBorderBox(playerFeetInScreen.x + center, playerFeetInScreen.y, width, head - extra, 1, hdcOverlay, Brush);
//Draw our heath by converting a int to a char
char healthChar[255];
sprintf_s(healthChar, sizeof(healthChar), "%i", playerHealth);
DrawString(playerFeetInScreen.x, playerFeetInScreen.y, TextCOLOR, healthChar, Font, hdcOverlay);
When I check the coordinates where it's trying to draw I see correct values, but I don't see anything drawn to the screen :( I don't know if it's important, but I have 3 screens.
How can I draw to my screen from my c++ dll?
I just had to change this line:
SetLayeredWindowAttributes(hwndOverlay, RGB(0, 0, 0), 0, LWA_COLORKEY | LWA_ALPHA);
To this:
SetLayeredWindowAttributes(hwndOverlay, RGB(0, 0, 0), 0, LWA_COLORKEY);