202 lines
7.1 KiB
C++
202 lines
7.1 KiB
C++
#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;
|
||
}
|
||
//==============================================================================
|
||
|