// // Created by Michael on 25/03/2024. // #include #include #include #include #include "application.h" int main() { std::string libraryPath = "library.dll"; // find the "library.dll" either in "./" or in "./lib" or in "./cmake-build-release" std::vector libraryPaths = { libraryPath, "lib\\" + libraryPath, "cmake-build-release\\" + libraryPath, "../" + libraryPath, "../lib/" + libraryPath, "../cmake-build-release/" + libraryPath }; std::string libraryFullPath; for(const std::string& path : libraryPaths) { if(GetFileAttributesA(path.c_str()) != INVALID_FILE_ATTRIBUTES) { libraryFullPath = path; break; } } if(libraryFullPath.empty()) { printf("Library not found\n"); return 1; } // In this directory, find all directories that start with "rekordbox" and end with a number. std::string programPath = R"(C:\Program Files\Pioneer\)"; // Find all matching directories std::vector directories; WIN32_FIND_DATAA findData; HANDLE hFind = FindFirstFileA((programPath + "rekordbox*").c_str(), &findData); if(hFind != INVALID_HANDLE_VALUE) { do { if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { std::string directoryName = findData.cFileName; if(directoryName.find("rekordbox") == 0 && isdigit(directoryName.back())) { directories.push_back(directoryName); } } } while(FindNextFileA(hFind, &findData)); FindClose(hFind); } // If there are no directories, exit if(directories.empty()) { MessageBoxA(NULL, "No rekordbox installation found.", "Error", MB_OK | MB_ICONERROR); return 1; } // Print all directories to stdout printf("Found rekordbox installations: \n"); for(const std::string& directory : directories) { printf(" %s\n", directory.c_str()); } // Out of all the directories, find the latest version // Versions are semver int latestVersion[3] = {0, 0, 0}; for(const std::string& directory : directories) { // Extract the version from the directory name std::string version_str = directory.substr(sizeof("rekordbox ")-1); // Split into major, minor, patch int version[3]; sscanf_s(version_str.c_str(), "%d.%d.%d", &version[0], &version[1], &version[2]); // Compare to latest version // If it's a newer major version, replace if(version[0] > latestVersion[0]) { latestVersion[0] = version[0]; latestVersion[1] = version[1]; latestVersion[2] = version[2]; continue; } // If it's the same major, but newer minor, replace if(version[0] == latestVersion[0] && version[1] > latestVersion[1]) { latestVersion[1] = version[1]; latestVersion[2] = version[2]; continue; } // If it's the same major and minor, but newer patch, replace if(version[0] == latestVersion[0] && version[1] == latestVersion[1] && version[2] > latestVersion[2]) { latestVersion[2] = version[2]; continue; } } // Convert the latest version back to a string like "1.2.3" std::string latestVersion_str = std::to_string(latestVersion[0]) + "." + std::to_string(latestVersion[1]) + "." + std::to_string(latestVersion[2]); // Get the full path to the latest version std::string latestVersionPath = programPath + "rekordbox " + latestVersion_str + "\\rekordbox.exe"; printf("Choosing latest version (v%s) at: %s\n", latestVersion_str.c_str(), latestVersionPath.c_str()); // Start the executable with the library injected PROCESS_INFORMATION pi = { 0 }; STARTUPINFOW si = { 0 }; si.cb = sizeof( si ); std::wstring latestVersionPathw = std::wstring(latestVersionPath.begin(), latestVersionPath.end()); LPCWSTR latestVersionPathW = latestVersionPathw.c_str(); DWORD flags = CREATE_SUSPENDED; if (!CreateProcessW(latestVersionPathW, nullptr, nullptr, nullptr, FALSE, flags, nullptr, nullptr, &si, &pi )) { printf("Failed to start rekordbox\n"); // Get error DWORD error = GetLastError(); LPSTR messageBuffer = nullptr; size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); printf("Error %lu: %s\n", error, messageBuffer); return 1; } // Make the stdout of the process the same as the current stdout LPVOID loc = VirtualAllocEx(pi.hProcess, nullptr, libraryFullPath.size() + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); BOOL result = WriteProcessMemory(pi.hProcess, loc, libraryFullPath.c_str(), libraryFullPath.size() + 1, nullptr); if(!result) { printf("Failed to inject DLL. Couldn't write process memory\n"); return 1; } HANDLE hThread = CreateRemoteThread(pi.hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE) LoadLibraryA, loc, 0, nullptr); if(hThread == nullptr) { printf("Failed to inject DLL. Couldn't create remote thread\n"); return 1; } ResumeThread(pi.hThread); printf("Started rekordbox, goodbye!\n"); // Cleanup CloseHandle(pi.hProcess); CloseHandle(pi.hThread); // Sleep for 5 seconds Sleep(5000); return 0; }