/* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // FILE: CopyProtection.cpp ////////////////////////////////////////////////// // Author: Matthew D. Campbell // Taken From: Denzil Long's code in Tiberian Sun, by way of Yuri's Revenge ////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" #include "Common/CopyProtection.h" #ifndef DO_COPY_PROTECTION //#pragma MESSAGE("*********************************************************") //#pragma MESSAGE("************* COPY PROTECTION IS DISABLED ***************") //#pragma MESSAGE("*********************************************************") #else LPVOID CopyProtect::s_protectedData = NULL; static const char* const LAUNCHER_GUID = "150C6462-4E49-4ccf-B073-57579569D994"; // Generals Multiplayer Test Launcher GUID static const char* const protectGUID = "6096561D-8A70-48ed-9FF8-18552419E50D"; // Generals Multiplayer Test Protect GUID /* static const char* const LAUNCHER_GUID = "FB327081-64F2-43d8-9B72-503C3B765134"; // Generals Launcher GUID static const char* const protectGUID = "7BEB9006-CC19-4aca-913A-C870A88DE01A"; // Generals Protect GUID */ #if defined(_DEBUG) || defined(_INTERNAL) Bool skipProtection(void) { //return FALSE; if (FindWindow("Afx:400000:8:10011:0:fe8e0125", NULL) != NULL) // DevStudio { DEBUG_LOG(("DevStudio is running - skipping notifyLauncher()\n")); return TRUE; } //return FALSE; return TRUE; } #endif // --------------------------------------------------------------------------- Bool CopyProtect::isLauncherRunning(void) { DEBUG_LOG(("COPYPROTECTION - Checking if launcher is running\n")); HANDLE launcherMutex = CreateMutex(NULL, FALSE, LAUNCHER_GUID); Bool isRunning = (GetLastError() == ERROR_ALREADY_EXISTS); if (launcherMutex != NULL) { CloseHandle(launcherMutex); } DEBUG_LOG(("result was %d\n", (int)isRunning)); #if defined(_DEBUG) || defined(_INTERNAL) if (skipProtection()) { DEBUG_LOG(("DevStudio is running - forcing to TRUE\n")); return TRUE; } #endif return isRunning; } // --------------------------------------------------------------------------- Bool CopyProtect::notifyLauncher(void) { DEBUG_LOG(("COPYPROTECTION - Notify launcher\n")); #if defined(_DEBUG) || defined(_INTERNAL) if (skipProtection()) { DEBUG_LOG(("DevStudio is running - skipping notifyLauncher()\n")); return TRUE; } #endif // Force system to create message queue MSG msg; PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); // Signal launcher to send the beef unsigned long eventTime = (timeGetTime() + 60000); HANDLE event = NULL; while (timeGetTime() < eventTime) { event = OpenEvent(EVENT_MODIFY_STATE, TRUE, protectGUID); if (event) { break; } Sleep(0); } if (event) { SetEvent(event); CloseHandle(event); DEBUG_LOG(("Launcher notified.\n")); DEBUG_LOG(("Waiting for message from launcher.\n")); unsigned long endTime = (timeGetTime() + 10000); while (timeGetTime() <= endTime) { if (PeekMessage(&msg, NULL, 0xBEEF, 0xBEEF, PM_REMOVE)) { // 0xBEEF is in the WM_APP - 0xBFFF range if (msg.message == 0xBEEF) { DEBUG_LOG(("COPYPROTECTION - Received message from launcher (Elapsed time %ld).\n", (10000 - (endTime - timeGetTime())))); HANDLE mappedFile = (HANDLE)msg.lParam; s_protectedData = MapViewOfFileEx(mappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL); if (s_protectedData == NULL) { DEBUG_LOG(("***** MapViewOfFileEx() Failed!\n")); break; } DEBUG_LOG(("The message says: %s\n", s_protectedData)); return TRUE; } } Sleep(0); } DEBUG_LOG(("***** Failed to notify launcher!\n")); return FALSE; } else { DEBUG_LOG(("***** Failed to notify launcher!\n")); } return FALSE; } // --------------------------------------------------------------------------- void CopyProtect::checkForMessage(UINT message, LPARAM lParam) { // 0xBEEF is in the WM_APP - 0xBFFF range if (message == 0xBEEF) { DEBUG_LOG(("COPYPROTECTION - Received message from launcher.\n")); HANDLE mappedFile = (HANDLE)lParam; s_protectedData = MapViewOfFileEx(mappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL); if (s_protectedData == NULL) { DEBUG_LOG(("***** MapViewOfFileEx() Failed!")); return; } DEBUG_LOG(("The message says: %s\n", s_protectedData)); } } // --------------------------------------------------------------------------- Bool CopyProtect::validate(void) { DEBUG_LOG(("COPYPROTECTION - Validating\n")); DEBUG_LOG(("s_protectedData = %d (%s)\n", s_protectedData, (s_protectedData)?s_protectedData:"EEK!")); if (s_protectedData != NULL) { return (strcmp((const char*)s_protectedData, "Play the \"Command & Conquer: Generals\" Multiplayer Test.") == 0); } #if defined(_DEBUG) || defined(_INTERNAL) if (skipProtection()) { DEBUG_LOG(("DevStudio is running - forcing to TRUE\n")); return TRUE; } #endif return FALSE; } // --------------------------------------------------------------------------- void CopyProtect::shutdown(void) { DEBUG_LOG(("COPYPROTECTION - Shutdown\n")); if (s_protectedData != NULL) { UnmapViewOfFile(s_protectedData); s_protectedData = NULL; } } #endif // DO_COPY_PROTECTION