Launcher/sources/main.cpp

202 lines
7.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <windows.h>
#include <string>
#include <vector>
#include <shlwapi.h>
#include <algorithm>
#include <versionhelpers.h> // Для IsWindows7OrGreater()
#pragma comment(lib, "shlwapi.lib")
//==============================================================================
// Проверка версии Windows (требуется Windows 7+)
bool IsSupportedWindowsVersion()
{
return IsWindows7OrGreater();
}
//==============================================================================
// Проверка существования файла
bool FileExists(const std::wstring& path)
{
DWORD attrs = GetFileAttributesW(path.c_str());
return (attrs != INVALID_FILE_ATTRIBUTES) && !(attrs & FILE_ATTRIBUTE_DIRECTORY);
}
//==============================================================================
// Поиск всех подкаталогов, содержащих "lib" в имени (регистронезависимо)
std::vector<std::wstring> FindLibSubdirectories(const std::wstring& baseDir)
{
std::vector<std::wstring> result;
WIN32_FIND_DATAW findData;
std::wstring searchPath = baseDir + L"\\*";
HANDLE hFind = FindFirstFileW(searchPath.c_str(), &findData);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
std::wstring dirName = findData.cFileName;
if (dirName != L"." && dirName != L"..") {
// Преобразуем в нижний регистр для проверки
std::wstring lowerName = dirName;
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower);
if (lowerName.find(L"lib") != std::wstring::npos) {
result.push_back(baseDir + L"\\" + dirName);
}
}
}
} while (FindNextFileW(hFind, &findData));
FindClose(hFind);
}
return result;
}
//==============================================================================
// Получение директории текущего EXE
std::wstring GetExeDirectory()
{
wchar_t buf[MAX_PATH];
GetModuleFileNameW(nullptr, buf, MAX_PATH);
return std::wstring(buf).substr(0, std::wstring(buf).find_last_of(L"\\/"));
}
//==============================================================================
// Построение пути к целевой программе
std::wstring GetTargetPath()
{
// Получаем путь к текущему исполняемому файлу
wchar_t currentPath[MAX_PATH];
GetModuleFileNameW(nullptr, currentPath, MAX_PATH);
// Извлекаем имя файла (без пути)
std::wstring exePath(currentPath);
size_t lastSlash = exePath.find_last_of(L"\\/");
std::wstring exeName = (lastSlash == std::wstring::npos) ? exePath : exePath.substr(lastSlash + 1);
// Формируем путь к программе в подкаталоге bin
std::wstring targetPath = exePath.substr(0, lastSlash + 1) + L"bin\\" + exeName;
if (!FileExists(targetPath)) {
MessageBoxW(nullptr,
(L"File not found:\n" + targetPath).c_str(),
L"Error", MB_ICONERROR);
return L"";
}
return targetPath;
}
//==============================================================================
// Создание нового блока окружения с обновлённым PATH
std::wstring BuildEnvironment()
{
std::wstring baseDir = GetExeDirectory();
std::wstring newPath;
// 1. Обновляем PATH
const std::vector<std::wstring> paths = {
baseDir + L"\\bin",
baseDir + L"\\modules",
baseDir + L"\\plugins"
};
for (const auto& path : paths) {
if (PathIsDirectoryW(path.c_str())) {
if (!newPath.empty()) newPath += L';';
newPath += path;
}
}
// Добавляем все подкаталоги с "lib" в имени
auto libDirs = FindLibSubdirectories(baseDir);
for (const auto& path : libDirs) {
if (!newPath.empty()) newPath += L";";
newPath += path;
}
// Добавляем системный PATH
wchar_t sysPath[32767];
GetEnvironmentVariableW(L"PATH", sysPath, 32767);
newPath = newPath + L';' + sysPath;
// 2. Обрабатываем QT_PLUGIN_PATH
std::wstring qtPluginPath = baseDir + L"\\plugins";
wchar_t oldQtPluginPath[32767];
DWORD qtPathSize = GetEnvironmentVariableW(L"QT_PLUGIN_PATH", oldQtPluginPath, 32767);
if (qtPathSize > 0) {
// Если переменная уже существует, заменяем её значение
qtPluginPath = baseDir + L"\\plugins;" + oldQtPluginPath;
}
// 3. Формируем полный блок среды
std::wstring envBlock =
L"PATH=" + newPath + L'\0' +
L"QT_PLUGIN_PATH=" + qtPluginPath + L'\0';
// Копируем остальные переменные (кроме PATH и QT_PLUGIN_PATH)
LPWCH envStrings = GetEnvironmentStringsW();
for (LPWSTR var = envStrings; *var; var += wcslen(var) + 1) {
if (wcsncmp(var, L"PATH=", 5) != 0 &&
wcsncmp(var, L"QT_PLUGIN_PATH=", 15) != 0) {
envBlock += std::wstring(var) + L'\0';
}
}
envBlock += L'\0';
FreeEnvironmentStringsW(envStrings);
return envBlock;
}
//==============================================================================
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
// Проверка версии Windows
if (!IsSupportedWindowsVersion()) {
MessageBoxW(nullptr,
L"Minimum version Windows 7",
L"Error version", MB_ICONERROR);
return 1;
}
// Получаем путь к целевой программе
std::wstring targetPath = GetTargetPath();
if (targetPath.empty()) return 1;
// Подготавливаем окружение
std::wstring envBlock = BuildEnvironment();
// Запускаем процесс
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi;
std::wstring cmdLine = L"\"" + targetPath + L"\"";
LPWSTR args = GetCommandLineW();
if (args) {
std::wstring fullArgs = args;
size_t pos = fullArgs.find(L' ');
if (pos != std::wstring::npos) {
cmdLine += fullArgs.substr(pos);
}
}
if (!CreateProcessW(
targetPath.c_str(),
&cmdLine[0],
nullptr,
nullptr,
FALSE,
CREATE_UNICODE_ENVIRONMENT,
(LPVOID)envBlock.c_str(),
nullptr,
&si,
&pi
)) {
DWORD err = GetLastError();
MessageBoxW(nullptr,
(L"Error create process (code " + std::to_wstring(err) + L")\n" + targetPath).c_str(),
L"Error", MB_ICONERROR);
return 1;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
//==============================================================================