From e89abfcc06ad3acf1bc6db5eaaee6ca08952548f Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 9 Aug 2022 17:55:33 +0200 Subject: [PATCH 01/30] Converted the log functions to plain C --- Publisher/src/Log.h | 30 ++++++++++++++---------------- Publisher/src/XLAST.h | 3 ++- Publisher/src/main.cpp | 2 +- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/Publisher/src/Log.h b/Publisher/src/Log.h index d7b5cef..2f8a1a2 100644 --- a/Publisher/src/Log.h +++ b/Publisher/src/Log.h @@ -1,8 +1,6 @@ #pragma once -#include -#include -#include +#include #include @@ -18,44 +16,44 @@ static void ResetConsoleColor(DWORD dwStdHandle) SetConsoleTextAttribute(hConsole, FOREGROUND_INTENSITY | 7); } -void LogInfo(const std::string &strMessage) +void LogInfo(const char *szMessage) { SetConsoleColor(STD_OUTPUT_HANDLE, 7); - std::cout << strMessage << '\n'; + fprintf_s(stdout, "%s\n", szMessage); ResetConsoleColor(STD_OUTPUT_HANDLE); } -void LogInfo(const std::wstring &wstrMessage) +void LogInfoW(const wchar_t *wszMessage) { SetConsoleColor(STD_OUTPUT_HANDLE, 7); - std::wcout << wstrMessage << '\n'; + fwprintf_s(stdout, L"%s\n", wszMessage); ResetConsoleColor(STD_OUTPUT_HANDLE); } -void LogError(const std::string &strMessage) +void LogError(const char *szMessage) { SetConsoleColor(STD_ERROR_HANDLE, FOREGROUND_RED); - std::cerr << strMessage << '\n'; + fprintf_s(stderr, "%s\n", szMessage); ResetConsoleColor(STD_ERROR_HANDLE); } -void LogError(const std::wstring &wstrMessage) +void LogErrorW(const wchar_t *wszMessage) { SetConsoleColor(STD_ERROR_HANDLE, FOREGROUND_RED); - std::wcerr << wstrMessage << '\n'; + fwprintf_s(stderr, L"%s\n", wszMessage); ResetConsoleColor(STD_ERROR_HANDLE); } -void ExitFailure(const std::string &strMessage) +void ExitFailure(const char *szMessage) { - LogError(strMessage); + LogError(szMessage); system("pause"); } -void ExitSuccess(const std::string &strMessage = "") +void ExitSuccess(const char *szMessage) { - if (strMessage != "") - LogInfo(strMessage); + if (szMessage != NULL) + LogInfo(szMessage); system("pause"); } diff --git a/Publisher/src/XLAST.h b/Publisher/src/XLAST.h index 51695e0..9a67b65 100644 --- a/Publisher/src/XLAST.h +++ b/Publisher/src/XLAST.h @@ -59,7 +59,8 @@ HRESULT BuildXLASTFile(const std::string &strGameName) XLASTFile.close(); - LogInfo(L"XLAST file successfully generated (ID: " + wstrRandomNumberAsHex + L")"); + std::wstring wstrSuccessMessage = L"XLAST file successfully generated (ID: " + wstrRandomNumberAsHex + L")"; + LogInfoW(wstrSuccessMessage.c_str()); return S_OK; } diff --git a/Publisher/src/main.cpp b/Publisher/src/main.cpp index 2d75c6c..a1328dc 100644 --- a/Publisher/src/main.cpp +++ b/Publisher/src/main.cpp @@ -59,7 +59,7 @@ int __cdecl main() Cleanup(); - ExitSuccess(); + ExitSuccess(NULL); return EXIT_SUCCESS; } From d566dc36c4d05e61c41a95c1aa750ab2e893aff8 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 10 Aug 2022 00:13:21 +0200 Subject: [PATCH 02/30] Converted the IO functions to plain C --- Publisher/src/IO.h | 54 +++++++++++++++++++++++++++++-------------- Publisher/src/Utils.h | 7 +++++- Publisher/src/XLAST.h | 16 ++++++++++--- 3 files changed, 56 insertions(+), 21 deletions(-) diff --git a/Publisher/src/IO.h b/Publisher/src/IO.h index 59f317d..3a7e4bd 100644 --- a/Publisher/src/IO.h +++ b/Publisher/src/IO.h @@ -1,27 +1,35 @@ #pragma once -#include +#include #include -std::string GetExecDir() +HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) { char szPath[MAX_PATH] = { 0 }; GetModuleFileName(NULL, szPath, MAX_PATH); - std::string strExecFilePath(szPath); + const char *szLastBackslash = strrchr(szPath, '\\'); + if (szLastBackslash == NULL) + return E_FAIL; + + memcpy_s(szExecDir, nMaxLength, szPath, strnlen_s(szPath, MAX_PATH) - strnlen_s(szLastBackslash, MAX_PATH)); - return strExecFilePath.substr(0, strExecFilePath.find_last_of("\\")); + return S_OK; } -static HRESULT DeleteDirectory(const std::string &strDirPath) +static HRESULT DeleteDirectory(const char *szDirPath) { - BOOL bResult; - std::string strPattern = strDirPath + "\\*.*"; + BOOL bResult = FALSE; + char szPattern[MAX_PATH] = { 0 }; + size_t nDirPathLength = strnlen_s(szDirPath, MAX_PATH); + + strncpy_s(szPattern, szDirPath, nDirPathLength); + strncat_s(szPattern, "\\*.*", 4); WIN32_FIND_DATA FileInfo; - HANDLE hFile = FindFirstFile(strPattern.c_str(), &FileInfo); + HANDLE hFile = FindFirstFile(szPattern, &FileInfo); if (hFile == INVALID_HANDLE_VALUE) return E_FAIL; @@ -30,21 +38,24 @@ static HRESULT DeleteDirectory(const std::string &strDirPath) if (FileInfo.cFileName[0] == '.') continue; - std::string strFilePath = strDirPath + "\\" + FileInfo.cFileName; + char szFilePath[MAX_PATH] = { 0 }; + strncpy_s(szFilePath, szDirPath, nDirPathLength); + strncat_s(szFilePath, "\\", 1); + strncpy_s(szFilePath, FileInfo.cFileName, strnlen_s(FileInfo.cFileName, MAX_PATH)); if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - HRESULT hr = DeleteDirectory(strFilePath); + HRESULT hr = DeleteDirectory(szFilePath); if (FAILED(hr)) return E_FAIL; } else { - bResult = SetFileAttributes(strFilePath.c_str(), FILE_ATTRIBUTE_NORMAL); + bResult = SetFileAttributes(szFilePath, FILE_ATTRIBUTE_NORMAL); if (!bResult) return E_FAIL; - bResult = DeleteFile(strFilePath.c_str()); + bResult = DeleteFile(szFilePath); if (!bResult) return E_FAIL; } @@ -56,11 +67,11 @@ static HRESULT DeleteDirectory(const std::string &strDirPath) if (dwError != ERROR_NO_MORE_FILES) return E_FAIL; - bResult = SetFileAttributes(strDirPath.c_str(), FILE_ATTRIBUTE_NORMAL); + bResult = SetFileAttributes(szDirPath, FILE_ATTRIBUTE_NORMAL); if (!bResult) return E_FAIL; - bResult = RemoveDirectory(strDirPath.c_str()); + bResult = RemoveDirectory(szDirPath); if (!bResult) return E_FAIL; @@ -69,8 +80,17 @@ static HRESULT DeleteDirectory(const std::string &strDirPath) void Cleanup() { - DeleteDirectory(GetExecDir() + "\\Online"); + char szPathToOnlineDir[MAX_PATH] = { 0 }; + char szPathToXLASTFile[MAX_PATH] = { 0 }; + + HRESULT hr = GetExecDir(szPathToOnlineDir, MAX_PATH); + if (FAILED(hr)) + return; + + strncpy_s(szPathToXLASTFile, szPathToOnlineDir, strnlen_s(szPathToOnlineDir, MAX_PATH)); + strncat_s(szPathToXLASTFile, "\\tmp.xlast", 10); + strncat_s(szPathToOnlineDir, "\\Online", 7); - std::string strXLASTFilePath = GetExecDir() + "\\tmp.xlast"; - DeleteFile(strXLASTFilePath.c_str()); + DeleteDirectory(szPathToOnlineDir); + DeleteFile(szPathToXLASTFile); } diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index 766b85e..b668add 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -10,7 +10,12 @@ HRESULT GetGameName(std::string &strName) { - std::ifstream ConfigFile(GetExecDir() + "\\config\\gameInfo.txt"); + char szExecDirBuffer[MAX_PATH] = { 0 }; + HRESULT hr = GetExecDir(szExecDirBuffer, MAX_PATH); + if (FAILED(hr)) + return E_FAIL; + + std::ifstream ConfigFile(std::string(szExecDirBuffer) + "\\config\\gameInfo.txt"); if (!ConfigFile.is_open()) return E_FAIL; diff --git a/Publisher/src/XLAST.h b/Publisher/src/XLAST.h index 9a67b65..5a78235 100644 --- a/Publisher/src/XLAST.h +++ b/Publisher/src/XLAST.h @@ -46,7 +46,12 @@ HRESULT BuildXLASTFile(const std::string &strGameName) L""; // clang-format on - std::wofstream XLASTFile(GetExecDir() + "\\tmp.xlast", std::ios::binary); + char szExecDirBuffer[MAX_PATH] = { 0 }; + HRESULT hr = GetExecDir(szExecDirBuffer, MAX_PATH); + if (FAILED(hr)) + return E_FAIL; + + std::wofstream XLASTFile(std::string(szExecDirBuffer) + "\\tmp.xlast", std::ios::binary); const std::codecvt_mode mode = static_cast(std::generate_header | std::little_endian); std::locale UTF16Locale(XLASTFile.getloc(), new std::codecvt_utf16); @@ -67,8 +72,13 @@ HRESULT BuildXLASTFile(const std::string &strGameName) HRESULT ExecBLAST(const std::string &strXDKPath) { + char szExecDirBuffer[MAX_PATH] = { 0 }; + HRESULT hr = GetExecDir(szExecDirBuffer, MAX_PATH); + if (FAILED(hr)) + return E_FAIL; + + std::string strBLASTParameters = std::string(szExecDirBuffer) + "\\tmp.xlast /build /install:Local /nologo"; std::string strBLASTPath = strXDKPath + "\\bin\\win32\\blast.exe"; - std::string strBLASTParameters = GetExecDir() + "\\tmp.xlast /build /install:Local /nologo"; SHELLEXECUTEINFO ShExecInfo = { 0 }; ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); @@ -77,7 +87,7 @@ HRESULT ExecBLAST(const std::string &strXDKPath) ShExecInfo.lpVerb = NULL; ShExecInfo.lpFile = strBLASTPath.c_str(); ShExecInfo.lpParameters = strBLASTParameters.c_str(); - ShExecInfo.lpDirectory = GetExecDir().c_str(); + ShExecInfo.lpDirectory = szExecDirBuffer; ShExecInfo.nShow = SW_SHOW; ShExecInfo.hInstApp = NULL; ShellExecuteEx(&ShExecInfo); From d45e3e33ba9e4fbbf2ee44055fbb596cf506a0c4 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 10 Aug 2022 18:14:46 +0200 Subject: [PATCH 03/30] Converted GetGameName to plain C --- Publisher/src/Utils.h | 48 ++++++++++++++++++++++++------------------ Publisher/src/main.cpp | 6 +++--- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index b668add..e308e00 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -1,37 +1,43 @@ #pragma once -#include -#include -#include +#include +#include #include #include "IO.h" -HRESULT GetGameName(std::string &strName) +HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) { - char szExecDirBuffer[MAX_PATH] = { 0 }; - HRESULT hr = GetExecDir(szExecDirBuffer, MAX_PATH); - if (FAILED(hr)) - return E_FAIL; - - std::ifstream ConfigFile(std::string(szExecDirBuffer) + "\\config\\gameInfo.txt"); - if (!ConfigFile.is_open()) - return E_FAIL; + HRESULT hr = S_OK; + FILE *ConfigFile = NULL; + char szConfigFilePath[MAX_PATH] = { 0 }; - std::vector lines; - lines.reserve(2); - std::string strCurrentLine; + hr = GetExecDir(szConfigFilePath, MAX_PATH); + if (FAILED(hr)) + { + fputs("Failed to read exec dir", stderr); + return hr; + } - while (std::getline(ConfigFile, strCurrentLine)) - lines.emplace_back(strCurrentLine); + strncat_s(szConfigFilePath, MAX_PATH, "\\config\\gameInfo.txt", 20); - ConfigFile.close(); + if (fopen_s(&ConfigFile, szConfigFilePath, "r") != 0) + { + fprintf_s(stderr, "Failed to open config file at location %s\n", szConfigFilePath); + return E_FAIL; + } - if (lines.size() != 2) + if (fgets(szGameName, (int)nMaxLength, ConfigFile) == NULL) + { + fclose(ConfigFile); return E_FAIL; + } + + size_t nGameNameSize = strnlen_s(szGameName, nMaxLength); + szGameName[nGameNameSize - 1] = '\0'; - strName = lines[0]; + fclose(ConfigFile); - return S_OK; + return hr; } diff --git a/Publisher/src/main.cpp b/Publisher/src/main.cpp index a1328dc..df476de 100644 --- a/Publisher/src/main.cpp +++ b/Publisher/src/main.cpp @@ -19,6 +19,7 @@ int __cdecl main() HRESULT hr; char *szXDKPath; size_t nXDKPathSize; + char szGameName[50] = { 0 }; errno_t err = _dupenv_s(&szXDKPath, &nXDKPathSize, "xedk"); if (!szXDKPath || err) @@ -34,15 +35,14 @@ int __cdecl main() return EXIT_FAILURE; } - std::string strGameName; - hr = GetGameName(strGameName); + hr = GetGameName(szGameName, sizeof(szGameName)); if (FAILED(hr)) { ExitFailure("The game information file (config\\gameInfo.txt) could not be loaded or has a wrong format."); return EXIT_FAILURE; } - hr = BuildXLASTFile(strGameName); + hr = BuildXLASTFile(szGameName); if (FAILED(hr)) { ExitFailure("Could not generate the XLAST file."); From 18e50c94ca351e6e053f8ab6ea0cb235a8dd78eb Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 10 Aug 2022 19:28:05 +0200 Subject: [PATCH 04/30] Converted ExecBLAST to plain C --- Publisher/src/XLAST.h | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Publisher/src/XLAST.h b/Publisher/src/XLAST.h index 5a78235..4eaff41 100644 --- a/Publisher/src/XLAST.h +++ b/Publisher/src/XLAST.h @@ -70,23 +70,30 @@ HRESULT BuildXLASTFile(const std::string &strGameName) return S_OK; } -HRESULT ExecBLAST(const std::string &strXDKPath) +HRESULT ExecBLAST(const char *szXDKPath) { char szExecDirBuffer[MAX_PATH] = { 0 }; + char szBLASTParameters[MAX_PATH] = { 0 }; + char szBLASTPath[MAX_PATH] = { 0 }; HRESULT hr = GetExecDir(szExecDirBuffer, MAX_PATH); if (FAILED(hr)) return E_FAIL; - std::string strBLASTParameters = std::string(szExecDirBuffer) + "\\tmp.xlast /build /install:Local /nologo"; - std::string strBLASTPath = strXDKPath + "\\bin\\win32\\blast.exe"; + size_t nExecDirLength = strnlen_s(szExecDirBuffer, MAX_PATH); + strncpy_s(szBLASTParameters, szExecDirBuffer, nExecDirLength); + strncat_s(szBLASTParameters, "\\tmp.xlast /build /install:Local /nologo", 40); + + size_t nXDKPathLength = strnlen_s(szExecDirBuffer, MAX_PATH); + strncpy_s(szBLASTPath, szXDKPath, nXDKPathLength); + strncat_s(szBLASTPath, "\\bin\\win32\\blast.exe", 20); SHELLEXECUTEINFO ShExecInfo = { 0 }; ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_NO_CONSOLE; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = NULL; - ShExecInfo.lpFile = strBLASTPath.c_str(); - ShExecInfo.lpParameters = strBLASTParameters.c_str(); + ShExecInfo.lpFile = szBLASTPath; + ShExecInfo.lpParameters = szBLASTParameters; ShExecInfo.lpDirectory = szExecDirBuffer; ShExecInfo.nShow = SW_SHOW; ShExecInfo.hInstApp = NULL; @@ -100,7 +107,7 @@ HRESULT ExecBLAST(const std::string &strXDKPath) char szErrorMsg[200] = { 0 }; strerror_s(szErrorMsg, 200, dwError); - std::cerr << szErrorMsg << '\n'; + LogError(szErrorMsg); return E_FAIL; } From e0302441ca3f241ad0c2b0f855b383708ff0a671 Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 11 Aug 2022 00:49:48 +0200 Subject: [PATCH 05/30] Converted BuildXLASTFile to plain C --- Publisher/src/XLAST.h | 90 ++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/Publisher/src/XLAST.h b/Publisher/src/XLAST.h index 4eaff41..90dcbc8 100644 --- a/Publisher/src/XLAST.h +++ b/Publisher/src/XLAST.h @@ -1,71 +1,73 @@ #pragma once -#include -#include -#include -#include -#include - #include #include "IO.h" #include "Log.h" -HRESULT BuildXLASTFile(const std::string &strGameName) +HRESULT BuildXLASTFile(const char *szGameName) { - std::wstring wstrGameName; - wstrGameName.assign(strGameName.begin(), strGameName.end()); + wchar_t wszGameName[50] = { 0 }; + mbstowcs_s(NULL, wszGameName, 50, szGameName, _TRUNCATE); + + uint32_t nRandomNumber = 0x12345678; - std::random_device RandomDevice; - std::mt19937 rng(RandomDevice()); - std::uniform_int_distribution RandomDistance(0, MAXDWORD); - size_t nRandomNumber = RandomDistance(rng); + wchar_t wszRandomNumber[9] = { 0 }; + _snwprintf_s(wszRandomNumber, 9, 9, L"%08x", nRandomNumber); - wchar_t wszBuffer[9] = { 0 }; - _snwprintf_s(wszBuffer, 9, 9, L"%08x", nRandomNumber); + for (size_t i = 0; i < 9; i++) + wszRandomNumber[i] = towlower(wszRandomNumber[i]); - std::wstring wstrRandomNumberAsHex(wszBuffer); - std::transform(wstrRandomNumberAsHex.begin(), wstrRandomNumberAsHex.end(), wstrRandomNumberAsHex.begin(), towupper); + wchar_t *wszFileContent = (wchar_t *)malloc(2048 * sizeof(wchar_t)); + if (wszFileContent == NULL) + return E_FAIL; - // clang-format off - std::wstring wstrFileContent = + const wchar_t *wszFileContentFormat = L"\n" L"\n" - L" \n" - L" \n" - L" \n" - L" \n" - L" \n" - L" \n" - L" \n" - L" \n" - L" \n" - L" \n" - L" \n" - L" \n" + L" \n" + L" \n" + L" \n" + L" \n" + L" \n" + L" \n" + L" \n" + L" \n" + L" \n" + L" \n" + L" \n" + L" \n" L""; - // clang-format on - char szExecDirBuffer[MAX_PATH] = { 0 }; - HRESULT hr = GetExecDir(szExecDirBuffer, MAX_PATH); + _snwprintf_s(wszFileContent, 2048, 2048, wszFileContentFormat, wszGameName, wszRandomNumber, wszGameName, wszGameName, wszGameName); + + char szFilePath[MAX_PATH] = { 0 }; + HRESULT hr = GetExecDir(szFilePath, MAX_PATH); if (FAILED(hr)) return E_FAIL; - std::wofstream XLASTFile(std::string(szExecDirBuffer) + "\\tmp.xlast", std::ios::binary); - const std::codecvt_mode mode = static_cast(std::generate_header | std::little_endian); - std::locale UTF16Locale(XLASTFile.getloc(), new std::codecvt_utf16); + strncat_s(szFilePath, MAX_PATH, "\\tmp.xlast", _TRUNCATE); - if (!XLASTFile.is_open()) + FILE *pFile = NULL; + fopen_s(&pFile, szFilePath, "w+, ccs=UTF-16LE"); + if (pFile == NULL) return E_FAIL; - XLASTFile.imbue(UTF16Locale); + size_t nWCharCount = wcsnlen_s(wszFileContent, 2048); + size_t nWritten = fwrite(wszFileContent, sizeof(wchar_t), nWCharCount, pFile); - XLASTFile << wstrFileContent; + if (nWritten != nWCharCount) + { + fclose(pFile); + return E_FAIL; + } - XLASTFile.close(); + fclose(pFile); + free(wszFileContent); - std::wstring wstrSuccessMessage = L"XLAST file successfully generated (ID: " + wstrRandomNumberAsHex + L")"; - LogInfoW(wstrSuccessMessage.c_str()); + wchar_t wszSuccessMessage[50] = { 0 }; + _snwprintf_s(wszSuccessMessage, 50, 50, L"XLAST file successfully generated (ID: %s)", wszRandomNumber); + LogInfoW(wszSuccessMessage); return S_OK; } @@ -101,7 +103,7 @@ HRESULT ExecBLAST(const char *szXDKPath) WaitForSingleObject(ShExecInfo.hProcess, INFINITE); CloseHandle(ShExecInfo.hProcess); - if (reinterpret_cast(ShExecInfo.hInstApp) <= 32) + if ((int)ShExecInfo.hInstApp <= 32) { DWORD dwError = GetLastError(); char szErrorMsg[200] = { 0 }; From d5f0555d28c8119ff17e799184238a70e147ed60 Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 11 Aug 2022 21:28:12 +0200 Subject: [PATCH 06/30] Made Visual Studio compile as C and moved all variable declarations to the top of the scope (require by C89 used by Visual Studio 2010) --- Publisher/Publisher.vcxproj | 3 +- Publisher/Publisher.vcxproj.filters | 2 +- Publisher/src/IO.h | 41 +++++++++++++--------- Publisher/src/Utils.h | 4 +-- Publisher/src/XLAST.h | 54 ++++++++++++++++------------- Publisher/src/{main.cpp => main.c} | 12 +++++-- 6 files changed, 68 insertions(+), 48 deletions(-) rename Publisher/src/{main.cpp => main.c} (85%) diff --git a/Publisher/Publisher.vcxproj b/Publisher/Publisher.vcxproj index f240b9a..a8e6c64 100644 --- a/Publisher/Publisher.vcxproj +++ b/Publisher/Publisher.vcxproj @@ -43,6 +43,7 @@ true $(IntDir)$(ProjectName)\%(RelativeDir) $(XEDK)\include\win32;%(AdditionalIncludeDirectories) + CompileAsC Console @@ -56,7 +57,7 @@ - + diff --git a/Publisher/Publisher.vcxproj.filters b/Publisher/Publisher.vcxproj.filters index 460d905..743bbb6 100644 --- a/Publisher/Publisher.vcxproj.filters +++ b/Publisher/Publisher.vcxproj.filters @@ -1,7 +1,7 @@  - + diff --git a/Publisher/src/IO.h b/Publisher/src/IO.h index 3a7e4bd..998892c 100644 --- a/Publisher/src/IO.h +++ b/Publisher/src/IO.h @@ -7,45 +7,51 @@ HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) { char szPath[MAX_PATH] = { 0 }; + char *szLastBackslash = NULL; GetModuleFileName(NULL, szPath, MAX_PATH); - const char *szLastBackslash = strrchr(szPath, '\\'); + szLastBackslash = strrchr(szPath, '\\'); if (szLastBackslash == NULL) return E_FAIL; - memcpy_s(szExecDir, nMaxLength, szPath, strnlen_s(szPath, MAX_PATH) - strnlen_s(szLastBackslash, MAX_PATH)); + strncpy_s(szExecDir, nMaxLength, szPath, strnlen_s(szPath, MAX_PATH) - strnlen_s(szLastBackslash, MAX_PATH)); return S_OK; } static HRESULT DeleteDirectory(const char *szDirPath) { + HRESULT hr = S_OK; BOOL bResult = FALSE; + DWORD dwError = 0; + char szPattern[MAX_PATH] = { 0 }; - size_t nDirPathLength = strnlen_s(szDirPath, MAX_PATH); - strncpy_s(szPattern, szDirPath, nDirPathLength); - strncat_s(szPattern, "\\*.*", 4); - WIN32_FIND_DATA FileInfo; + WIN32_FIND_DATA FileInfo = { 0 }; + HANDLE hFile = INVALID_HANDLE_VALUE; + + strncpy_s(szPattern, MAX_PATH, szDirPath, _TRUNCATE); + strncat_s(szPattern, MAX_PATH, "\\*.*", _TRUNCATE); - HANDLE hFile = FindFirstFile(szPattern, &FileInfo); + hFile = FindFirstFile(szPattern, &FileInfo); if (hFile == INVALID_HANDLE_VALUE) return E_FAIL; while (FindNextFile(hFile, &FileInfo)) { + char szFilePath[MAX_PATH] = { 0 }; + if (FileInfo.cFileName[0] == '.') continue; - char szFilePath[MAX_PATH] = { 0 }; - strncpy_s(szFilePath, szDirPath, nDirPathLength); - strncat_s(szFilePath, "\\", 1); - strncpy_s(szFilePath, FileInfo.cFileName, strnlen_s(FileInfo.cFileName, MAX_PATH)); + strncpy_s(szFilePath, MAX_PATH, szDirPath, _TRUNCATE); + strncat_s(szFilePath, MAX_PATH, "\\", _TRUNCATE); + strncpy_s(szFilePath, MAX_PATH, FileInfo.cFileName, _TRUNCATE); if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - HRESULT hr = DeleteDirectory(szFilePath); + hr = DeleteDirectory(szFilePath); if (FAILED(hr)) return E_FAIL; } @@ -63,7 +69,7 @@ static HRESULT DeleteDirectory(const char *szDirPath) FindClose(hFile); - DWORD dwError = GetLastError(); + dwError = GetLastError(); if (dwError != ERROR_NO_MORE_FILES) return E_FAIL; @@ -80,16 +86,17 @@ static HRESULT DeleteDirectory(const char *szDirPath) void Cleanup() { + HRESULT hr = S_OK; char szPathToOnlineDir[MAX_PATH] = { 0 }; char szPathToXLASTFile[MAX_PATH] = { 0 }; - HRESULT hr = GetExecDir(szPathToOnlineDir, MAX_PATH); + hr = GetExecDir(szPathToOnlineDir, MAX_PATH); if (FAILED(hr)) return; - strncpy_s(szPathToXLASTFile, szPathToOnlineDir, strnlen_s(szPathToOnlineDir, MAX_PATH)); - strncat_s(szPathToXLASTFile, "\\tmp.xlast", 10); - strncat_s(szPathToOnlineDir, "\\Online", 7); + strncpy_s(szPathToXLASTFile, MAX_PATH, szPathToOnlineDir, _TRUNCATE); + strncat_s(szPathToXLASTFile, MAX_PATH, "\\tmp.xlast", _TRUNCATE); + strncat_s(szPathToOnlineDir, MAX_PATH, "\\Online", _TRUNCATE); DeleteDirectory(szPathToOnlineDir); DeleteFile(szPathToXLASTFile); diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index e308e00..00f5eb1 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -12,6 +12,7 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) HRESULT hr = S_OK; FILE *ConfigFile = NULL; char szConfigFilePath[MAX_PATH] = { 0 }; + size_t nGameNameSize = strnlen_s(szGameName, nMaxLength); hr = GetExecDir(szConfigFilePath, MAX_PATH); if (FAILED(hr)) @@ -20,7 +21,7 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) return hr; } - strncat_s(szConfigFilePath, MAX_PATH, "\\config\\gameInfo.txt", 20); + strncat_s(szConfigFilePath, MAX_PATH, "\\config\\gameInfo.txt", _TRUNCATE); if (fopen_s(&ConfigFile, szConfigFilePath, "r") != 0) { @@ -34,7 +35,6 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) return E_FAIL; } - size_t nGameNameSize = strnlen_s(szGameName, nMaxLength); szGameName[nGameNameSize - 1] = '\0'; fclose(ConfigFile); diff --git a/Publisher/src/XLAST.h b/Publisher/src/XLAST.h index 90dcbc8..3ae0fb1 100644 --- a/Publisher/src/XLAST.h +++ b/Publisher/src/XLAST.h @@ -7,21 +7,20 @@ HRESULT BuildXLASTFile(const char *szGameName) { + HRESULT hr = S_OK; + + char szFilePath[MAX_PATH] = { 0 }; wchar_t wszGameName[50] = { 0 }; - mbstowcs_s(NULL, wszGameName, 50, szGameName, _TRUNCATE); uint32_t nRandomNumber = 0x12345678; - wchar_t wszRandomNumber[9] = { 0 }; - _snwprintf_s(wszRandomNumber, 9, 9, L"%08x", nRandomNumber); - for (size_t i = 0; i < 9; i++) - wszRandomNumber[i] = towlower(wszRandomNumber[i]); + size_t i = 0; + size_t nWCharCount = 0; + size_t nWritten = 0; + FILE *pFile = NULL; wchar_t *wszFileContent = (wchar_t *)malloc(2048 * sizeof(wchar_t)); - if (wszFileContent == NULL) - return E_FAIL; - const wchar_t *wszFileContentFormat = L"\n" L"\n" @@ -39,22 +38,29 @@ HRESULT BuildXLASTFile(const char *szGameName) L" \n" L""; + mbstowcs_s(NULL, wszGameName, 50, szGameName, _TRUNCATE); + _snwprintf_s(wszRandomNumber, 9, 9, L"%08x", nRandomNumber); + + for (i = 0; i < 9; i++) + wszRandomNumber[i] = towlower(wszRandomNumber[i]); + + if (wszFileContent == NULL) + return E_FAIL; + _snwprintf_s(wszFileContent, 2048, 2048, wszFileContentFormat, wszGameName, wszRandomNumber, wszGameName, wszGameName, wszGameName); - char szFilePath[MAX_PATH] = { 0 }; - HRESULT hr = GetExecDir(szFilePath, MAX_PATH); + hr = GetExecDir(szFilePath, MAX_PATH); if (FAILED(hr)) return E_FAIL; strncat_s(szFilePath, MAX_PATH, "\\tmp.xlast", _TRUNCATE); - FILE *pFile = NULL; fopen_s(&pFile, szFilePath, "w+, ccs=UTF-16LE"); if (pFile == NULL) return E_FAIL; - size_t nWCharCount = wcsnlen_s(wszFileContent, 2048); - size_t nWritten = fwrite(wszFileContent, sizeof(wchar_t), nWCharCount, pFile); + nWCharCount = wcsnlen_s(wszFileContent, 2048); + nWritten = fwrite(wszFileContent, sizeof(wchar_t), nWCharCount, pFile); if (nWritten != nWCharCount) { @@ -65,31 +71,31 @@ HRESULT BuildXLASTFile(const char *szGameName) fclose(pFile); free(wszFileContent); - wchar_t wszSuccessMessage[50] = { 0 }; - _snwprintf_s(wszSuccessMessage, 50, 50, L"XLAST file successfully generated (ID: %s)", wszRandomNumber); - LogInfoW(wszSuccessMessage); + wprintf_s(L"XLAST file successfully generated (ID: %s)", wszRandomNumber); return S_OK; } HRESULT ExecBLAST(const char *szXDKPath) { + HRESULT hr = S_OK; + char szExecDirBuffer[MAX_PATH] = { 0 }; char szBLASTParameters[MAX_PATH] = { 0 }; char szBLASTPath[MAX_PATH] = { 0 }; - HRESULT hr = GetExecDir(szExecDirBuffer, MAX_PATH); + + SHELLEXECUTEINFO ShExecInfo = { 0 }; + + hr = GetExecDir(szExecDirBuffer, MAX_PATH); if (FAILED(hr)) return E_FAIL; - size_t nExecDirLength = strnlen_s(szExecDirBuffer, MAX_PATH); - strncpy_s(szBLASTParameters, szExecDirBuffer, nExecDirLength); - strncat_s(szBLASTParameters, "\\tmp.xlast /build /install:Local /nologo", 40); + strncpy_s(szBLASTParameters, MAX_PATH, szExecDirBuffer, _TRUNCATE); + strncat_s(szBLASTParameters, MAX_PATH, "\\tmp.xlast /build /install:Local /nologo", _TRUNCATE); - size_t nXDKPathLength = strnlen_s(szExecDirBuffer, MAX_PATH); - strncpy_s(szBLASTPath, szXDKPath, nXDKPathLength); - strncat_s(szBLASTPath, "\\bin\\win32\\blast.exe", 20); + strncpy_s(szBLASTPath, MAX_PATH, szXDKPath, _TRUNCATE); + strncat_s(szBLASTPath, MAX_PATH, "\\bin\\win32\\blast.exe", _TRUNCATE); - SHELLEXECUTEINFO ShExecInfo = { 0 }; ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_NO_CONSOLE; ShExecInfo.hwnd = NULL; diff --git a/Publisher/src/main.cpp b/Publisher/src/main.c similarity index 85% rename from Publisher/src/main.cpp rename to Publisher/src/main.c index df476de..090f751 100644 --- a/Publisher/src/main.cpp +++ b/Publisher/src/main.c @@ -1,5 +1,9 @@ #include + +#pragma warning(push) +#pragma warning(disable: 4214) #include +#pragma warning(pop) #include "IO.h" #include "Utils.h" @@ -16,13 +20,15 @@ static HRESULT CheckXBDMConnection() int __cdecl main() { - HRESULT hr; + HRESULT hr = S_OK; + errno_t err = 0; + char *szXDKPath; size_t nXDKPathSize; char szGameName[50] = { 0 }; - errno_t err = _dupenv_s(&szXDKPath, &nXDKPathSize, "xedk"); - if (!szXDKPath || err) + err = _dupenv_s(&szXDKPath, &nXDKPathSize, "xedk"); + if (szXDKPath == NULL || err != 0) { ExitFailure("You must have the Xbox 360 Development Kit (XDK) installed on your computer."); return EXIT_FAILURE; From 5e8092b3b346196153c76714615a0cacdaa370c5 Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 11 Aug 2022 21:59:13 +0200 Subject: [PATCH 07/30] Fixed some variables that were not initialized and a missing header file --- Publisher/src/XLAST.h | 2 ++ Publisher/src/main.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Publisher/src/XLAST.h b/Publisher/src/XLAST.h index 3ae0fb1..23e25dc 100644 --- a/Publisher/src/XLAST.h +++ b/Publisher/src/XLAST.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include "IO.h" diff --git a/Publisher/src/main.c b/Publisher/src/main.c index 090f751..7084bee 100644 --- a/Publisher/src/main.c +++ b/Publisher/src/main.c @@ -1,7 +1,7 @@ #include #pragma warning(push) -#pragma warning(disable: 4214) +#pragma warning(disable : 4214) #include #pragma warning(pop) @@ -23,8 +23,8 @@ int __cdecl main() HRESULT hr = S_OK; errno_t err = 0; - char *szXDKPath; - size_t nXDKPathSize; + char *szXDKPath = NULL; + size_t nXDKPathSize = 0; char szGameName[50] = { 0 }; err = _dupenv_s(&szXDKPath, &nXDKPathSize, "xedk"); From 57aa0ab644d82518af1ed054e85786cef59865a0 Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 11 Aug 2022 21:59:38 +0200 Subject: [PATCH 08/30] Converted the Xbox 360 app to plain C --- GameShortcut/GameShortcut.vcxproj | 5 +- GameShortcut/GameShortcut.vcxproj.filters | 2 +- GameShortcut/src/main.c | 111 ++++++++++++++++++++++ GameShortcut/src/main.cpp | 108 --------------------- 4 files changed, 115 insertions(+), 111 deletions(-) create mode 100644 GameShortcut/src/main.c delete mode 100644 GameShortcut/src/main.cpp diff --git a/GameShortcut/GameShortcut.vcxproj b/GameShortcut/GameShortcut.vcxproj index 277a54e..cbd9842 100644 --- a/GameShortcut/GameShortcut.vcxproj +++ b/GameShortcut/GameShortcut.vcxproj @@ -1,4 +1,4 @@ - + @@ -46,6 +46,7 @@ NDEBUG;_XBOX true $(IntDir)$(ProjectName)\%(RelativeDir) + CompileAsC true @@ -66,7 +67,7 @@ - + diff --git a/GameShortcut/GameShortcut.vcxproj.filters b/GameShortcut/GameShortcut.vcxproj.filters index a6b84a1..48743fa 100644 --- a/GameShortcut/GameShortcut.vcxproj.filters +++ b/GameShortcut/GameShortcut.vcxproj.filters @@ -1,7 +1,7 @@  - + diff --git a/GameShortcut/src/main.c b/GameShortcut/src/main.c new file mode 100644 index 0000000..baecf84 --- /dev/null +++ b/GameShortcut/src/main.c @@ -0,0 +1,111 @@ +#include +#include + +#include + +typedef struct +{ + uint16_t wLength; + uint16_t wMaxLength; + const char *szBuffer; +} STRING; + +HRESULT __stdcall ObCreateSymbolicLink(STRING *, STRING *); + +static HRESULT MountHdd() +{ + STRING DeviceName = { 0 }; + STRING LinkName = { 0 }; + const char *szDestDrive = "\\??\\hdd:"; + const char *szHddDeviceName = "\\Device\\Harddisk0\\Partition1\\"; + + DeviceName.wLength = (uint16_t)strnlen_s(szHddDeviceName, MAX_PATH); + DeviceName.wMaxLength = (uint16_t)(strnlen_s(szHddDeviceName, MAX_PATH) + 1); + DeviceName.szBuffer = szHddDeviceName; + + LinkName.wLength = (uint16_t)strnlen_s(szDestDrive, MAX_PATH); + LinkName.wMaxLength = (uint16_t)(strnlen_s(szDestDrive, MAX_PATH) + 1); + LinkName.szBuffer = szDestDrive; + + return ObCreateSymbolicLink(&LinkName, &DeviceName); +} + +static HRESULT GetGamePath(char *szGamePath, uint32_t nMaxLength) +{ + HRESULT hr = S_OK; + size_t i = 0; + FILE *ConfigFile = NULL; + size_t nGamePathSize = strnlen_s(szGamePath, nMaxLength); + + if (fopen_s(&ConfigFile, "game:\\config\\gameInfo.txt", "r") != 0) + return E_FAIL; + + for (i = 0; i < 2; i++) + if (fgets(szGamePath, (int)nMaxLength, ConfigFile) == NULL) + return E_FAIL; + + szGamePath[nGamePathSize - 1] = '\0'; + + fclose(ConfigFile); + + return hr; +} + +static HRESULT ShowMessageBoxError(const char *szMessage) +{ + DWORD dwResult = 0; + + wchar_t wszMessage[200] = { 0 }; + XOVERLAPPED Overlapped = { 0 }; + MESSAGEBOX_RESULT Result = { 0 }; + const wchar_t *pwstrButtons[] = { L"OK", L"Cancel" }; + + mbstowcs_s(NULL, wszMessage, 200, szMessage, _TRUNCATE); + + dwResult = XShowMessageBoxUI( + 0, + L"Error", + wszMessage, + ARRAYSIZE(pwstrButtons), + pwstrButtons, + 0, + XMB_ERRORICON, + &Result, + &Overlapped + ); + + if (dwResult != ERROR_IO_PENDING) + return E_FAIL; + + while (!XHasOverlappedIoCompleted(&Overlapped)) + Sleep(100); + + dwResult = XGetOverlappedResult(&Overlapped, NULL, TRUE); + + if (dwResult == ERROR_ACCESS_DENIED) + return E_FAIL; + + return S_OK; +} + +int __cdecl main() +{ + HRESULT hr = S_OK; + char szGamePath[MAX_PATH] = { 0 }; + + hr = MountHdd(); + if (FAILED(hr)) + { + ShowMessageBoxError("Could not mount HDD1."); + return EXIT_FAILURE; + } + + hr = GetGamePath(szGamePath, MAX_PATH); + if (FAILED(hr)) + { + ShowMessageBoxError("The game information file (config\\gameInfo.txt) could not be loaded or has a wrong format."); + return EXIT_FAILURE; + } + + XLaunchNewImage(szGamePath, 0); +} diff --git a/GameShortcut/src/main.cpp b/GameShortcut/src/main.cpp deleted file mode 100644 index 295ae50..0000000 --- a/GameShortcut/src/main.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include -#include -#include -#include -#include - -struct STRING -{ - uint16_t wLength; - uint16_t wMaxLength; - const char *szBuffer; -}; - -// clang-format off -#define MakeString(s) { static_cast(strlen(s)), static_cast(strlen(s)) + 1, s } -// clang-format on - -extern "C" HRESULT __stdcall ObCreateSymbolicLink(STRING *, STRING *); - -static HRESULT MountHdd() -{ - const char *szDestDrive = "\\??\\hdd:"; - const char *szHddDeviceName = "\\Device\\Harddisk0\\Partition1\\"; - - STRING DeviceName = MakeString(szHddDeviceName); - STRING LinkName = MakeString(szDestDrive); - - return ObCreateSymbolicLink(&LinkName, &DeviceName); -} - -static HRESULT GetGamePath(std::string &strPath) -{ - std::ifstream ConfigFile("game:\\config\\gameInfo.txt"); - if (!ConfigFile.is_open()) - return E_FAIL; - - std::vector Lines; - Lines.reserve(2); - std::string strCurrentLine; - - while (std::getline(ConfigFile, strCurrentLine)) - Lines.emplace_back(strCurrentLine); - - ConfigFile.close(); - - if (Lines.size() != 2) - return E_FAIL; - - strPath = Lines[1]; - - return S_OK; -} - -static HRESULT ShowMessageBoxError(const std::string &strMessage) -{ - XOVERLAPPED Overlapped = { 0 }; - MESSAGEBOX_RESULT Result = { 0 }; - - std::wstring wstrMessage; - wstrMessage.assign(strMessage.begin(), strMessage.end()); - - const wchar_t *pwstrButtons[] = { L"OK", L"Cancel" }; - - DWORD dwResult = XShowMessageBoxUI( - 0, - L"Error", - wstrMessage.c_str(), - ARRAYSIZE(pwstrButtons), - pwstrButtons, - 0, - XMB_ERRORICON, - &Result, - &Overlapped - ); - - if (dwResult != ERROR_IO_PENDING) - return E_FAIL; - - while (!XHasOverlappedIoCompleted(&Overlapped)) - Sleep(100); - - dwResult = XGetOverlappedResult(&Overlapped, nullptr, true); - - if (dwResult == ERROR_ACCESS_DENIED) - return E_FAIL; - - return S_OK; -} - -int __cdecl main() -{ - HRESULT hr = MountHdd(); - if (FAILED(hr)) - { - ShowMessageBoxError("Could not mount HDD1."); - return EXIT_FAILURE; - } - - std::string strGamePath; - hr = GetGamePath(strGamePath); - if (FAILED(hr)) - { - ShowMessageBoxError("The game information file (config\\gameInfo.txt) could not be loaded or has a wrong format."); - return EXIT_FAILURE; - } - - XLaunchNewImage(strGamePath.c_str(), 0); -} From 6ecd6be2037b26f1ed1bb8b362d9683e7700b13a Mon Sep 17 00:00:00 2001 From: Clement Date: Sat, 13 Aug 2022 01:39:14 +0200 Subject: [PATCH 09/30] Initialized the STRINGs with RtlInitAnsiString instead of doing it manually --- GameShortcut/src/main.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/GameShortcut/src/main.c b/GameShortcut/src/main.c index baecf84..abde4e2 100644 --- a/GameShortcut/src/main.c +++ b/GameShortcut/src/main.c @@ -10,7 +10,8 @@ typedef struct const char *szBuffer; } STRING; -HRESULT __stdcall ObCreateSymbolicLink(STRING *, STRING *); +void RtlInitAnsiString(STRING *, const char *); +HRESULT ObCreateSymbolicLink(STRING *, STRING *); static HRESULT MountHdd() { @@ -19,13 +20,8 @@ static HRESULT MountHdd() const char *szDestDrive = "\\??\\hdd:"; const char *szHddDeviceName = "\\Device\\Harddisk0\\Partition1\\"; - DeviceName.wLength = (uint16_t)strnlen_s(szHddDeviceName, MAX_PATH); - DeviceName.wMaxLength = (uint16_t)(strnlen_s(szHddDeviceName, MAX_PATH) + 1); - DeviceName.szBuffer = szHddDeviceName; - - LinkName.wLength = (uint16_t)strnlen_s(szDestDrive, MAX_PATH); - LinkName.wMaxLength = (uint16_t)(strnlen_s(szDestDrive, MAX_PATH) + 1); - LinkName.szBuffer = szDestDrive; + RtlInitAnsiString(&DeviceName, szHddDeviceName); + RtlInitAnsiString(&LinkName, szDestDrive); return ObCreateSymbolicLink(&LinkName, &DeviceName); } From b9383ba3bb1cb4ac8aa0b88fc3913b2a39a4be14 Mon Sep 17 00:00:00 2001 From: Clement Date: Sat, 13 Aug 2022 01:40:01 +0200 Subject: [PATCH 10/30] Fixed the game name and path lengths being wrong --- GameShortcut/src/main.c | 3 ++- Publisher/src/Utils.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/GameShortcut/src/main.c b/GameShortcut/src/main.c index abde4e2..673a548 100644 --- a/GameShortcut/src/main.c +++ b/GameShortcut/src/main.c @@ -31,7 +31,7 @@ static HRESULT GetGamePath(char *szGamePath, uint32_t nMaxLength) HRESULT hr = S_OK; size_t i = 0; FILE *ConfigFile = NULL; - size_t nGamePathSize = strnlen_s(szGamePath, nMaxLength); + size_t nGamePathSize = 0; if (fopen_s(&ConfigFile, "game:\\config\\gameInfo.txt", "r") != 0) return E_FAIL; @@ -40,6 +40,7 @@ static HRESULT GetGamePath(char *szGamePath, uint32_t nMaxLength) if (fgets(szGamePath, (int)nMaxLength, ConfigFile) == NULL) return E_FAIL; + nGamePathSize = strnlen_s(szGamePath, nMaxLength); szGamePath[nGamePathSize - 1] = '\0'; fclose(ConfigFile); diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index 00f5eb1..65dacad 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -12,7 +12,7 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) HRESULT hr = S_OK; FILE *ConfigFile = NULL; char szConfigFilePath[MAX_PATH] = { 0 }; - size_t nGameNameSize = strnlen_s(szGameName, nMaxLength); + size_t nGameNameSize = 0; hr = GetExecDir(szConfigFilePath, MAX_PATH); if (FAILED(hr)) @@ -35,6 +35,7 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) return E_FAIL; } + nGameNameSize = strnlen_s(szGameName, nMaxLength); szGameName[nGameNameSize - 1] = '\0'; fclose(ConfigFile); From 6f754b87e7888bc9ca269e6d0822cc71f858950c Mon Sep 17 00:00:00 2001 From: Clement Date: Sat, 13 Aug 2022 01:40:17 +0200 Subject: [PATCH 11/30] Fixed missing new line in printf --- Publisher/src/XLAST.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Publisher/src/XLAST.h b/Publisher/src/XLAST.h index 23e25dc..8e51f78 100644 --- a/Publisher/src/XLAST.h +++ b/Publisher/src/XLAST.h @@ -73,7 +73,7 @@ HRESULT BuildXLASTFile(const char *szGameName) fclose(pFile); free(wszFileContent); - wprintf_s(L"XLAST file successfully generated (ID: %s)", wszRandomNumber); + wprintf_s(L"XLAST file successfully generated (ID: %s)\n", wszRandomNumber); return S_OK; } From 8ca33883ca3d6e8643a2ced2dce871320f471ad1 Mon Sep 17 00:00:00 2001 From: Clement Date: Sat, 13 Aug 2022 14:17:09 +0200 Subject: [PATCH 12/30] Moved every function besides to entry point to a single translation unit --- Publisher/Publisher.vcxproj | 4 +- Publisher/Publisher.vcxproj.filters | 4 +- Publisher/src/IO.h | 103 ----------------- Publisher/src/Log.h | 59 ---------- Publisher/src/{XLAST.h => Utils.c} | 170 +++++++++++++++++++++++++++- Publisher/src/Utils.h | 39 ++----- Publisher/src/main.c | 18 --- 7 files changed, 175 insertions(+), 222 deletions(-) delete mode 100644 Publisher/src/IO.h delete mode 100644 Publisher/src/Log.h rename Publisher/src/{XLAST.h => Utils.c} (52%) diff --git a/Publisher/Publisher.vcxproj b/Publisher/Publisher.vcxproj index a8e6c64..39ba0bf 100644 --- a/Publisher/Publisher.vcxproj +++ b/Publisher/Publisher.vcxproj @@ -58,12 +58,10 @@ + - - - diff --git a/Publisher/Publisher.vcxproj.filters b/Publisher/Publisher.vcxproj.filters index 743bbb6..563de3e 100644 --- a/Publisher/Publisher.vcxproj.filters +++ b/Publisher/Publisher.vcxproj.filters @@ -2,12 +2,10 @@ + - - - diff --git a/Publisher/src/IO.h b/Publisher/src/IO.h deleted file mode 100644 index 998892c..0000000 --- a/Publisher/src/IO.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include - -#include - -HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) -{ - char szPath[MAX_PATH] = { 0 }; - char *szLastBackslash = NULL; - - GetModuleFileName(NULL, szPath, MAX_PATH); - - szLastBackslash = strrchr(szPath, '\\'); - if (szLastBackslash == NULL) - return E_FAIL; - - strncpy_s(szExecDir, nMaxLength, szPath, strnlen_s(szPath, MAX_PATH) - strnlen_s(szLastBackslash, MAX_PATH)); - - return S_OK; -} - -static HRESULT DeleteDirectory(const char *szDirPath) -{ - HRESULT hr = S_OK; - BOOL bResult = FALSE; - DWORD dwError = 0; - - char szPattern[MAX_PATH] = { 0 }; - - WIN32_FIND_DATA FileInfo = { 0 }; - HANDLE hFile = INVALID_HANDLE_VALUE; - - strncpy_s(szPattern, MAX_PATH, szDirPath, _TRUNCATE); - strncat_s(szPattern, MAX_PATH, "\\*.*", _TRUNCATE); - - hFile = FindFirstFile(szPattern, &FileInfo); - if (hFile == INVALID_HANDLE_VALUE) - return E_FAIL; - - while (FindNextFile(hFile, &FileInfo)) - { - char szFilePath[MAX_PATH] = { 0 }; - - if (FileInfo.cFileName[0] == '.') - continue; - - strncpy_s(szFilePath, MAX_PATH, szDirPath, _TRUNCATE); - strncat_s(szFilePath, MAX_PATH, "\\", _TRUNCATE); - strncpy_s(szFilePath, MAX_PATH, FileInfo.cFileName, _TRUNCATE); - - if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - hr = DeleteDirectory(szFilePath); - if (FAILED(hr)) - return E_FAIL; - } - else - { - bResult = SetFileAttributes(szFilePath, FILE_ATTRIBUTE_NORMAL); - if (!bResult) - return E_FAIL; - - bResult = DeleteFile(szFilePath); - if (!bResult) - return E_FAIL; - } - } - - FindClose(hFile); - - dwError = GetLastError(); - if (dwError != ERROR_NO_MORE_FILES) - return E_FAIL; - - bResult = SetFileAttributes(szDirPath, FILE_ATTRIBUTE_NORMAL); - if (!bResult) - return E_FAIL; - - bResult = RemoveDirectory(szDirPath); - if (!bResult) - return E_FAIL; - - return S_OK; -} - -void Cleanup() -{ - HRESULT hr = S_OK; - char szPathToOnlineDir[MAX_PATH] = { 0 }; - char szPathToXLASTFile[MAX_PATH] = { 0 }; - - hr = GetExecDir(szPathToOnlineDir, MAX_PATH); - if (FAILED(hr)) - return; - - strncpy_s(szPathToXLASTFile, MAX_PATH, szPathToOnlineDir, _TRUNCATE); - strncat_s(szPathToXLASTFile, MAX_PATH, "\\tmp.xlast", _TRUNCATE); - strncat_s(szPathToOnlineDir, MAX_PATH, "\\Online", _TRUNCATE); - - DeleteDirectory(szPathToOnlineDir); - DeleteFile(szPathToXLASTFile); -} diff --git a/Publisher/src/Log.h b/Publisher/src/Log.h deleted file mode 100644 index 2f8a1a2..0000000 --- a/Publisher/src/Log.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include - -#include - -static void SetConsoleColor(DWORD dwStdHandle, uint16_t wColor) -{ - HANDLE hConsole = GetStdHandle(dwStdHandle); - SetConsoleTextAttribute(hConsole, FOREGROUND_INTENSITY | wColor); -} - -static void ResetConsoleColor(DWORD dwStdHandle) -{ - HANDLE hConsole = GetStdHandle(dwStdHandle); - SetConsoleTextAttribute(hConsole, FOREGROUND_INTENSITY | 7); -} - -void LogInfo(const char *szMessage) -{ - SetConsoleColor(STD_OUTPUT_HANDLE, 7); - fprintf_s(stdout, "%s\n", szMessage); - ResetConsoleColor(STD_OUTPUT_HANDLE); -} - -void LogInfoW(const wchar_t *wszMessage) -{ - SetConsoleColor(STD_OUTPUT_HANDLE, 7); - fwprintf_s(stdout, L"%s\n", wszMessage); - ResetConsoleColor(STD_OUTPUT_HANDLE); -} - -void LogError(const char *szMessage) -{ - SetConsoleColor(STD_ERROR_HANDLE, FOREGROUND_RED); - fprintf_s(stderr, "%s\n", szMessage); - ResetConsoleColor(STD_ERROR_HANDLE); -} - -void LogErrorW(const wchar_t *wszMessage) -{ - SetConsoleColor(STD_ERROR_HANDLE, FOREGROUND_RED); - fwprintf_s(stderr, L"%s\n", wszMessage); - ResetConsoleColor(STD_ERROR_HANDLE); -} - -void ExitFailure(const char *szMessage) -{ - LogError(szMessage); - system("pause"); -} - -void ExitSuccess(const char *szMessage) -{ - if (szMessage != NULL) - LogInfo(szMessage); - - system("pause"); -} diff --git a/Publisher/src/XLAST.h b/Publisher/src/Utils.c similarity index 52% rename from Publisher/src/XLAST.h rename to Publisher/src/Utils.c index 8e51f78..c4e6558 100644 --- a/Publisher/src/XLAST.h +++ b/Publisher/src/Utils.c @@ -1,11 +1,148 @@ -#pragma once - #include +#include #include -#include "IO.h" -#include "Log.h" +#pragma warning(push) +#pragma warning(disable : 4214) +#include +#pragma warning(pop) + +#include "Utils.h" + +HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) +{ + HRESULT hr = S_OK; + FILE *ConfigFile = NULL; + char szConfigFilePath[MAX_PATH] = { 0 }; + size_t nGameNameSize = 0; + + hr = GetExecDir(szConfigFilePath, MAX_PATH); + if (FAILED(hr)) + { + fputs("Failed to read exec dir", stderr); + return hr; + } + + strncat_s(szConfigFilePath, MAX_PATH, "\\config\\gameInfo.txt", _TRUNCATE); + + if (fopen_s(&ConfigFile, szConfigFilePath, "r") != 0) + { + fprintf_s(stderr, "Failed to open config file at location %s\n", szConfigFilePath); + return E_FAIL; + } + + if (fgets(szGameName, (int)nMaxLength, ConfigFile) == NULL) + { + fclose(ConfigFile); + return E_FAIL; + } + + nGameNameSize = strnlen_s(szGameName, nMaxLength); + szGameName[nGameNameSize - 1] = '\0'; + + fclose(ConfigFile); + + return hr; +} + +HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) +{ + char szPath[MAX_PATH] = { 0 }; + char *szLastBackslash = NULL; + + GetModuleFileName(NULL, szPath, MAX_PATH); + + szLastBackslash = strrchr(szPath, '\\'); + if (szLastBackslash == NULL) + return E_FAIL; + + strncpy_s(szExecDir, nMaxLength, szPath, strnlen_s(szPath, MAX_PATH) - strnlen_s(szLastBackslash, MAX_PATH)); + + return S_OK; +} + +static HRESULT DeleteDirectory(const char *szDirPath) +{ + HRESULT hr = S_OK; + BOOL bResult = FALSE; + DWORD dwError = 0; + + char szPattern[MAX_PATH] = { 0 }; + + WIN32_FIND_DATA FileInfo = { 0 }; + HANDLE hFile = INVALID_HANDLE_VALUE; + + strncpy_s(szPattern, MAX_PATH, szDirPath, _TRUNCATE); + strncat_s(szPattern, MAX_PATH, "\\*.*", _TRUNCATE); + + hFile = FindFirstFile(szPattern, &FileInfo); + if (hFile == INVALID_HANDLE_VALUE) + return E_FAIL; + + while (FindNextFile(hFile, &FileInfo)) + { + char szFilePath[MAX_PATH] = { 0 }; + + if (FileInfo.cFileName[0] == '.') + continue; + + strncpy_s(szFilePath, MAX_PATH, szDirPath, _TRUNCATE); + strncat_s(szFilePath, MAX_PATH, "\\", _TRUNCATE); + strncpy_s(szFilePath, MAX_PATH, FileInfo.cFileName, _TRUNCATE); + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + hr = DeleteDirectory(szFilePath); + if (FAILED(hr)) + return E_FAIL; + } + else + { + bResult = SetFileAttributes(szFilePath, FILE_ATTRIBUTE_NORMAL); + if (!bResult) + return E_FAIL; + + bResult = DeleteFile(szFilePath); + if (!bResult) + return E_FAIL; + } + } + + FindClose(hFile); + + dwError = GetLastError(); + if (dwError != ERROR_NO_MORE_FILES) + return E_FAIL; + + bResult = SetFileAttributes(szDirPath, FILE_ATTRIBUTE_NORMAL); + if (!bResult) + return E_FAIL; + + bResult = RemoveDirectory(szDirPath); + if (!bResult) + return E_FAIL; + + return S_OK; +} + +void Cleanup() +{ + HRESULT hr = S_OK; + char szPathToOnlineDir[MAX_PATH] = { 0 }; + char szPathToXLASTFile[MAX_PATH] = { 0 }; + + hr = GetExecDir(szPathToOnlineDir, MAX_PATH); + if (FAILED(hr)) + return; + + strncpy_s(szPathToXLASTFile, MAX_PATH, szPathToOnlineDir, _TRUNCATE); + strncat_s(szPathToXLASTFile, MAX_PATH, "\\tmp.xlast", _TRUNCATE); + strncat_s(szPathToOnlineDir, MAX_PATH, "\\Online", _TRUNCATE); + + DeleteDirectory(szPathToOnlineDir); + DeleteFile(szPathToXLASTFile); +} HRESULT BuildXLASTFile(const char *szGameName) { @@ -117,10 +254,33 @@ HRESULT ExecBLAST(const char *szXDKPath) char szErrorMsg[200] = { 0 }; strerror_s(szErrorMsg, 200, dwError); - LogError(szErrorMsg); + fputs(szErrorMsg, stderr); return E_FAIL; } return S_OK; } + +HRESULT CheckXBDMConnection() +{ + DWORD dwXboxNameSize = MAX_PATH; + char szXboxName[MAX_PATH]; + + return DmGetNameOfXbox(szXboxName, &dwXboxNameSize, TRUE); +} + +void ExitSuccess(const char *szMessage) +{ + fputs(szMessage, stderr); + + system("pause"); +} + +void ExitFailure(const char *szMessage) +{ + if (szMessage != NULL) + puts(szMessage); + + system("pause"); +} diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index 65dacad..9ed93ca 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -1,44 +1,21 @@ #pragma once -#include #include #include -#include "IO.h" +HRESULT GetGameName(char *szGameName, uint32_t nMaxLength); -HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) -{ - HRESULT hr = S_OK; - FILE *ConfigFile = NULL; - char szConfigFilePath[MAX_PATH] = { 0 }; - size_t nGameNameSize = 0; +HRESULT GetExecDir(char *szExecDir, size_t nMaxLength); - hr = GetExecDir(szConfigFilePath, MAX_PATH); - if (FAILED(hr)) - { - fputs("Failed to read exec dir", stderr); - return hr; - } +void Cleanup(); - strncat_s(szConfigFilePath, MAX_PATH, "\\config\\gameInfo.txt", _TRUNCATE); +HRESULT BuildXLASTFile(const char *szGameName); - if (fopen_s(&ConfigFile, szConfigFilePath, "r") != 0) - { - fprintf_s(stderr, "Failed to open config file at location %s\n", szConfigFilePath); - return E_FAIL; - } +HRESULT ExecBLAST(const char *szXDKPath); - if (fgets(szGameName, (int)nMaxLength, ConfigFile) == NULL) - { - fclose(ConfigFile); - return E_FAIL; - } +HRESULT CheckXBDMConnection(); - nGameNameSize = strnlen_s(szGameName, nMaxLength); - szGameName[nGameNameSize - 1] = '\0'; +void ExitSuccess(const char *szMessage); - fclose(ConfigFile); - - return hr; -} +void ExitFailure(const char *szMessage); diff --git a/Publisher/src/main.c b/Publisher/src/main.c index 7084bee..f0419f4 100644 --- a/Publisher/src/main.c +++ b/Publisher/src/main.c @@ -1,22 +1,4 @@ -#include - -#pragma warning(push) -#pragma warning(disable : 4214) -#include -#pragma warning(pop) - -#include "IO.h" #include "Utils.h" -#include "XLAST.h" -#include "Log.h" - -static HRESULT CheckXBDMConnection() -{ - DWORD dwXboxNameSize = MAX_PATH; - char szXboxName[MAX_PATH]; - - return DmGetNameOfXbox(szXboxName, &dwXboxNameSize, TRUE); -} int __cdecl main() { From 8b17cb601e88dc5cf5e8945bd2711341cd6bcaa3 Mon Sep 17 00:00:00 2001 From: Clement Date: Sat, 13 Aug 2022 14:20:41 +0200 Subject: [PATCH 13/30] Explicitly put void in parameters of functions that didn't take any --- Publisher/src/Utils.c | 4 ++-- Publisher/src/Utils.h | 4 ++-- Publisher/src/main.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index c4e6558..ee2ce45 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -126,7 +126,7 @@ static HRESULT DeleteDirectory(const char *szDirPath) return S_OK; } -void Cleanup() +void Cleanup(void) { HRESULT hr = S_OK; char szPathToOnlineDir[MAX_PATH] = { 0 }; @@ -262,7 +262,7 @@ HRESULT ExecBLAST(const char *szXDKPath) return S_OK; } -HRESULT CheckXBDMConnection() +HRESULT CheckXBDMConnection(void) { DWORD dwXboxNameSize = MAX_PATH; char szXboxName[MAX_PATH]; diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index 9ed93ca..40e8f35 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -8,13 +8,13 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength); HRESULT GetExecDir(char *szExecDir, size_t nMaxLength); -void Cleanup(); +void Cleanup(void); HRESULT BuildXLASTFile(const char *szGameName); HRESULT ExecBLAST(const char *szXDKPath); -HRESULT CheckXBDMConnection(); +HRESULT CheckXBDMConnection(void); void ExitSuccess(const char *szMessage); diff --git a/Publisher/src/main.c b/Publisher/src/main.c index f0419f4..33588de 100644 --- a/Publisher/src/main.c +++ b/Publisher/src/main.c @@ -1,6 +1,6 @@ #include "Utils.h" -int __cdecl main() +int main() { HRESULT hr = S_OK; errno_t err = 0; From 3e3294fb956f4260a9c2a3a2a8fd54e11895a323 Mon Sep 17 00:00:00 2001 From: Clement Date: Sat, 13 Aug 2022 19:50:23 +0200 Subject: [PATCH 14/30] Changed some variable names --- GameShortcut/src/main.c | 26 +++++++++++++------------- Publisher/src/Utils.c | 10 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/GameShortcut/src/main.c b/GameShortcut/src/main.c index 673a548..5ccb232 100644 --- a/GameShortcut/src/main.c +++ b/GameShortcut/src/main.c @@ -7,20 +7,20 @@ typedef struct { uint16_t wLength; uint16_t wMaxLength; - const char *szBuffer; + char *szBuffer; } STRING; -void RtlInitAnsiString(STRING *, const char *); -HRESULT ObCreateSymbolicLink(STRING *, STRING *); +void RtlInitAnsiString(STRING *pDestinationString, const char *szSourceString); +HRESULT ObCreateSymbolicLink(STRING *pLinkName, STRING *pDevicePath); static HRESULT MountHdd() { STRING DeviceName = { 0 }; STRING LinkName = { 0 }; const char *szDestDrive = "\\??\\hdd:"; - const char *szHddDeviceName = "\\Device\\Harddisk0\\Partition1\\"; + const char *szHddDevicePath = "\\Device\\Harddisk0\\Partition1\\"; - RtlInitAnsiString(&DeviceName, szHddDeviceName); + RtlInitAnsiString(&DeviceName, szHddDevicePath); RtlInitAnsiString(&LinkName, szDestDrive); return ObCreateSymbolicLink(&LinkName, &DeviceName); @@ -30,20 +30,20 @@ static HRESULT GetGamePath(char *szGamePath, uint32_t nMaxLength) { HRESULT hr = S_OK; size_t i = 0; - FILE *ConfigFile = NULL; + FILE *pConfigFile = NULL; size_t nGamePathSize = 0; - if (fopen_s(&ConfigFile, "game:\\config\\gameInfo.txt", "r") != 0) + if (fopen_s(&pConfigFile, "game:\\config\\gameInfo.txt", "r") != 0) return E_FAIL; for (i = 0; i < 2; i++) - if (fgets(szGamePath, (int)nMaxLength, ConfigFile) == NULL) + if (fgets(szGamePath, (int)nMaxLength, pConfigFile) == NULL) return E_FAIL; nGamePathSize = strnlen_s(szGamePath, nMaxLength); szGamePath[nGamePathSize - 1] = '\0'; - fclose(ConfigFile); + fclose(pConfigFile); return hr; } @@ -55,7 +55,7 @@ static HRESULT ShowMessageBoxError(const char *szMessage) wchar_t wszMessage[200] = { 0 }; XOVERLAPPED Overlapped = { 0 }; MESSAGEBOX_RESULT Result = { 0 }; - const wchar_t *pwstrButtons[] = { L"OK", L"Cancel" }; + const wchar_t *pwszButtons[] = { L"OK", L"Cancel" }; mbstowcs_s(NULL, wszMessage, 200, szMessage, _TRUNCATE); @@ -63,8 +63,8 @@ static HRESULT ShowMessageBoxError(const char *szMessage) 0, L"Error", wszMessage, - ARRAYSIZE(pwstrButtons), - pwstrButtons, + ARRAYSIZE(pwszButtons), + pwszButtons, 0, XMB_ERRORICON, &Result, @@ -85,7 +85,7 @@ static HRESULT ShowMessageBoxError(const char *szMessage) return S_OK; } -int __cdecl main() +int main() { HRESULT hr = S_OK; char szGamePath[MAX_PATH] = { 0 }; diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index ee2ce45..6d3e0bc 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -13,7 +13,7 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) { HRESULT hr = S_OK; - FILE *ConfigFile = NULL; + FILE *pConfigFile = NULL; char szConfigFilePath[MAX_PATH] = { 0 }; size_t nGameNameSize = 0; @@ -26,22 +26,22 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) strncat_s(szConfigFilePath, MAX_PATH, "\\config\\gameInfo.txt", _TRUNCATE); - if (fopen_s(&ConfigFile, szConfigFilePath, "r") != 0) + if (fopen_s(&pConfigFile, szConfigFilePath, "r") != 0) { fprintf_s(stderr, "Failed to open config file at location %s\n", szConfigFilePath); return E_FAIL; } - if (fgets(szGameName, (int)nMaxLength, ConfigFile) == NULL) + if (fgets(szGameName, (int)nMaxLength, pConfigFile) == NULL) { - fclose(ConfigFile); + fclose(pConfigFile); return E_FAIL; } nGameNameSize = strnlen_s(szGameName, nMaxLength); szGameName[nGameNameSize - 1] = '\0'; - fclose(ConfigFile); + fclose(pConfigFile); return hr; } From a597ee4791273b2407b02993390ed511c3ca422c Mon Sep 17 00:00:00 2001 From: Clement Date: Sat, 13 Aug 2022 20:35:30 +0200 Subject: [PATCH 15/30] Added some more error handling and made error message more accurate --- Publisher/src/Utils.c | 84 ++++++++++++++++++++++++++++++++----------- Publisher/src/Utils.h | 4 --- Publisher/src/main.c | 12 +++---- 3 files changed, 70 insertions(+), 30 deletions(-) diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index 6d3e0bc..cecd0b5 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -17,10 +17,16 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) char szConfigFilePath[MAX_PATH] = { 0 }; size_t nGameNameSize = 0; + if (szGameName != NULL) + { + fputs("szGameName is NULL", stderr); + return E_FAIL; + } + hr = GetExecDir(szConfigFilePath, MAX_PATH); if (FAILED(hr)) { - fputs("Failed to read exec dir", stderr); + fputs("Failed to read execution diriectory", stderr); return hr; } @@ -34,6 +40,7 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) if (fgets(szGameName, (int)nMaxLength, pConfigFile) == NULL) { + fprintf_s(stderr, "Failed to read from config file at location %s\n", szConfigFilePath); fclose(pConfigFile); return E_FAIL; } @@ -51,6 +58,12 @@ HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) char szPath[MAX_PATH] = { 0 }; char *szLastBackslash = NULL; + if (szExecDir == NULL) + { + fputs("szExecDir is NULL", stderr); + return E_FAIL; + } + GetModuleFileName(NULL, szPath, MAX_PATH); szLastBackslash = strrchr(szPath, '\\'); @@ -73,12 +86,21 @@ static HRESULT DeleteDirectory(const char *szDirPath) WIN32_FIND_DATA FileInfo = { 0 }; HANDLE hFile = INVALID_HANDLE_VALUE; + if (szDirPath == NULL) + { + fputs("szDirPath is NULL", stderr); + return E_FAIL; + } + strncpy_s(szPattern, MAX_PATH, szDirPath, _TRUNCATE); strncat_s(szPattern, MAX_PATH, "\\*.*", _TRUNCATE); hFile = FindFirstFile(szPattern, &FileInfo); if (hFile == INVALID_HANDLE_VALUE) + { + fprintf_s(stderr, "Could not find file at location %s\n", szDirPath); return E_FAIL; + } while (FindNextFile(hFile, &FileInfo)) { @@ -101,11 +123,17 @@ static HRESULT DeleteDirectory(const char *szDirPath) { bResult = SetFileAttributes(szFilePath, FILE_ATTRIBUTE_NORMAL); if (!bResult) + { + fprintf_s(stderr, "Could not set file attributes of %s\n", szFilePath); return E_FAIL; + } bResult = DeleteFile(szFilePath); if (!bResult) + { + fprintf_s(stderr, "Could not delete %s\n", szFilePath); return E_FAIL; + } } } @@ -117,11 +145,17 @@ static HRESULT DeleteDirectory(const char *szDirPath) bResult = SetFileAttributes(szDirPath, FILE_ATTRIBUTE_NORMAL); if (!bResult) + { + fprintf_s(stderr, "Could not set file attributes of %s\n", szDirPath); return E_FAIL; + } bResult = RemoveDirectory(szDirPath); if (!bResult) + { + fprintf_s(stderr, "Could not delete %s\n", szDirPath); return E_FAIL; + } return S_OK; } @@ -159,7 +193,7 @@ HRESULT BuildXLASTFile(const char *szGameName) size_t nWCharCount = 0; size_t nWritten = 0; FILE *pFile = NULL; - wchar_t *wszFileContent = (wchar_t *)malloc(2048 * sizeof(wchar_t)); + wchar_t *wszFileContent = NULL; const wchar_t *wszFileContentFormat = L"\n" L"\n" @@ -177,15 +211,25 @@ HRESULT BuildXLASTFile(const char *szGameName) L" \n" L""; + if (szGameName == NULL) + { + fputs("szGameName is NULL", stderr); + return E_FAIL; + } + + wszFileContent = (wchar_t *)malloc(2048 * sizeof(wchar_t)); + if (wszFileContent == NULL) + { + fputs("Allocating memory for XLAST file content failed", stderr); + return E_FAIL; + } + mbstowcs_s(NULL, wszGameName, 50, szGameName, _TRUNCATE); _snwprintf_s(wszRandomNumber, 9, 9, L"%08x", nRandomNumber); for (i = 0; i < 9; i++) wszRandomNumber[i] = towlower(wszRandomNumber[i]); - if (wszFileContent == NULL) - return E_FAIL; - _snwprintf_s(wszFileContent, 2048, 2048, wszFileContentFormat, wszGameName, wszRandomNumber, wszGameName, wszGameName, wszGameName); hr = GetExecDir(szFilePath, MAX_PATH); @@ -196,13 +240,17 @@ HRESULT BuildXLASTFile(const char *szGameName) fopen_s(&pFile, szFilePath, "w+, ccs=UTF-16LE"); if (pFile == NULL) + { + fprintf_s(stderr, "Could not open XLAST file at location %s\n", szFilePath); return E_FAIL; + } nWCharCount = wcsnlen_s(wszFileContent, 2048); nWritten = fwrite(wszFileContent, sizeof(wchar_t), nWCharCount, pFile); if (nWritten != nWCharCount) { + fprintf_s(stderr, "Could not write XLAST file, was expecting to write %llu characters but wrote %llu\n", nWCharCount, nWritten); fclose(pFile); return E_FAIL; } @@ -225,6 +273,12 @@ HRESULT ExecBLAST(const char *szXDKPath) SHELLEXECUTEINFO ShExecInfo = { 0 }; + if (szXDKPath == NULL) + { + fputs("szXDKPath is NULL", stderr); + return E_FAIL; + } + hr = GetExecDir(szExecDirBuffer, MAX_PATH); if (FAILED(hr)) return E_FAIL; @@ -264,23 +318,13 @@ HRESULT ExecBLAST(const char *szXDKPath) HRESULT CheckXBDMConnection(void) { + HRESULT hr = S_OK; DWORD dwXboxNameSize = MAX_PATH; char szXboxName[MAX_PATH]; - return DmGetNameOfXbox(szXboxName, &dwXboxNameSize, TRUE); -} - -void ExitSuccess(const char *szMessage) -{ - fputs(szMessage, stderr); - - system("pause"); -} - -void ExitFailure(const char *szMessage) -{ - if (szMessage != NULL) - puts(szMessage); + hr = DmGetNameOfXbox(szXboxName, &dwXboxNameSize, TRUE); + if (FAILED(hr)) + fputs("Could not connect to console", stderr); - system("pause"); + return hr; } diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index 40e8f35..c0ace84 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -15,7 +15,3 @@ HRESULT BuildXLASTFile(const char *szGameName); HRESULT ExecBLAST(const char *szXDKPath); HRESULT CheckXBDMConnection(void); - -void ExitSuccess(const char *szMessage); - -void ExitFailure(const char *szMessage); diff --git a/Publisher/src/main.c b/Publisher/src/main.c index 33588de..a22e37a 100644 --- a/Publisher/src/main.c +++ b/Publisher/src/main.c @@ -12,28 +12,28 @@ int main() err = _dupenv_s(&szXDKPath, &nXDKPathSize, "xedk"); if (szXDKPath == NULL || err != 0) { - ExitFailure("You must have the Xbox 360 Development Kit (XDK) installed on your computer."); + system("pause"); return EXIT_FAILURE; } hr = CheckXBDMConnection(); if (FAILED(hr)) { - ExitFailure("Could not connect to console."); + system("pause"); return EXIT_FAILURE; } hr = GetGameName(szGameName, sizeof(szGameName)); if (FAILED(hr)) { - ExitFailure("The game information file (config\\gameInfo.txt) could not be loaded or has a wrong format."); + system("pause"); return EXIT_FAILURE; } hr = BuildXLASTFile(szGameName); if (FAILED(hr)) { - ExitFailure("Could not generate the XLAST file."); + system("pause"); return EXIT_FAILURE; } @@ -41,13 +41,13 @@ int main() if (FAILED(hr)) { Cleanup(); - ExitFailure("Could not execute BLAST."); + system("pause"); return EXIT_FAILURE; } Cleanup(); - ExitSuccess(NULL); + system("pause"); return EXIT_SUCCESS; } From 589dfe66557977fccde7c86fe412dee5022e0151 Mon Sep 17 00:00:00 2001 From: Clement Date: Mon, 15 Aug 2022 00:43:22 +0200 Subject: [PATCH 16/30] Added comment everywhere to explain the code --- GameShortcut/src/main.c | 18 ++++++++++ Publisher/src/Utils.c | 77 +++++++++++++++++++++++++++++++---------- Publisher/src/Utils.h | 6 ++++ 3 files changed, 82 insertions(+), 19 deletions(-) diff --git a/GameShortcut/src/main.c b/GameShortcut/src/main.c index 5ccb232..4d0a6d9 100644 --- a/GameShortcut/src/main.c +++ b/GameShortcut/src/main.c @@ -3,6 +3,7 @@ #include +// Structs and function prototypes from xboxkrnl.exe typedef struct { uint16_t wLength; @@ -13,6 +14,9 @@ typedef struct void RtlInitAnsiString(STRING *pDestinationString, const char *szSourceString); HRESULT ObCreateSymbolicLink(STRING *pLinkName, STRING *pDevicePath); +// Allow the game to access the entire hard drive. +// The system only allows executables to access the directory they live in and binds it to +// the "game:" drive. Everything else if not accessible unless you create a symbolic link. static HRESULT MountHdd() { STRING DeviceName = { 0 }; @@ -20,12 +24,15 @@ static HRESULT MountHdd() const char *szDestDrive = "\\??\\hdd:"; const char *szHddDevicePath = "\\Device\\Harddisk0\\Partition1\\"; + // Initialize the STRING structs RtlInitAnsiString(&DeviceName, szHddDevicePath); RtlInitAnsiString(&LinkName, szDestDrive); + // Bind the root of the hard drive to the "hdd:" drive. return ObCreateSymbolicLink(&LinkName, &DeviceName); } +// Read the path to the executable from the config file and write it to szGamePath. static HRESULT GetGamePath(char *szGamePath, uint32_t nMaxLength) { HRESULT hr = S_OK; @@ -33,14 +40,18 @@ static HRESULT GetGamePath(char *szGamePath, uint32_t nMaxLength) FILE *pConfigFile = NULL; size_t nGamePathSize = 0; + // Open the config file in read-only mode if (fopen_s(&pConfigFile, "game:\\config\\gameInfo.txt", "r") != 0) return E_FAIL; + // Read the second line of the config file into szGamePath for (i = 0; i < 2; i++) if (fgets(szGamePath, (int)nMaxLength, pConfigFile) == NULL) return E_FAIL; nGamePathSize = strnlen_s(szGamePath, nMaxLength); + + // Remove the new line character at the end of the line szGamePath[nGamePathSize - 1] = '\0'; fclose(pConfigFile); @@ -48,6 +59,7 @@ static HRESULT GetGamePath(char *szGamePath, uint32_t nMaxLength) return hr; } +// Display an error dialog on the console. static HRESULT ShowMessageBoxError(const char *szMessage) { DWORD dwResult = 0; @@ -57,6 +69,7 @@ static HRESULT ShowMessageBoxError(const char *szMessage) MESSAGEBOX_RESULT Result = { 0 }; const wchar_t *pwszButtons[] = { L"OK", L"Cancel" }; + // Convert szMessage, which is a narrow string, to a wide string mbstowcs_s(NULL, wszMessage, 200, szMessage, _TRUNCATE); dwResult = XShowMessageBoxUI( @@ -74,9 +87,11 @@ static HRESULT ShowMessageBoxError(const char *szMessage) if (dwResult != ERROR_IO_PENDING) return E_FAIL; + // Wait until the user closes the dialog while (!XHasOverlappedIoCompleted(&Overlapped)) Sleep(100); + // Get how the user closed the dialog (by clicking "OK", "Cancel" or the Xbox button on the controller dwResult = XGetOverlappedResult(&Overlapped, NULL, TRUE); if (dwResult == ERROR_ACCESS_DENIED) @@ -90,6 +105,7 @@ int main() HRESULT hr = S_OK; char szGamePath[MAX_PATH] = { 0 }; + // Mount the entire hard drive to be able to access any path in it hr = MountHdd(); if (FAILED(hr)) { @@ -97,6 +113,7 @@ int main() return EXIT_FAILURE; } + // Read the path to the executable hr = GetGamePath(szGamePath, MAX_PATH); if (FAILED(hr)) { @@ -104,5 +121,6 @@ int main() return EXIT_FAILURE; } + // Launch the executable XLaunchNewImage(szGamePath, 0); } diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index cecd0b5..48131bb 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -30,14 +30,18 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) return hr; } + // Append the path to the config file to the executable directory to get the + // absolute path to the config file strncat_s(szConfigFilePath, MAX_PATH, "\\config\\gameInfo.txt", _TRUNCATE); + // Open the config file in read-only mode if (fopen_s(&pConfigFile, szConfigFilePath, "r") != 0) { fprintf_s(stderr, "Failed to open config file at location %s\n", szConfigFilePath); return E_FAIL; } + // Read the first line of the config file, which contains the shortcut name, into szGameName if (fgets(szGameName, (int)nMaxLength, pConfigFile) == NULL) { fprintf_s(stderr, "Failed to read from config file at location %s\n", szConfigFilePath); @@ -46,6 +50,8 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) } nGameNameSize = strnlen_s(szGameName, nMaxLength); + + // Remove the new line character at the end of the line szGameName[nGameNameSize - 1] = '\0'; fclose(pConfigFile); @@ -57,6 +63,7 @@ HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) { char szPath[MAX_PATH] = { 0 }; char *szLastBackslash = NULL; + size_t nExecDirPathLength = 0; if (szExecDir == NULL) { @@ -64,17 +71,24 @@ HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) return E_FAIL; } + // Get the absolute path to the Publisher executable GetModuleFileName(NULL, szPath, MAX_PATH); + // Get a pointer to the last backslash in the path szLastBackslash = strrchr(szPath, '\\'); + + // It should not happen but just in case no blackslashes were found, return if (szLastBackslash == NULL) return E_FAIL; - strncpy_s(szExecDir, nMaxLength, szPath, strnlen_s(szPath, MAX_PATH) - strnlen_s(szLastBackslash, MAX_PATH)); + // Copy szPath into szExecDir but only up until the last backslash + nExecDirPathLength = strnlen_s(szPath, MAX_PATH) - strnlen_s(szLastBackslash, MAX_PATH); + strncpy_s(szExecDir, nMaxLength, szPath, nExecDirPathLength); return S_OK; } +// Delete a directory and all of its files/subdirectories. static HRESULT DeleteDirectory(const char *szDirPath) { HRESULT hr = S_OK; @@ -92,9 +106,11 @@ static HRESULT DeleteDirectory(const char *szDirPath) return E_FAIL; } + // Create the pattern to start searching the files strncpy_s(szPattern, MAX_PATH, szDirPath, _TRUNCATE); strncat_s(szPattern, MAX_PATH, "\\*.*", _TRUNCATE); + // Find the first file corresponding to the pattern hFile = FindFirstFile(szPattern, &FileInfo); if (hFile == INVALID_HANDLE_VALUE) { @@ -102,17 +118,21 @@ static HRESULT DeleteDirectory(const char *szDirPath) return E_FAIL; } + // Loop as long as there are files in the directory while (FindNextFile(hFile, &FileInfo)) { char szFilePath[MAX_PATH] = { 0 }; - if (FileInfo.cFileName[0] == '.') + // Don't try to get "." (current directory) or ".." (parent directory) + if (!strcmp(FileInfo.cFileName, ".") || !strcmp(FileInfo.cFileName, "..")) continue; + // Create the full path to the current file to delete strncpy_s(szFilePath, MAX_PATH, szDirPath, _TRUNCATE); strncat_s(szFilePath, MAX_PATH, "\\", _TRUNCATE); - strncpy_s(szFilePath, MAX_PATH, FileInfo.cFileName, _TRUNCATE); + strncat_s(szFilePath, MAX_PATH, FileInfo.cFileName, _TRUNCATE); + // If the current file is a directory, start the recursion if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { hr = DeleteDirectory(szFilePath); @@ -121,13 +141,7 @@ static HRESULT DeleteDirectory(const char *szDirPath) } else { - bResult = SetFileAttributes(szFilePath, FILE_ATTRIBUTE_NORMAL); - if (!bResult) - { - fprintf_s(stderr, "Could not set file attributes of %s\n", szFilePath); - return E_FAIL; - } - + // Delete the file bResult = DeleteFile(szFilePath); if (!bResult) { @@ -139,17 +153,12 @@ static HRESULT DeleteDirectory(const char *szDirPath) FindClose(hFile); + // Check for errors dwError = GetLastError(); if (dwError != ERROR_NO_MORE_FILES) return E_FAIL; - bResult = SetFileAttributes(szDirPath, FILE_ATTRIBUTE_NORMAL); - if (!bResult) - { - fprintf_s(stderr, "Could not set file attributes of %s\n", szDirPath); - return E_FAIL; - } - + // Remove the directory once it's empty bResult = RemoveDirectory(szDirPath); if (!bResult) { @@ -166,14 +175,19 @@ void Cleanup(void) char szPathToOnlineDir[MAX_PATH] = { 0 }; char szPathToXLASTFile[MAX_PATH] = { 0 }; + // Read the executable directory path and write it to szPathToOnlineDir hr = GetExecDir(szPathToOnlineDir, MAX_PATH); if (FAILED(hr)) return; + // Copy the executable directory path (which lives in szPathToOnlineDir) into szPathToXLASTFile strncpy_s(szPathToXLASTFile, MAX_PATH, szPathToOnlineDir, _TRUNCATE); + + // Finish the paths to the XLAST file and Online directory strncat_s(szPathToXLASTFile, MAX_PATH, "\\tmp.xlast", _TRUNCATE); strncat_s(szPathToOnlineDir, MAX_PATH, "\\Online", _TRUNCATE); + // Delete the Online directory and the XLAST config file DeleteDirectory(szPathToOnlineDir); DeleteFile(szPathToXLASTFile); } @@ -185,6 +199,7 @@ HRESULT BuildXLASTFile(const char *szGameName) char szFilePath[MAX_PATH] = { 0 }; wchar_t wszGameName[50] = { 0 }; + // TODO: create an actual random number, based on the shortcut name if possible uint32_t nRandomNumber = 0x12345678; wchar_t wszRandomNumber[9] = { 0 }; @@ -217,6 +232,7 @@ HRESULT BuildXLASTFile(const char *szGameName) return E_FAIL; } + // Allocate enough memory on the heap to hold the config file content wszFileContent = (wchar_t *)malloc(2048 * sizeof(wchar_t)); if (wszFileContent == NULL) { @@ -224,20 +240,28 @@ HRESULT BuildXLASTFile(const char *szGameName) return E_FAIL; } + // Convert szGameName, which is a narrow string, to a wide string mbstowcs_s(NULL, wszGameName, 50, szGameName, _TRUNCATE); + + // Write the string representation of the random number in wszRandomNumber _snwprintf_s(wszRandomNumber, 9, 9, L"%08x", nRandomNumber); + // Convert the string representation of the random number to uppercase for (i = 0; i < 9; i++) - wszRandomNumber[i] = towlower(wszRandomNumber[i]); + wszRandomNumber[i] = towupper(wszRandomNumber[i]); + // Create the actual config file content from the game name and the random number and write it to wszFileContent _snwprintf_s(wszFileContent, 2048, 2048, wszFileContentFormat, wszGameName, wszRandomNumber, wszGameName, wszGameName, wszGameName); + // Read the executable directory path and write it to szFilePath hr = GetExecDir(szFilePath, MAX_PATH); if (FAILED(hr)) return E_FAIL; + // Append the config file name to the executable directory path to get the absolute path to the config file strncat_s(szFilePath, MAX_PATH, "\\tmp.xlast", _TRUNCATE); + // Open the config file in write mode and create it if it doesn't exist (which should always be the case) fopen_s(&pFile, szFilePath, "w+, ccs=UTF-16LE"); if (pFile == NULL) { @@ -245,9 +269,13 @@ HRESULT BuildXLASTFile(const char *szGameName) return E_FAIL; } - nWCharCount = wcsnlen_s(wszFileContent, 2048); + // Write the config file content to the actual file on disk and get the amount of characters written nWritten = fwrite(wszFileContent, sizeof(wchar_t), nWCharCount, pFile); + // Get the amount of characters that are supposed to be written + nWCharCount = wcsnlen_s(wszFileContent, 2048); + + // Make sure all characters from the config file content were written to disk if (nWritten != nWCharCount) { fprintf_s(stderr, "Could not write XLAST file, was expecting to write %llu characters but wrote %llu\n", nWCharCount, nWritten); @@ -255,6 +283,7 @@ HRESULT BuildXLASTFile(const char *szGameName) return E_FAIL; } + // Close the config file and free the buffer that was holding its content fclose(pFile); free(wszFileContent); @@ -279,16 +308,20 @@ HRESULT ExecBLAST(const char *szXDKPath) return E_FAIL; } + // Read the executable directory path and write it to szExecDirBuffer hr = GetExecDir(szExecDirBuffer, MAX_PATH); if (FAILED(hr)) return E_FAIL; + // Create the full list of parameters to pass to BLAST strncpy_s(szBLASTParameters, MAX_PATH, szExecDirBuffer, _TRUNCATE); strncat_s(szBLASTParameters, MAX_PATH, "\\tmp.xlast /build /install:Local /nologo", _TRUNCATE); + // Create the absolute path to the BLAST executable strncpy_s(szBLASTPath, MAX_PATH, szXDKPath, _TRUNCATE); strncat_s(szBLASTPath, MAX_PATH, "\\bin\\win32\\blast.exe", _TRUNCATE); + // Populate the SHELLEXECUTEINFO struct ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_NO_CONSOLE; ShExecInfo.hwnd = NULL; @@ -298,10 +331,15 @@ HRESULT ExecBLAST(const char *szXDKPath) ShExecInfo.lpDirectory = szExecDirBuffer; ShExecInfo.nShow = SW_SHOW; ShExecInfo.hInstApp = NULL; + + // Execute the command ShellExecuteEx(&ShExecInfo); + + // Wait for the command's process to complete WaitForSingleObject(ShExecInfo.hProcess, INFINITE); CloseHandle(ShExecInfo.hProcess); + // Get the status code returned by the BLAST process and check if it returned an error if ((int)ShExecInfo.hInstApp <= 32) { DWORD dwError = GetLastError(); @@ -322,6 +360,7 @@ HRESULT CheckXBDMConnection(void) DWORD dwXboxNameSize = MAX_PATH; char szXboxName[MAX_PATH]; + // Get the name of the default Xbox 360 set up in Neighborhood hr = DmGetNameOfXbox(szXboxName, &dwXboxNameSize, TRUE); if (FAILED(hr)) fputs("Could not connect to console", stderr); diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index c0ace84..68083b1 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -4,14 +4,20 @@ #include +// Read the name of the shortcut from the config file and write it to szGameName. HRESULT GetGameName(char *szGameName, uint32_t nMaxLength); +// Get the path of the directory the Publisher executable lives in and write it to szGameName. HRESULT GetExecDir(char *szExecDir, size_t nMaxLength); +// Delete the XLAST files generated by Publisher. void Cleanup(void); +// Create the XML config file XLAST uses to build the shortcut. HRESULT BuildXLASTFile(const char *szGameName); +// Run BLAST in a separate process. HRESULT ExecBLAST(const char *szXDKPath); +// Make sure an XBDM connection is properly set up. HRESULT CheckXBDMConnection(void); From d088a4ad9a70f956b86da4b2bb20604f6d02238a Mon Sep 17 00:00:00 2001 From: Clement Date: Mon, 15 Aug 2022 00:50:43 +0200 Subject: [PATCH 17/30] Change the function order in Utils.h and Utils.c --- Publisher/src/Utils.c | 364 +++++++++++++++++++++--------------------- Publisher/src/Utils.h | 18 +-- 2 files changed, 191 insertions(+), 191 deletions(-) diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index 48131bb..f5de5c2 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -10,188 +10,6 @@ #include "Utils.h" -HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) -{ - HRESULT hr = S_OK; - FILE *pConfigFile = NULL; - char szConfigFilePath[MAX_PATH] = { 0 }; - size_t nGameNameSize = 0; - - if (szGameName != NULL) - { - fputs("szGameName is NULL", stderr); - return E_FAIL; - } - - hr = GetExecDir(szConfigFilePath, MAX_PATH); - if (FAILED(hr)) - { - fputs("Failed to read execution diriectory", stderr); - return hr; - } - - // Append the path to the config file to the executable directory to get the - // absolute path to the config file - strncat_s(szConfigFilePath, MAX_PATH, "\\config\\gameInfo.txt", _TRUNCATE); - - // Open the config file in read-only mode - if (fopen_s(&pConfigFile, szConfigFilePath, "r") != 0) - { - fprintf_s(stderr, "Failed to open config file at location %s\n", szConfigFilePath); - return E_FAIL; - } - - // Read the first line of the config file, which contains the shortcut name, into szGameName - if (fgets(szGameName, (int)nMaxLength, pConfigFile) == NULL) - { - fprintf_s(stderr, "Failed to read from config file at location %s\n", szConfigFilePath); - fclose(pConfigFile); - return E_FAIL; - } - - nGameNameSize = strnlen_s(szGameName, nMaxLength); - - // Remove the new line character at the end of the line - szGameName[nGameNameSize - 1] = '\0'; - - fclose(pConfigFile); - - return hr; -} - -HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) -{ - char szPath[MAX_PATH] = { 0 }; - char *szLastBackslash = NULL; - size_t nExecDirPathLength = 0; - - if (szExecDir == NULL) - { - fputs("szExecDir is NULL", stderr); - return E_FAIL; - } - - // Get the absolute path to the Publisher executable - GetModuleFileName(NULL, szPath, MAX_PATH); - - // Get a pointer to the last backslash in the path - szLastBackslash = strrchr(szPath, '\\'); - - // It should not happen but just in case no blackslashes were found, return - if (szLastBackslash == NULL) - return E_FAIL; - - // Copy szPath into szExecDir but only up until the last backslash - nExecDirPathLength = strnlen_s(szPath, MAX_PATH) - strnlen_s(szLastBackslash, MAX_PATH); - strncpy_s(szExecDir, nMaxLength, szPath, nExecDirPathLength); - - return S_OK; -} - -// Delete a directory and all of its files/subdirectories. -static HRESULT DeleteDirectory(const char *szDirPath) -{ - HRESULT hr = S_OK; - BOOL bResult = FALSE; - DWORD dwError = 0; - - char szPattern[MAX_PATH] = { 0 }; - - WIN32_FIND_DATA FileInfo = { 0 }; - HANDLE hFile = INVALID_HANDLE_VALUE; - - if (szDirPath == NULL) - { - fputs("szDirPath is NULL", stderr); - return E_FAIL; - } - - // Create the pattern to start searching the files - strncpy_s(szPattern, MAX_PATH, szDirPath, _TRUNCATE); - strncat_s(szPattern, MAX_PATH, "\\*.*", _TRUNCATE); - - // Find the first file corresponding to the pattern - hFile = FindFirstFile(szPattern, &FileInfo); - if (hFile == INVALID_HANDLE_VALUE) - { - fprintf_s(stderr, "Could not find file at location %s\n", szDirPath); - return E_FAIL; - } - - // Loop as long as there are files in the directory - while (FindNextFile(hFile, &FileInfo)) - { - char szFilePath[MAX_PATH] = { 0 }; - - // Don't try to get "." (current directory) or ".." (parent directory) - if (!strcmp(FileInfo.cFileName, ".") || !strcmp(FileInfo.cFileName, "..")) - continue; - - // Create the full path to the current file to delete - strncpy_s(szFilePath, MAX_PATH, szDirPath, _TRUNCATE); - strncat_s(szFilePath, MAX_PATH, "\\", _TRUNCATE); - strncat_s(szFilePath, MAX_PATH, FileInfo.cFileName, _TRUNCATE); - - // If the current file is a directory, start the recursion - if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - hr = DeleteDirectory(szFilePath); - if (FAILED(hr)) - return E_FAIL; - } - else - { - // Delete the file - bResult = DeleteFile(szFilePath); - if (!bResult) - { - fprintf_s(stderr, "Could not delete %s\n", szFilePath); - return E_FAIL; - } - } - } - - FindClose(hFile); - - // Check for errors - dwError = GetLastError(); - if (dwError != ERROR_NO_MORE_FILES) - return E_FAIL; - - // Remove the directory once it's empty - bResult = RemoveDirectory(szDirPath); - if (!bResult) - { - fprintf_s(stderr, "Could not delete %s\n", szDirPath); - return E_FAIL; - } - - return S_OK; -} - -void Cleanup(void) -{ - HRESULT hr = S_OK; - char szPathToOnlineDir[MAX_PATH] = { 0 }; - char szPathToXLASTFile[MAX_PATH] = { 0 }; - - // Read the executable directory path and write it to szPathToOnlineDir - hr = GetExecDir(szPathToOnlineDir, MAX_PATH); - if (FAILED(hr)) - return; - - // Copy the executable directory path (which lives in szPathToOnlineDir) into szPathToXLASTFile - strncpy_s(szPathToXLASTFile, MAX_PATH, szPathToOnlineDir, _TRUNCATE); - - // Finish the paths to the XLAST file and Online directory - strncat_s(szPathToXLASTFile, MAX_PATH, "\\tmp.xlast", _TRUNCATE); - strncat_s(szPathToOnlineDir, MAX_PATH, "\\Online", _TRUNCATE); - - // Delete the Online directory and the XLAST config file - DeleteDirectory(szPathToOnlineDir); - DeleteFile(szPathToXLASTFile); -} - HRESULT BuildXLASTFile(const char *szGameName) { HRESULT hr = S_OK; @@ -354,6 +172,84 @@ HRESULT ExecBLAST(const char *szXDKPath) return S_OK; } +HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) +{ + char szPath[MAX_PATH] = { 0 }; + char *szLastBackslash = NULL; + size_t nExecDirPathLength = 0; + + if (szExecDir == NULL) + { + fputs("szExecDir is NULL", stderr); + return E_FAIL; + } + + // Get the absolute path to the Publisher executable + GetModuleFileName(NULL, szPath, MAX_PATH); + + // Get a pointer to the last backslash in the path + szLastBackslash = strrchr(szPath, '\\'); + + // It should not happen but just in case no blackslashes were found, return + if (szLastBackslash == NULL) + return E_FAIL; + + // Copy szPath into szExecDir but only up until the last backslash + nExecDirPathLength = strnlen_s(szPath, MAX_PATH) - strnlen_s(szLastBackslash, MAX_PATH); + strncpy_s(szExecDir, nMaxLength, szPath, nExecDirPathLength); + + return S_OK; +} + +HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) +{ + HRESULT hr = S_OK; + FILE *pConfigFile = NULL; + char szConfigFilePath[MAX_PATH] = { 0 }; + size_t nGameNameSize = 0; + + if (szGameName != NULL) + { + fputs("szGameName is NULL", stderr); + return E_FAIL; + } + + hr = GetExecDir(szConfigFilePath, MAX_PATH); + if (FAILED(hr)) + { + fputs("Failed to read execution diriectory", stderr); + return hr; + } + + // Append the path to the config file to the executable directory to get the + // absolute path to the config file + strncat_s(szConfigFilePath, MAX_PATH, "\\config\\gameInfo.txt", _TRUNCATE); + + // Open the config file in read-only mode + if (fopen_s(&pConfigFile, szConfigFilePath, "r") != 0) + { + fprintf_s(stderr, "Failed to open config file at location %s\n", szConfigFilePath); + return E_FAIL; + } + + // Read the first line of the config file, which contains the shortcut name, into szGameName + if (fgets(szGameName, (int)nMaxLength, pConfigFile) == NULL) + { + fprintf_s(stderr, "Failed to read from config file at location %s\n", szConfigFilePath); + fclose(pConfigFile); + return E_FAIL; + } + + nGameNameSize = strnlen_s(szGameName, nMaxLength); + + // Remove the new line character at the end of the line + szGameName[nGameNameSize - 1] = '\0'; + + fclose(pConfigFile); + + return hr; +} + HRESULT CheckXBDMConnection(void) { HRESULT hr = S_OK; @@ -367,3 +263,107 @@ HRESULT CheckXBDMConnection(void) return hr; } + +// Delete a directory and all of its files/subdirectories. +static HRESULT DeleteDirectory(const char *szDirPath) +{ + HRESULT hr = S_OK; + BOOL bResult = FALSE; + DWORD dwError = 0; + + char szPattern[MAX_PATH] = { 0 }; + + WIN32_FIND_DATA FileInfo = { 0 }; + HANDLE hFile = INVALID_HANDLE_VALUE; + + if (szDirPath == NULL) + { + fputs("szDirPath is NULL", stderr); + return E_FAIL; + } + + // Create the pattern to start searching the files + strncpy_s(szPattern, MAX_PATH, szDirPath, _TRUNCATE); + strncat_s(szPattern, MAX_PATH, "\\*.*", _TRUNCATE); + + // Find the first file corresponding to the pattern + hFile = FindFirstFile(szPattern, &FileInfo); + if (hFile == INVALID_HANDLE_VALUE) + { + fprintf_s(stderr, "Could not find file at location %s\n", szDirPath); + return E_FAIL; + } + + // Loop as long as there are files in the directory + while (FindNextFile(hFile, &FileInfo)) + { + char szFilePath[MAX_PATH] = { 0 }; + + // Don't try to get "." (current directory) or ".." (parent directory) + if (!strcmp(FileInfo.cFileName, ".") || !strcmp(FileInfo.cFileName, "..")) + continue; + + // Create the full path to the current file to delete + strncpy_s(szFilePath, MAX_PATH, szDirPath, _TRUNCATE); + strncat_s(szFilePath, MAX_PATH, "\\", _TRUNCATE); + strncat_s(szFilePath, MAX_PATH, FileInfo.cFileName, _TRUNCATE); + + // If the current file is a directory, start the recursion + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + hr = DeleteDirectory(szFilePath); + if (FAILED(hr)) + return E_FAIL; + } + else + { + // Delete the file + bResult = DeleteFile(szFilePath); + if (!bResult) + { + fprintf_s(stderr, "Could not delete %s\n", szFilePath); + return E_FAIL; + } + } + } + + FindClose(hFile); + + // Check for errors + dwError = GetLastError(); + if (dwError != ERROR_NO_MORE_FILES) + return E_FAIL; + + // Remove the directory once it's empty + bResult = RemoveDirectory(szDirPath); + if (!bResult) + { + fprintf_s(stderr, "Could not delete %s\n", szDirPath); + return E_FAIL; + } + + return S_OK; +} + +void Cleanup(void) +{ + HRESULT hr = S_OK; + char szPathToOnlineDir[MAX_PATH] = { 0 }; + char szPathToXLASTFile[MAX_PATH] = { 0 }; + + // Read the executable directory path and write it to szPathToOnlineDir + hr = GetExecDir(szPathToOnlineDir, MAX_PATH); + if (FAILED(hr)) + return; + + // Copy the executable directory path (which lives in szPathToOnlineDir) into szPathToXLASTFile + strncpy_s(szPathToXLASTFile, MAX_PATH, szPathToOnlineDir, _TRUNCATE); + + // Finish the paths to the XLAST file and Online directory + strncat_s(szPathToXLASTFile, MAX_PATH, "\\tmp.xlast", _TRUNCATE); + strncat_s(szPathToOnlineDir, MAX_PATH, "\\Online", _TRUNCATE); + + // Delete the Online directory and the XLAST config file + DeleteDirectory(szPathToOnlineDir); + DeleteFile(szPathToXLASTFile); +} diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index 68083b1..fdfd467 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -4,20 +4,20 @@ #include -// Read the name of the shortcut from the config file and write it to szGameName. -HRESULT GetGameName(char *szGameName, uint32_t nMaxLength); - -// Get the path of the directory the Publisher executable lives in and write it to szGameName. -HRESULT GetExecDir(char *szExecDir, size_t nMaxLength); - -// Delete the XLAST files generated by Publisher. -void Cleanup(void); - // Create the XML config file XLAST uses to build the shortcut. HRESULT BuildXLASTFile(const char *szGameName); // Run BLAST in a separate process. HRESULT ExecBLAST(const char *szXDKPath); +// Get the path of the directory the Publisher executable lives in and write it to szGameName. +HRESULT GetExecDir(char *szExecDir, size_t nMaxLength); + +// Read the name of the shortcut from the config file and write it to szGameName. +HRESULT GetGameName(char *szGameName, uint32_t nMaxLength); + // Make sure an XBDM connection is properly set up. HRESULT CheckXBDMConnection(void); + +// Delete the XLAST files generated by Publisher. +void Cleanup(void); From 6b03927b6657c99a6b177225202729b6b0580cc5 Mon Sep 17 00:00:00 2001 From: Clement Date: Mon, 15 Aug 2022 00:53:03 +0200 Subject: [PATCH 18/30] Added a comment to explain why a warning is disabled before including xbdm.h --- Publisher/src/Utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index f5de5c2..1dac1ab 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -3,6 +3,8 @@ #include +// XBDM uses bit field types other than int which triggers a warning at warning level 4 +// so we just disable it for XBDM #pragma warning(push) #pragma warning(disable : 4214) #include From 142f27fc3b08144a897232a6988d4549fffd3aa8 Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 16 Aug 2022 01:52:28 +0200 Subject: [PATCH 19/30] Created a hash of the game name instead of using a random number not to allow to create multiple shortcuts with the same name --- Publisher/Publisher.vcxproj | 2 +- Publisher/src/Utils.c | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Publisher/Publisher.vcxproj b/Publisher/Publisher.vcxproj index 39ba0bf..1263723 100644 --- a/Publisher/Publisher.vcxproj +++ b/Publisher/Publisher.vcxproj @@ -52,7 +52,7 @@ true $(OutDir)$(TargetName)$(TargetExt) $(IntDir)$(ProjectName)\$(ProjectName).pdb - xbdm.lib;%(AdditionalDependencies) + xbdm.lib;Shlwapi.lib;%(AdditionalDependencies) $(XEDK)\lib\win32\vs2010;%(AdditionalLibraryDirectories) diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index 1dac1ab..2c4adb2 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -2,6 +2,7 @@ #include #include +#include // XBDM uses bit field types other than int which triggers a warning at warning level 4 // so we just disable it for XBDM @@ -19,9 +20,8 @@ HRESULT BuildXLASTFile(const char *szGameName) char szFilePath[MAX_PATH] = { 0 }; wchar_t wszGameName[50] = { 0 }; - // TODO: create an actual random number, based on the shortcut name if possible - uint32_t nRandomNumber = 0x12345678; - wchar_t wszRandomNumber[9] = { 0 }; + uint32_t nGameNameHash = 0; + wchar_t wszGameNameHash[9] = { 0 }; size_t i = 0; @@ -60,18 +60,25 @@ HRESULT BuildXLASTFile(const char *szGameName) return E_FAIL; } + hr = HashData((uint8_t *)szGameName, (uint32_t)strnlen_s(szGameName, 50), (uint8_t *)&nGameNameHash, 4); + if (FAILED(hr)) + { + fputs("Could not hash to game name", stderr); + return E_FAIL; + } + // Convert szGameName, which is a narrow string, to a wide string mbstowcs_s(NULL, wszGameName, 50, szGameName, _TRUNCATE); // Write the string representation of the random number in wszRandomNumber - _snwprintf_s(wszRandomNumber, 9, 9, L"%08x", nRandomNumber); + _snwprintf_s(wszGameNameHash, 9, 9, L"%08x", nGameNameHash); // Convert the string representation of the random number to uppercase for (i = 0; i < 9; i++) - wszRandomNumber[i] = towupper(wszRandomNumber[i]); + wszGameNameHash[i] = towupper(wszGameNameHash[i]); // Create the actual config file content from the game name and the random number and write it to wszFileContent - _snwprintf_s(wszFileContent, 2048, 2048, wszFileContentFormat, wszGameName, wszRandomNumber, wszGameName, wszGameName, wszGameName); + _snwprintf_s(wszFileContent, 2048, 2048, wszFileContentFormat, wszGameName, wszGameNameHash, wszGameName, wszGameName, wszGameName); // Read the executable directory path and write it to szFilePath hr = GetExecDir(szFilePath, MAX_PATH); @@ -107,7 +114,7 @@ HRESULT BuildXLASTFile(const char *szGameName) fclose(pFile); free(wszFileContent); - wprintf_s(L"XLAST file successfully generated (ID: %s)\n", wszRandomNumber); + wprintf_s(L"XLAST file successfully generated (ID: %s)\n", wszGameNameHash); return S_OK; } From 5a952f478ff3f2fe747837ba5f9bff8a2a006ec5 Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 18 Aug 2022 00:21:53 +0200 Subject: [PATCH 20/30] Renamed XDK related variables --- Publisher/src/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Publisher/src/main.c b/Publisher/src/main.c index a22e37a..1f643f3 100644 --- a/Publisher/src/main.c +++ b/Publisher/src/main.c @@ -5,12 +5,12 @@ int main() HRESULT hr = S_OK; errno_t err = 0; - char *szXDKPath = NULL; - size_t nXDKPathSize = 0; + char *szXDKDirPath = NULL; + size_t nXDKDirPathSize = 0; char szGameName[50] = { 0 }; - err = _dupenv_s(&szXDKPath, &nXDKPathSize, "xedk"); - if (szXDKPath == NULL || err != 0) + err = _dupenv_s(&szXDKDirPath, &nXDKDirPathSize, "xedk"); + if (szXDKDirPath == NULL || err != 0) { system("pause"); return EXIT_FAILURE; @@ -37,7 +37,7 @@ int main() return EXIT_FAILURE; } - hr = ExecBLAST(szXDKPath); + hr = ExecBLAST(szXDKDirPath); if (FAILED(hr)) { Cleanup(); From 57b2a44f9d991718b2c73e19b5f8a1fec23da12b Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 18 Aug 2022 00:30:59 +0200 Subject: [PATCH 21/30] Renamed variables with "GameName" to "ShortcutName" --- Publisher/src/Utils.c | 49 ++++++++++++++++++++++--------------------- Publisher/src/Utils.h | 8 +++---- Publisher/src/main.c | 6 +++--- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index 2c4adb2..089a946 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -13,15 +13,15 @@ #include "Utils.h" -HRESULT BuildXLASTFile(const char *szGameName) +HRESULT BuildXLASTFile(const char *szShortcutName) { HRESULT hr = S_OK; char szFilePath[MAX_PATH] = { 0 }; - wchar_t wszGameName[50] = { 0 }; + wchar_t wszShortcutName[50] = { 0 }; - uint32_t nGameNameHash = 0; - wchar_t wszGameNameHash[9] = { 0 }; + uint32_t nShortcutNameHash = 0; + wchar_t wszShortcutNameHash[9] = { 0 }; size_t i = 0; @@ -46,9 +46,9 @@ HRESULT BuildXLASTFile(const char *szGameName) L" \n" L""; - if (szGameName == NULL) + if (szShortcutName == NULL) { - fputs("szGameName is NULL", stderr); + fputs("szShortcutName is NULL", stderr); return E_FAIL; } @@ -60,25 +60,26 @@ HRESULT BuildXLASTFile(const char *szGameName) return E_FAIL; } - hr = HashData((uint8_t *)szGameName, (uint32_t)strnlen_s(szGameName, 50), (uint8_t *)&nGameNameHash, 4); + // Create a hash from the shortcut name and use it has title ID for the shortcut + hr = HashData((uint8_t *)szShortcutName, (uint32_t)strnlen_s(szShortcutName, 50), (uint8_t *)&nShortcutNameHash, 4); if (FAILED(hr)) { - fputs("Could not hash to game name", stderr); + fputs("Could not hash to shortcut name", stderr); return E_FAIL; } - // Convert szGameName, which is a narrow string, to a wide string - mbstowcs_s(NULL, wszGameName, 50, szGameName, _TRUNCATE); + // Convert szShortcutName, which is a narrow string, to a wide string + mbstowcs_s(NULL, wszShortcutName, 50, szShortcutName, _TRUNCATE); // Write the string representation of the random number in wszRandomNumber - _snwprintf_s(wszGameNameHash, 9, 9, L"%08x", nGameNameHash); + _snwprintf_s(wszShortcutNameHash, 9, 9, L"%08x", nShortcutNameHash); // Convert the string representation of the random number to uppercase for (i = 0; i < 9; i++) - wszGameNameHash[i] = towupper(wszGameNameHash[i]); + wszShortcutNameHash[i] = towupper(wszShortcutNameHash[i]); - // Create the actual config file content from the game name and the random number and write it to wszFileContent - _snwprintf_s(wszFileContent, 2048, 2048, wszFileContentFormat, wszGameName, wszGameNameHash, wszGameName, wszGameName, wszGameName); + // Create the actual config file content from the shortcut name and the random number and write it to wszFileContent + _snwprintf_s(wszFileContent, 2048, 2048, wszFileContentFormat, wszShortcutName, wszShortcutNameHash, wszShortcutName, wszShortcutName, wszShortcutName); // Read the executable directory path and write it to szFilePath hr = GetExecDir(szFilePath, MAX_PATH); @@ -114,7 +115,7 @@ HRESULT BuildXLASTFile(const char *szGameName) fclose(pFile); free(wszFileContent); - wprintf_s(L"XLAST file successfully generated (ID: %s)\n", wszGameNameHash); + wprintf_s(L"XLAST file successfully generated (ID: %s)\n", wszShortcutNameHash); return S_OK; } @@ -210,23 +211,23 @@ HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) return S_OK; } -HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) +HRESULT GetShortcutName(char *szShortcutName, uint32_t nMaxLength) { HRESULT hr = S_OK; FILE *pConfigFile = NULL; char szConfigFilePath[MAX_PATH] = { 0 }; - size_t nGameNameSize = 0; + size_t nShortcutNameSize = 0; - if (szGameName != NULL) + if (szShortcutName != NULL) { - fputs("szGameName is NULL", stderr); + fputs("szShortcutName is NULL", stderr); return E_FAIL; } hr = GetExecDir(szConfigFilePath, MAX_PATH); if (FAILED(hr)) { - fputs("Failed to read execution diriectory", stderr); + fputs("Failed to read execution directory", stderr); return hr; } @@ -241,18 +242,18 @@ HRESULT GetGameName(char *szGameName, uint32_t nMaxLength) return E_FAIL; } - // Read the first line of the config file, which contains the shortcut name, into szGameName - if (fgets(szGameName, (int)nMaxLength, pConfigFile) == NULL) + // Read the first line of the config file, which contains the shortcut name, into szShortcutName + if (fgets(szShortcutName, (int)nMaxLength, pConfigFile) == NULL) { fprintf_s(stderr, "Failed to read from config file at location %s\n", szConfigFilePath); fclose(pConfigFile); return E_FAIL; } - nGameNameSize = strnlen_s(szGameName, nMaxLength); + nShortcutNameSize = strnlen_s(szShortcutName, nMaxLength); // Remove the new line character at the end of the line - szGameName[nGameNameSize - 1] = '\0'; + szShortcutName[nShortcutNameSize - 1] = '\0'; fclose(pConfigFile); diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index fdfd467..79d736d 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -5,16 +5,16 @@ #include // Create the XML config file XLAST uses to build the shortcut. -HRESULT BuildXLASTFile(const char *szGameName); +HRESULT BuildXLASTFile(const char *szShortcutName); // Run BLAST in a separate process. HRESULT ExecBLAST(const char *szXDKPath); -// Get the path of the directory the Publisher executable lives in and write it to szGameName. +// Get the path of the directory the Publisher executable lives in and write it to szShortcutName. HRESULT GetExecDir(char *szExecDir, size_t nMaxLength); -// Read the name of the shortcut from the config file and write it to szGameName. -HRESULT GetGameName(char *szGameName, uint32_t nMaxLength); +// Read the name of the shortcut from the config file and write it to szShortcutName. +HRESULT GetShortcutName(char *szShortcutName, uint32_t nMaxLength); // Make sure an XBDM connection is properly set up. HRESULT CheckXBDMConnection(void); diff --git a/Publisher/src/main.c b/Publisher/src/main.c index 1f643f3..dd590aa 100644 --- a/Publisher/src/main.c +++ b/Publisher/src/main.c @@ -7,7 +7,7 @@ int main() char *szXDKDirPath = NULL; size_t nXDKDirPathSize = 0; - char szGameName[50] = { 0 }; + char szShortcutName[50] = { 0 }; err = _dupenv_s(&szXDKDirPath, &nXDKDirPathSize, "xedk"); if (szXDKDirPath == NULL || err != 0) @@ -23,14 +23,14 @@ int main() return EXIT_FAILURE; } - hr = GetGameName(szGameName, sizeof(szGameName)); + hr = GetShortcutName(szShortcutName, sizeof(szShortcutName)); if (FAILED(hr)) { system("pause"); return EXIT_FAILURE; } - hr = BuildXLASTFile(szGameName); + hr = BuildXLASTFile(szShortcutName); if (FAILED(hr)) { system("pause"); From 432d2ea9a02d291faba82898688eb919435ba76b Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 18 Aug 2022 00:42:34 +0200 Subject: [PATCH 22/30] Created a macro for the shortcut name length --- Publisher/src/Utils.c | 7 +++---- Publisher/src/Utils.h | 3 ++- Publisher/src/main.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index 089a946..baa6625 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -1,6 +1,5 @@ #include #include - #include #include @@ -18,7 +17,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) HRESULT hr = S_OK; char szFilePath[MAX_PATH] = { 0 }; - wchar_t wszShortcutName[50] = { 0 }; + wchar_t wszShortcutName[SHORCUT_NAME_LENGTH] = { 0 }; uint32_t nShortcutNameHash = 0; wchar_t wszShortcutNameHash[9] = { 0 }; @@ -61,7 +60,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) } // Create a hash from the shortcut name and use it has title ID for the shortcut - hr = HashData((uint8_t *)szShortcutName, (uint32_t)strnlen_s(szShortcutName, 50), (uint8_t *)&nShortcutNameHash, 4); + hr = HashData((uint8_t *)szShortcutName, (uint32_t)strnlen_s(szShortcutName, SHORCUT_NAME_LENGTH), (uint8_t *)&nShortcutNameHash, 4); if (FAILED(hr)) { fputs("Could not hash to shortcut name", stderr); @@ -69,7 +68,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) } // Convert szShortcutName, which is a narrow string, to a wide string - mbstowcs_s(NULL, wszShortcutName, 50, szShortcutName, _TRUNCATE); + mbstowcs_s(NULL, wszShortcutName, SHORCUT_NAME_LENGTH, szShortcutName, _TRUNCATE); // Write the string representation of the random number in wszRandomNumber _snwprintf_s(wszShortcutNameHash, 9, 9, L"%08x", nShortcutNameHash); diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index 79d736d..3592bdd 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -1,9 +1,10 @@ #pragma once #include - #include +#define SHORCUT_NAME_LENGTH 50 + // Create the XML config file XLAST uses to build the shortcut. HRESULT BuildXLASTFile(const char *szShortcutName); diff --git a/Publisher/src/main.c b/Publisher/src/main.c index dd590aa..6c3e1b9 100644 --- a/Publisher/src/main.c +++ b/Publisher/src/main.c @@ -7,7 +7,7 @@ int main() char *szXDKDirPath = NULL; size_t nXDKDirPathSize = 0; - char szShortcutName[50] = { 0 }; + char szShortcutName[SHORCUT_NAME_LENGTH] = { 0 }; err = _dupenv_s(&szXDKDirPath, &nXDKDirPathSize, "xedk"); if (szXDKDirPath == NULL || err != 0) @@ -23,7 +23,7 @@ int main() return EXIT_FAILURE; } - hr = GetShortcutName(szShortcutName, sizeof(szShortcutName)); + hr = GetShortcutName(szShortcutName, SHORCUT_NAME_LENGTH); if (FAILED(hr)) { system("pause"); From 786c07dd29387b563cb6e190f4372878297ddadb Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 18 Aug 2022 01:03:32 +0200 Subject: [PATCH 23/30] Some general variable renaming --- GameShortcut/src/main.c | 9 +++--- Publisher/src/Utils.c | 64 ++++++++++++++++++++--------------------- Publisher/src/Utils.h | 2 +- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/GameShortcut/src/main.c b/GameShortcut/src/main.c index 4d0a6d9..44b3698 100644 --- a/GameShortcut/src/main.c +++ b/GameShortcut/src/main.c @@ -1,10 +1,9 @@ #include #include - #include // Structs and function prototypes from xboxkrnl.exe -typedef struct +typedef struct _STRING { uint16_t wLength; uint16_t wMaxLength; @@ -21,12 +20,12 @@ static HRESULT MountHdd() { STRING DeviceName = { 0 }; STRING LinkName = { 0 }; - const char *szDestDrive = "\\??\\hdd:"; + const char *szDestinationDrive = "\\??\\hdd:"; const char *szHddDevicePath = "\\Device\\Harddisk0\\Partition1\\"; // Initialize the STRING structs RtlInitAnsiString(&DeviceName, szHddDevicePath); - RtlInitAnsiString(&LinkName, szDestDrive); + RtlInitAnsiString(&LinkName, szDestinationDrive); // Bind the root of the hard drive to the "hdd:" drive. return ObCreateSymbolicLink(&LinkName, &DeviceName); @@ -91,7 +90,7 @@ static HRESULT ShowMessageBoxError(const char *szMessage) while (!XHasOverlappedIoCompleted(&Overlapped)) Sleep(100); - // Get how the user closed the dialog (by clicking "OK", "Cancel" or the Xbox button on the controller + // Get how the user closed the dialog (by clicking "OK", "Cancel" or the Xbox button on the controller) dwResult = XGetOverlappedResult(&Overlapped, NULL, TRUE); if (dwResult == ERROR_ACCESS_DENIED) diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index baa6625..38ed6c8 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -24,8 +24,8 @@ HRESULT BuildXLASTFile(const char *szShortcutName) size_t i = 0; - size_t nWCharCount = 0; - size_t nWritten = 0; + size_t nWCharToWrite = 0; + size_t nWCharWritten = 0; FILE *pFile = NULL; wchar_t *wszFileContent = NULL; const wchar_t *wszFileContentFormat = @@ -51,7 +51,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) return E_FAIL; } - // Allocate enough memory on the heap to hold the config file content + // Allocate enough memory on the heap to hold the XLAST file content wszFileContent = (wchar_t *)malloc(2048 * sizeof(wchar_t)); if (wszFileContent == NULL) { @@ -77,7 +77,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) for (i = 0; i < 9; i++) wszShortcutNameHash[i] = towupper(wszShortcutNameHash[i]); - // Create the actual config file content from the shortcut name and the random number and write it to wszFileContent + // Create the actual XLAST file content from the shortcut name and the random number and write it to wszFileContent _snwprintf_s(wszFileContent, 2048, 2048, wszFileContentFormat, wszShortcutName, wszShortcutNameHash, wszShortcutName, wszShortcutName, wszShortcutName); // Read the executable directory path and write it to szFilePath @@ -85,10 +85,10 @@ HRESULT BuildXLASTFile(const char *szShortcutName) if (FAILED(hr)) return E_FAIL; - // Append the config file name to the executable directory path to get the absolute path to the config file + // Append the XLAST file name to the executable directory path to get the absolute path to the XLAST file strncat_s(szFilePath, MAX_PATH, "\\tmp.xlast", _TRUNCATE); - // Open the config file in write mode and create it if it doesn't exist (which should always be the case) + // Open the XLAST file in write mode and create it if it doesn't exist (which should always be the case) fopen_s(&pFile, szFilePath, "w+, ccs=UTF-16LE"); if (pFile == NULL) { @@ -96,21 +96,21 @@ HRESULT BuildXLASTFile(const char *szShortcutName) return E_FAIL; } - // Write the config file content to the actual file on disk and get the amount of characters written - nWritten = fwrite(wszFileContent, sizeof(wchar_t), nWCharCount, pFile); + // Write the XLAST file content to the actual file on disk and get the amount of characters written + nWCharWritten = fwrite(wszFileContent, sizeof(wchar_t), nWCharToWrite, pFile); // Get the amount of characters that are supposed to be written - nWCharCount = wcsnlen_s(wszFileContent, 2048); + nWCharToWrite = wcsnlen_s(wszFileContent, 2048); - // Make sure all characters from the config file content were written to disk - if (nWritten != nWCharCount) + // Make sure all characters from the XLAST file content were written to disk + if (nWCharWritten != nWCharToWrite) { - fprintf_s(stderr, "Could not write XLAST file, was expecting to write %llu characters but wrote %llu\n", nWCharCount, nWritten); + fprintf_s(stderr, "Could not write XLAST file, was expecting to write %llu characters but wrote %llu\n", nWCharToWrite, nWCharWritten); fclose(pFile); return E_FAIL; } - // Close the config file and free the buffer that was holding its content + // Close the XLAST file and free the buffer that was holding its content fclose(pFile); free(wszFileContent); @@ -119,7 +119,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) return S_OK; } -HRESULT ExecBLAST(const char *szXDKPath) +HRESULT ExecBLAST(const char *szXDKDirPath) { HRESULT hr = S_OK; @@ -127,11 +127,11 @@ HRESULT ExecBLAST(const char *szXDKPath) char szBLASTParameters[MAX_PATH] = { 0 }; char szBLASTPath[MAX_PATH] = { 0 }; - SHELLEXECUTEINFO ShExecInfo = { 0 }; + SHELLEXECUTEINFO ShellExecInfo = { 0 }; - if (szXDKPath == NULL) + if (szXDKDirPath == NULL) { - fputs("szXDKPath is NULL", stderr); + fputs("szXDKDirPath is NULL", stderr); return E_FAIL; } @@ -145,29 +145,29 @@ HRESULT ExecBLAST(const char *szXDKPath) strncat_s(szBLASTParameters, MAX_PATH, "\\tmp.xlast /build /install:Local /nologo", _TRUNCATE); // Create the absolute path to the BLAST executable - strncpy_s(szBLASTPath, MAX_PATH, szXDKPath, _TRUNCATE); + strncpy_s(szBLASTPath, MAX_PATH, szXDKDirPath, _TRUNCATE); strncat_s(szBLASTPath, MAX_PATH, "\\bin\\win32\\blast.exe", _TRUNCATE); // Populate the SHELLEXECUTEINFO struct - ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); - ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_NO_CONSOLE; - ShExecInfo.hwnd = NULL; - ShExecInfo.lpVerb = NULL; - ShExecInfo.lpFile = szBLASTPath; - ShExecInfo.lpParameters = szBLASTParameters; - ShExecInfo.lpDirectory = szExecDirBuffer; - ShExecInfo.nShow = SW_SHOW; - ShExecInfo.hInstApp = NULL; + ShellExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); + ShellExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_NO_CONSOLE; + ShellExecInfo.hwnd = NULL; + ShellExecInfo.lpVerb = NULL; + ShellExecInfo.lpFile = szBLASTPath; + ShellExecInfo.lpParameters = szBLASTParameters; + ShellExecInfo.lpDirectory = szExecDirBuffer; + ShellExecInfo.nShow = SW_SHOW; + ShellExecInfo.hInstApp = NULL; // Execute the command - ShellExecuteEx(&ShExecInfo); + ShellExecuteEx(&ShellExecInfo); // Wait for the command's process to complete - WaitForSingleObject(ShExecInfo.hProcess, INFINITE); - CloseHandle(ShExecInfo.hProcess); + WaitForSingleObject(ShellExecInfo.hProcess, INFINITE); + CloseHandle(ShellExecInfo.hProcess); // Get the status code returned by the BLAST process and check if it returned an error - if ((int)ShExecInfo.hInstApp <= 32) + if ((int)ShellExecInfo.hInstApp <= 32) { DWORD dwError = GetLastError(); char szErrorMsg[200] = { 0 }; @@ -372,7 +372,7 @@ void Cleanup(void) strncat_s(szPathToXLASTFile, MAX_PATH, "\\tmp.xlast", _TRUNCATE); strncat_s(szPathToOnlineDir, MAX_PATH, "\\Online", _TRUNCATE); - // Delete the Online directory and the XLAST config file + // Delete the Online directory and the XLAST file DeleteDirectory(szPathToOnlineDir); DeleteFile(szPathToXLASTFile); } diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index 3592bdd..3e1d6d9 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -9,7 +9,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName); // Run BLAST in a separate process. -HRESULT ExecBLAST(const char *szXDKPath); +HRESULT ExecBLAST(const char *szXDKDirPath); // Get the path of the directory the Publisher executable lives in and write it to szShortcutName. HRESULT GetExecDir(char *szExecDir, size_t nMaxLength); From 7a749958590e43c5317af710421cd8081ca9e109 Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 18 Aug 2022 01:06:06 +0200 Subject: [PATCH 24/30] Renamed the config file from gameInfo.txt to shortcutInfo.txt --- GameShortcut/config/{gameInfo.txt => shortcutInfo.txt} | 0 GameShortcut/src/main.c | 4 ++-- Publisher/src/Utils.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename GameShortcut/config/{gameInfo.txt => shortcutInfo.txt} (100%) diff --git a/GameShortcut/config/gameInfo.txt b/GameShortcut/config/shortcutInfo.txt similarity index 100% rename from GameShortcut/config/gameInfo.txt rename to GameShortcut/config/shortcutInfo.txt diff --git a/GameShortcut/src/main.c b/GameShortcut/src/main.c index 44b3698..2d5687a 100644 --- a/GameShortcut/src/main.c +++ b/GameShortcut/src/main.c @@ -40,7 +40,7 @@ static HRESULT GetGamePath(char *szGamePath, uint32_t nMaxLength) size_t nGamePathSize = 0; // Open the config file in read-only mode - if (fopen_s(&pConfigFile, "game:\\config\\gameInfo.txt", "r") != 0) + if (fopen_s(&pConfigFile, "game:\\config\\shortcutInfo.txt", "r") != 0) return E_FAIL; // Read the second line of the config file into szGamePath @@ -116,7 +116,7 @@ int main() hr = GetGamePath(szGamePath, MAX_PATH); if (FAILED(hr)) { - ShowMessageBoxError("The game information file (config\\gameInfo.txt) could not be loaded or has a wrong format."); + ShowMessageBoxError("The game information file (config\\shortcutInfo.txt) could not be loaded or has a wrong format."); return EXIT_FAILURE; } diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index 38ed6c8..3967113 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -37,7 +37,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) L" \n" L" \n" L" \n" - L" \n" + L" \n" L" \n" L" \n" L" \n" @@ -232,7 +232,7 @@ HRESULT GetShortcutName(char *szShortcutName, uint32_t nMaxLength) // Append the path to the config file to the executable directory to get the // absolute path to the config file - strncat_s(szConfigFilePath, MAX_PATH, "\\config\\gameInfo.txt", _TRUNCATE); + strncat_s(szConfigFilePath, MAX_PATH, "\\config\\shortcutInfo.txt", _TRUNCATE); // Open the config file in read-only mode if (fopen_s(&pConfigFile, szConfigFilePath, "r") != 0) From f04f49cce095a51281cc411c99899c3a766f84a0 Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 18 Aug 2022 01:11:44 +0200 Subject: [PATCH 25/30] Added missing changes to vcxproj files --- GameShortcut/GameShortcut.vcxproj | 2 +- GameShortcut/GameShortcut.vcxproj.filters | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GameShortcut/GameShortcut.vcxproj b/GameShortcut/GameShortcut.vcxproj index cbd9842..0187c27 100644 --- a/GameShortcut/GameShortcut.vcxproj +++ b/GameShortcut/GameShortcut.vcxproj @@ -70,7 +70,7 @@ - + copy "%(FullPath)" "$(OutDir)config\%(Filename)%(Extension)" Copy config file %(FullPath) $(OutDir)config\%(Filename)%(Extension) diff --git a/GameShortcut/GameShortcut.vcxproj.filters b/GameShortcut/GameShortcut.vcxproj.filters index 48743fa..fab47a2 100644 --- a/GameShortcut/GameShortcut.vcxproj.filters +++ b/GameShortcut/GameShortcut.vcxproj.filters @@ -4,6 +4,6 @@ - + \ No newline at end of file From 510dc648813c4257d35b88b94b8e272ae90c446c Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 18 Aug 2022 01:35:56 +0200 Subject: [PATCH 26/30] Replaced hard coded length with macros --- GameShortcut/src/main.c | 6 ++++-- Publisher/src/Utils.c | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/GameShortcut/src/main.c b/GameShortcut/src/main.c index 2d5687a..a00825d 100644 --- a/GameShortcut/src/main.c +++ b/GameShortcut/src/main.c @@ -2,6 +2,8 @@ #include #include +#define ERROR_LENGTH 200 + // Structs and function prototypes from xboxkrnl.exe typedef struct _STRING { @@ -63,13 +65,13 @@ static HRESULT ShowMessageBoxError(const char *szMessage) { DWORD dwResult = 0; - wchar_t wszMessage[200] = { 0 }; + wchar_t wszMessage[ERROR_LENGTH] = { 0 }; XOVERLAPPED Overlapped = { 0 }; MESSAGEBOX_RESULT Result = { 0 }; const wchar_t *pwszButtons[] = { L"OK", L"Cancel" }; // Convert szMessage, which is a narrow string, to a wide string - mbstowcs_s(NULL, wszMessage, 200, szMessage, _TRUNCATE); + mbstowcs_s(NULL, wszMessage, ERROR_LENGTH, szMessage, _TRUNCATE); dwResult = XShowMessageBoxUI( 0, diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index 3967113..a26a0ac 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -12,6 +12,10 @@ #include "Utils.h" +#define FILE_CONTENT_MAX_LENGTH 2048 +#define ERROR_LENGTH 200 +#define HASH_LENGTH sizeof(uint32_t) + 1 + HRESULT BuildXLASTFile(const char *szShortcutName) { HRESULT hr = S_OK; @@ -20,7 +24,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) wchar_t wszShortcutName[SHORCUT_NAME_LENGTH] = { 0 }; uint32_t nShortcutNameHash = 0; - wchar_t wszShortcutNameHash[9] = { 0 }; + wchar_t wszShortcutNameHash[HASH_LENGTH] = { 0 }; size_t i = 0; @@ -52,7 +56,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) } // Allocate enough memory on the heap to hold the XLAST file content - wszFileContent = (wchar_t *)malloc(2048 * sizeof(wchar_t)); + wszFileContent = (wchar_t *)malloc(FILE_CONTENT_MAX_LENGTH * sizeof(wchar_t)); if (wszFileContent == NULL) { fputs("Allocating memory for XLAST file content failed", stderr); @@ -60,7 +64,13 @@ HRESULT BuildXLASTFile(const char *szShortcutName) } // Create a hash from the shortcut name and use it has title ID for the shortcut - hr = HashData((uint8_t *)szShortcutName, (uint32_t)strnlen_s(szShortcutName, SHORCUT_NAME_LENGTH), (uint8_t *)&nShortcutNameHash, 4); + hr = HashData( + (uint8_t *)szShortcutName, + (uint32_t)strnlen_s(szShortcutName, SHORCUT_NAME_LENGTH), + (uint8_t *)&nShortcutNameHash, + sizeof(uint32_t) + ); + if (FAILED(hr)) { fputs("Could not hash to shortcut name", stderr); @@ -71,14 +81,24 @@ HRESULT BuildXLASTFile(const char *szShortcutName) mbstowcs_s(NULL, wszShortcutName, SHORCUT_NAME_LENGTH, szShortcutName, _TRUNCATE); // Write the string representation of the random number in wszRandomNumber - _snwprintf_s(wszShortcutNameHash, 9, 9, L"%08x", nShortcutNameHash); + _snwprintf_s(wszShortcutNameHash, HASH_LENGTH, HASH_LENGTH, L"%08x", nShortcutNameHash); // Convert the string representation of the random number to uppercase - for (i = 0; i < 9; i++) + for (i = 0; i < HASH_LENGTH; i++) wszShortcutNameHash[i] = towupper(wszShortcutNameHash[i]); // Create the actual XLAST file content from the shortcut name and the random number and write it to wszFileContent - _snwprintf_s(wszFileContent, 2048, 2048, wszFileContentFormat, wszShortcutName, wszShortcutNameHash, wszShortcutName, wszShortcutName, wszShortcutName); + _snwprintf_s( + wszFileContent, + FILE_CONTENT_MAX_LENGTH, + FILE_CONTENT_MAX_LENGTH, + wszFileContentFormat, + wszShortcutName, + wszShortcutNameHash, + wszShortcutName, + wszShortcutName, + wszShortcutName + ); // Read the executable directory path and write it to szFilePath hr = GetExecDir(szFilePath, MAX_PATH); @@ -100,7 +120,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) nWCharWritten = fwrite(wszFileContent, sizeof(wchar_t), nWCharToWrite, pFile); // Get the amount of characters that are supposed to be written - nWCharToWrite = wcsnlen_s(wszFileContent, 2048); + nWCharToWrite = wcsnlen_s(wszFileContent, FILE_CONTENT_MAX_LENGTH); // Make sure all characters from the XLAST file content were written to disk if (nWCharWritten != nWCharToWrite) @@ -170,8 +190,8 @@ HRESULT ExecBLAST(const char *szXDKDirPath) if ((int)ShellExecInfo.hInstApp <= 32) { DWORD dwError = GetLastError(); - char szErrorMsg[200] = { 0 }; - strerror_s(szErrorMsg, 200, dwError); + char szErrorMsg[ERROR_LENGTH] = { 0 }; + strerror_s(szErrorMsg, ERROR_LENGTH, dwError); fputs(szErrorMsg, stderr); From 5f77806118f8efe3c25c6b398530e58c2d856ba6 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 24 Aug 2022 13:28:52 +0200 Subject: [PATCH 27/30] Used size_t instead of uint32_t when it was meaningful + corrected some comments --- GameShortcut/src/main.c | 8 ++++---- Publisher/src/Utils.c | 8 ++++---- Publisher/src/Utils.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/GameShortcut/src/main.c b/GameShortcut/src/main.c index a00825d..17fb1f3 100644 --- a/GameShortcut/src/main.c +++ b/GameShortcut/src/main.c @@ -17,7 +17,7 @@ HRESULT ObCreateSymbolicLink(STRING *pLinkName, STRING *pDevicePath); // Allow the game to access the entire hard drive. // The system only allows executables to access the directory they live in and binds it to -// the "game:" drive. Everything else if not accessible unless you create a symbolic link. +// the "game:" drive. Nothing else is accessible unless you create a symbolic link. static HRESULT MountHdd() { STRING DeviceName = { 0 }; @@ -34,7 +34,7 @@ static HRESULT MountHdd() } // Read the path to the executable from the config file and write it to szGamePath. -static HRESULT GetGamePath(char *szGamePath, uint32_t nMaxLength) +static HRESULT GetGamePath(char *szGamePath, size_t nMaxLength) { HRESULT hr = S_OK; size_t i = 0; @@ -88,11 +88,11 @@ static HRESULT ShowMessageBoxError(const char *szMessage) if (dwResult != ERROR_IO_PENDING) return E_FAIL; - // Wait until the user closes the dialog + // Wait until the user closes the message box while (!XHasOverlappedIoCompleted(&Overlapped)) Sleep(100); - // Get how the user closed the dialog (by clicking "OK", "Cancel" or the Xbox button on the controller) + // Get how the user closed the message box (by clicking "OK", "Cancel" or the Xbox button on the controller) dwResult = XGetOverlappedResult(&Overlapped, NULL, TRUE); if (dwResult == ERROR_ACCESS_DENIED) diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index a26a0ac..7f92808 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -80,14 +80,14 @@ HRESULT BuildXLASTFile(const char *szShortcutName) // Convert szShortcutName, which is a narrow string, to a wide string mbstowcs_s(NULL, wszShortcutName, SHORCUT_NAME_LENGTH, szShortcutName, _TRUNCATE); - // Write the string representation of the random number in wszRandomNumber + // Write the string representation of the shortcut name hash in wszShortcutNameHash _snwprintf_s(wszShortcutNameHash, HASH_LENGTH, HASH_LENGTH, L"%08x", nShortcutNameHash); - // Convert the string representation of the random number to uppercase + // Convert the string representation of the shortcut name hash number to uppercase for (i = 0; i < HASH_LENGTH; i++) wszShortcutNameHash[i] = towupper(wszShortcutNameHash[i]); - // Create the actual XLAST file content from the shortcut name and the random number and write it to wszFileContent + // Create the actual XLAST file content from the shortcut name and the shortcut name hash and write it to wszFileContent _snwprintf_s( wszFileContent, FILE_CONTENT_MAX_LENGTH, @@ -230,7 +230,7 @@ HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) return S_OK; } -HRESULT GetShortcutName(char *szShortcutName, uint32_t nMaxLength) +HRESULT GetShortcutName(char *szShortcutName, size_t nMaxLength) { HRESULT hr = S_OK; FILE *pConfigFile = NULL; diff --git a/Publisher/src/Utils.h b/Publisher/src/Utils.h index 3e1d6d9..3c33b62 100644 --- a/Publisher/src/Utils.h +++ b/Publisher/src/Utils.h @@ -15,7 +15,7 @@ HRESULT ExecBLAST(const char *szXDKDirPath); HRESULT GetExecDir(char *szExecDir, size_t nMaxLength); // Read the name of the shortcut from the config file and write it to szShortcutName. -HRESULT GetShortcutName(char *szShortcutName, uint32_t nMaxLength); +HRESULT GetShortcutName(char *szShortcutName, size_t nMaxLength); // Make sure an XBDM connection is properly set up. HRESULT CheckXBDMConnection(void); From ccd4249d2d1218cd8de0e5e78af6ba38ed0d5291 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 31 Aug 2022 14:21:29 +0200 Subject: [PATCH 28/30] Added missing new line characters when using fputs --- Publisher/src/Utils.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index 7f92808..e5ebace 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -51,7 +51,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) if (szShortcutName == NULL) { - fputs("szShortcutName is NULL", stderr); + fputs("szShortcutName is NULL\n", stderr); return E_FAIL; } @@ -59,7 +59,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) wszFileContent = (wchar_t *)malloc(FILE_CONTENT_MAX_LENGTH * sizeof(wchar_t)); if (wszFileContent == NULL) { - fputs("Allocating memory for XLAST file content failed", stderr); + fputs("Allocating memory for XLAST file content failed\n", stderr); return E_FAIL; } @@ -73,7 +73,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) if (FAILED(hr)) { - fputs("Could not hash to shortcut name", stderr); + fputs("Could not hash to shortcut name\n", stderr); return E_FAIL; } @@ -151,7 +151,7 @@ HRESULT ExecBLAST(const char *szXDKDirPath) if (szXDKDirPath == NULL) { - fputs("szXDKDirPath is NULL", stderr); + fputs("szXDKDirPath is NULL\n", stderr); return E_FAIL; } @@ -209,7 +209,7 @@ HRESULT GetExecDir(char *szExecDir, size_t nMaxLength) if (szExecDir == NULL) { - fputs("szExecDir is NULL", stderr); + fputs("szExecDir is NULL\n", stderr); return E_FAIL; } @@ -239,14 +239,14 @@ HRESULT GetShortcutName(char *szShortcutName, size_t nMaxLength) if (szShortcutName != NULL) { - fputs("szShortcutName is NULL", stderr); + fputs("szShortcutName is NULL\n", stderr); return E_FAIL; } hr = GetExecDir(szConfigFilePath, MAX_PATH); if (FAILED(hr)) { - fputs("Failed to read execution directory", stderr); + fputs("Failed to read execution directory\n", stderr); return hr; } @@ -288,7 +288,7 @@ HRESULT CheckXBDMConnection(void) // Get the name of the default Xbox 360 set up in Neighborhood hr = DmGetNameOfXbox(szXboxName, &dwXboxNameSize, TRUE); if (FAILED(hr)) - fputs("Could not connect to console", stderr); + fputs("Could not connect to console\n", stderr); return hr; } @@ -307,7 +307,7 @@ static HRESULT DeleteDirectory(const char *szDirPath) if (szDirPath == NULL) { - fputs("szDirPath is NULL", stderr); + fputs("szDirPath is NULL\n", stderr); return E_FAIL; } From ff89ca7331795d3e69371ae314b3138684ac24fb Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 31 Aug 2022 15:29:41 +0200 Subject: [PATCH 29/30] Fixed the file content and shortcut name hash lengths being wrong --- Publisher/src/Utils.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Publisher/src/Utils.c b/Publisher/src/Utils.c index e5ebace..e497223 100644 --- a/Publisher/src/Utils.c +++ b/Publisher/src/Utils.c @@ -14,7 +14,9 @@ #define FILE_CONTENT_MAX_LENGTH 2048 #define ERROR_LENGTH 200 -#define HASH_LENGTH sizeof(uint32_t) + 1 + +// Each bytes is represented as 2 characters in hex and we need an extra character to null-terminate the string +#define HASH_LENGTH ((sizeof(uint32_t) * 2) + 1) HRESULT BuildXLASTFile(const char *szShortcutName) { @@ -81,7 +83,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) mbstowcs_s(NULL, wszShortcutName, SHORCUT_NAME_LENGTH, szShortcutName, _TRUNCATE); // Write the string representation of the shortcut name hash in wszShortcutNameHash - _snwprintf_s(wszShortcutNameHash, HASH_LENGTH, HASH_LENGTH, L"%08x", nShortcutNameHash); + _snwprintf_s(wszShortcutNameHash, HASH_LENGTH, _TRUNCATE, L"%08x", nShortcutNameHash); // Convert the string representation of the shortcut name hash number to uppercase for (i = 0; i < HASH_LENGTH; i++) @@ -91,7 +93,7 @@ HRESULT BuildXLASTFile(const char *szShortcutName) _snwprintf_s( wszFileContent, FILE_CONTENT_MAX_LENGTH, - FILE_CONTENT_MAX_LENGTH, + _TRUNCATE, wszFileContentFormat, wszShortcutName, wszShortcutNameHash, @@ -116,12 +118,12 @@ HRESULT BuildXLASTFile(const char *szShortcutName) return E_FAIL; } - // Write the XLAST file content to the actual file on disk and get the amount of characters written - nWCharWritten = fwrite(wszFileContent, sizeof(wchar_t), nWCharToWrite, pFile); - // Get the amount of characters that are supposed to be written nWCharToWrite = wcsnlen_s(wszFileContent, FILE_CONTENT_MAX_LENGTH); + // Write the XLAST file content to the actual file on disk and get the amount of characters written + nWCharWritten = fwrite(wszFileContent, sizeof(wchar_t), nWCharToWrite, pFile); + // Make sure all characters from the XLAST file content were written to disk if (nWCharWritten != nWCharToWrite) { @@ -237,7 +239,7 @@ HRESULT GetShortcutName(char *szShortcutName, size_t nMaxLength) char szConfigFilePath[MAX_PATH] = { 0 }; size_t nShortcutNameSize = 0; - if (szShortcutName != NULL) + if (szShortcutName == NULL) { fputs("szShortcutName is NULL\n", stderr); return E_FAIL; From 0bbf8dd863aafa33d4d02695dfd2bfe928fd7e6c Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 31 Aug 2022 15:30:02 +0200 Subject: [PATCH 30/30] Stopped deploying the XEX to the console on build --- GameShortcut/GameShortcut.vcxproj | 5 ----- 1 file changed, 5 deletions(-) diff --git a/GameShortcut/GameShortcut.vcxproj b/GameShortcut/GameShortcut.vcxproj index 0187c27..b4bd277 100644 --- a/GameShortcut/GameShortcut.vcxproj +++ b/GameShortcut/GameShortcut.vcxproj @@ -25,7 +25,6 @@ - hdd:\Games\$(ProjectName) $(SolutionDir)build\bin\ $(SolutionDir)build\obj\ $(OutDir)$(TargetName)$(TargetExt) @@ -55,10 +54,6 @@ $(IntDir)$(ProjectName)\$(ProjectName).pdb true - - CopyToHardDrive - $(RemoteRoot)=$(ImagePath);$(RemoteRoot)\config=$(OutDir)config - del $(OutDir)$(TargetName)$(TargetExt)