/
sevawhite
/
claude-code-installer
Обзор
Документация
Войти
/
sevawhite
/
claude-code-installer
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
installer.cpp
699 строк
26 KB
Seva
Initial commit: Claude Code Installer with modern design
24 июл 2026, 16:08
24 июл 2026, 16:08
726c2dd
Код
Авторство
О чём код?
/* * Claude Code Installer for Windows * GUI Installer using Windows API */ #include <windows.h> #include <commctrl.h> #include <shlobj.h> #include <string> #include <fstream> #include <direct.h> #pragma comment(lib, "comctl32.lib") #pragma comment(lib, "shell32.lib") // Глобальные переменные HINSTANCE hInst; HWND hwndMain; int currentPage = 0; const int TOTAL_PAGES = 7; // Данные установки struct InstallData { std::string installPath; std::string apiKey; bool useProxy; std::string proxyIp; std::string proxyPort; std::string proxyLogin; std::string proxyPassword; std::string telegramToken; } installData; // ID элементов управления #define IDC_NEXT 1001 #define IDC_BACK 1002 #define IDC_CANCEL 1003 #define IDC_INSTALL_PATH 1004 #define IDC_BROWSE 1005 #define IDC_API_KEY 1006 #define IDC_USE_PROXY 1007 #define IDC_PROXY_IP 1008 #define IDC_PROXY_PORT 1009 #define IDC_PROXY_LOGIN 1010 #define IDC_PROXY_PASSWORD 1011 #define IDC_TELEGRAM_TOKEN 1012 #define IDC_PROGRESS 1013 #define IDC_LOG 1014 // Вспомогательные функции std::string GetUserProfilePath() { char path[MAX_PATH]; if (SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, path) == S_OK) { return std::string(path); } return "C:\\Users\\Default"; } void CreateDirectoryRecursive(const std::string& path) { size_t pos = 0; do { pos = path.find_first_of("\\/", pos + 1); std::string subPath = path.substr(0, pos); CreateDirectoryA(subPath.c_str(), NULL); } while (pos != std::string::npos); } void SaveConfig() { std::string configPath = installData.installPath + "\\config.json"; std::ofstream file(configPath); file << "{\n"; file << " \"api_key\": \"" << installData.apiKey << "\",\n"; file << " \"telegram_token\": \"" << installData.telegramToken << "\",\n"; file << " \"proxy\": {\n"; file << " \"enabled\": " << (installData.useProxy ? "true" : "false") << ",\n"; file << " \"ip\": \"" << installData.proxyIp << "\",\n"; file << " \"port\": \"" << installData.proxyPort << "\",\n"; file << " \"login\": \"" << installData.proxyLogin << "\",\n"; file << " \"password\": \"" << installData.proxyPassword << "\"\n"; file << " }\n"; file << "}\n"; file.close(); } void CreateLaunchScript() { std::string scriptPath = installData.installPath + "\\start-claude.bat"; std::ofstream file(scriptPath); file << "@echo off\n"; file << "chcp 65001 >nul\n"; file << "title Claude Code Launcher\n\n"; file << "echo ========================================\n"; file << "echo Claude Code Launcher\n"; file << "echo ========================================\n"; file << "echo.\n\n"; if (!installData.apiKey.empty()) { file << "set ANTHROPIC_API_KEY=" << installData.apiKey << "\n"; } file << "set ANTHROPIC_BASE_URL=http://localhost:20128/v1\n"; file << "set ANTHROPIC_MODEL=kr/claude-sonnet-4.5\n\n"; if (installData.useProxy) { file << "set HTTP_PROXY=http://" << installData.proxyLogin << ":" << installData.proxyPassword << "@" << installData.proxyIp << ":" << installData.proxyPort << "\n"; file << "set HTTPS_PROXY=http://" << installData.proxyLogin << ":" << installData.proxyPassword << "@" << installData.proxyIp << ":" << installData.proxyPort << "\n"; file << "set NO_PROXY=localhost,127.0.0.1\n\n"; } file << "echo Запуск Claude Code...\n"; file << "echo.\n\n"; file << "set \"CLAUDE_EXE=" << installData.installPath << "\\claude\\claude.exe\"\n\n"; file << "if exist \"%CLAUDE_EXE%\" (\n"; file << " echo Найден: %CLAUDE_EXE%\n"; file << " \"%CLAUDE_EXE%\" --channels plugin:telegram@claude-plugins-official\n"; file << ") else (\n"; file << " echo ОШИБКА: claude.exe не найден!\n"; file << " echo Скачайте: https://disk.yandex.ru/d/bjIN_6e2j94LhA\n"; file << " pause\n"; file << ")\n"; file.close(); } // Функции отрисовки страниц void ShowPage(HWND hwnd, int page); void DrawWelcomePage(HWND hwnd) { HWND hStatic; hStatic = CreateWindowW(L"STATIC", L"Добро пожаловать в установщик Claude Code!\n\n" L"Этот мастер поможет установить:\n" L"• Node.js 22 LTS\n" L"• Claude Code CLI\n" L"• OmniRoute маршрутизатор\n" L"• Telegram интеграция\n\n" L"Нажмите 'Далее' для продолжения.", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 100, 600, 250, hwnd, NULL, hInst, NULL); HFONT hFont = CreateFontW(18, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI"); SendMessage(hStatic, WM_SETFONT, (WPARAM)hFont, TRUE); } void DrawInstallPathPage(HWND hwnd) { CreateWindowW(L"STATIC", L"Папка установки:", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 100, 200, 25, hwnd, NULL, hInst, NULL); std::wstring wPath(installData.installPath.begin(), installData.installPath.end()); CreateWindowW(L"EDIT", wPath.c_str(), WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 50, 130, 500, 25, hwnd, (HMENU)IDC_INSTALL_PATH, hInst, NULL); CreateWindowW(L"BUTTON", L"Обзор...", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 560, 130, 90, 25, hwnd, (HMENU)IDC_BROWSE, hInst, NULL); } void DrawOmniRoutePage(HWND hwnd) { CreateWindowW(L"STATIC", L"Введите API ключ от OmniRoute:\n\n" L"Как получить:\n" L"1. Запустите 'omniroute'\n" L"2. Зарегистрируйтесь в веб-интерфейсе\n" L"3. Создайте API ключ\n\n" L"Можно пропустить и настроить позже.", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 80, 600, 150, hwnd, NULL, hInst, NULL); CreateWindowW(L"STATIC", L"API ключ:", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 240, 200, 25, hwnd, NULL, hInst, NULL); CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | ES_PASSWORD, 50, 265, 600, 25, hwnd, (HMENU)IDC_API_KEY, hInst, NULL); } void DrawProxyPage(HWND hwnd) { CreateWindowW(L"STATIC", L"Настройка прокси (опционально)\n\n" L"Если используете VPN - пропустите этот шаг", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 80, 600, 60, hwnd, NULL, hInst, NULL); CreateWindowW(L"BUTTON", L"Использовать прокси", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 50, 150, 200, 25, hwnd, (HMENU)IDC_USE_PROXY, hInst, NULL); CreateWindowW(L"STATIC", L"IP адрес:", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 190, 100, 25, hwnd, NULL, hInst, NULL); CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 160, 190, 200, 25, hwnd, (HMENU)IDC_PROXY_IP, hInst, NULL); CreateWindowW(L"STATIC", L"Порт:", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 225, 100, 25, hwnd, NULL, hInst, NULL); CreateWindowW(L"EDIT", L"8080", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 160, 225, 200, 25, hwnd, (HMENU)IDC_PROXY_PORT, hInst, NULL); CreateWindowW(L"STATIC", L"Логин:", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 260, 100, 25, hwnd, NULL, hInst, NULL); CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 160, 260, 200, 25, hwnd, (HMENU)IDC_PROXY_LOGIN, hInst, NULL); CreateWindowW(L"STATIC", L"Пароль:", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 295, 100, 25, hwnd, NULL, hInst, NULL); CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | ES_PASSWORD, 160, 295, 200, 25, hwnd, (HMENU)IDC_PROXY_PASSWORD, hInst, NULL); } void DrawTelegramPage(HWND hwnd) { CreateWindowW(L"STATIC", L"Telegram интеграция (опционально)\n\n" L"Как создать бота:\n" L"1. Откройте @BotFather в Telegram\n" L"2. Отправьте: /newbot\n" L"3. Следуйте инструкциям\n" L"4. Скопируйте токен\n\n" L"Можно пропустить и настроить позже.", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 80, 600, 180, hwnd, NULL, hInst, NULL); CreateWindowW(L"STATIC", L"Telegram Token:", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 270, 200, 25, hwnd, NULL, hInst, NULL); CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 50, 295, 600, 25, hwnd, (HMENU)IDC_TELEGRAM_TOKEN, hInst, NULL); } void DrawSummaryPage(HWND hwnd) { std::wstring summary = L"Готово к установке!\n\n"; summary += L"Папка: "; summary += std::wstring(installData.installPath.begin(), installData.installPath.end()); summary += L"\n"; summary += L"API ключ: "; summary += installData.apiKey.empty() ? L"Не настроен" : L"Настроен"; summary += L"\n"; summary += L"Прокси: "; summary += installData.useProxy ? L"Включен" : L"Выключен"; summary += L"\n"; summary += L"Telegram: "; summary += installData.telegramToken.empty() ? L"Не настроен" : L"Настроен"; summary += L"\n\n"; summary += L"Нажмите 'Установить' для начала."; CreateWindowW(L"STATIC", summary.c_str(), WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 80, 600, 300, hwnd, NULL, hInst, NULL); } void DrawInstallPage(HWND hwnd) { CreateWindowW(L"STATIC", L"Установка...", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 80, 600, 25, hwnd, NULL, hInst, NULL); CreateWindowExW(0, PROGRESS_CLASSW, NULL, WS_CHILD | WS_VISIBLE | PBS_SMOOTH, 50, 110, 600, 30, hwnd, (HMENU)IDC_PROGRESS, hInst, NULL); CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY, 50, 150, 600, 250, hwnd, (HMENU)IDC_LOG, hInst, NULL); } void DrawFinishPage(HWND hwnd) { CreateWindowW(L"STATIC", L"Установка завершена!\n\n" L"Claude Code успешно установлен.\n\n" L"Что дальше:\n" L"1. Установите Node.js 22: https://nodejs.org\n" L"2. Установите OmniRoute: npm install -g omniroute\n" L"3. Запустите omniroute и получите API ключ\n" L"4. Скачайте Claude Code и распакуйте\n" L"5. Запустите start-claude.bat", WS_CHILD | WS_VISIBLE | SS_LEFT, 50, 80, 600, 300, hwnd, NULL, hInst, NULL); } void ShowPage(HWND hwnd, int page) { // Удалить все дочерние окна HWND hChild = GetWindow(hwnd, GW_CHILD); while (hChild) { HWND hNext = GetWindow(hChild, GW_HWNDNEXT); int id = GetDlgCtrlID(hChild); if (id != IDC_NEXT && id != IDC_BACK && id != IDC_CANCEL) { DestroyWindow(hChild); } hChild = hNext; } // Показать нужную страницу switch (page) { case 0: DrawWelcomePage(hwnd); break; case 1: DrawInstallPathPage(hwnd); break; case 2: DrawInstallPage(hwnd); break; // Установка сразу после выбора папки case 3: DrawOmniRoutePage(hwnd); break; // API ключ ПОСЛЕ установки case 4: DrawTelegramPage(hwnd); break; case 5: DrawProxyPage(hwnd); break; case 6: DrawFinishPage(hwnd); break; } // Обновить кнопки HWND hNext = GetDlgItem(hwnd, IDC_NEXT); HWND hBack = GetDlgItem(hwnd, IDC_BACK); EnableWindow(hBack, page > 0 && page != 2); // Нельзя вернуться во время установки if (page == 6) { SetWindowTextW(hNext, L"Завершить"); } else { SetWindowTextW(hNext, L"Далее"); } ShowWindow(hNext, page != 2 ? SW_SHOW : SW_HIDE); // Скрыть кнопку во время установки } void PerformInstallation(HWND hwnd) { HWND hProgress = GetDlgItem(hwnd, IDC_PROGRESS); HWND hLog = GetDlgItem(hwnd, IDC_LOG); SendMessage(hProgress, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); auto AddLog = [hLog](const wchar_t* text) { int len = GetWindowTextLengthW(hLog); SendMessageW(hLog, EM_SETSEL, len, len); SendMessageW(hLog, EM_REPLACESEL, FALSE, (LPARAM)text); SendMessageW(hLog, EM_REPLACESEL, FALSE, (LPARAM)L"\r\n"); UpdateWindow(hLog); }; AddLog(L"Начинаем установку..."); SendMessage(hProgress, PBM_SETPOS, 5, 0); Sleep(500); // 1. Создание директории AddLog(L"Создание директории установки..."); CreateDirectoryRecursive(installData.installPath); AddLog(L"✓ Директория создана"); SendMessage(hProgress, PBM_SETPOS, 10, 0); // 2. Проверка и установка Node.js AddLog(L"\nПроверка Node.js..."); DWORD exitCode; STARTUPINFOA si = {sizeof(si)}; PROCESS_INFORMATION pi; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; bool nodeInstalled = false; // Проверка установлен ли Node.js if (CreateProcessA(NULL, (LPSTR)"cmd /c node --version", NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { WaitForSingleObject(pi.hProcess, 5000); GetExitCodeProcess(pi.hProcess, &exitCode); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if (exitCode == 0) { AddLog(L"✓ Node.js уже установлен"); nodeInstalled = true; } } if (!nodeInstalled) { AddLog(L"Node.js не установлен, начинаем установку..."); // Скачивание Node.js std::string nodeUrl = "https://nodejs.org/dist/v22.11.0/node-v22.11.0-x64.msi"; std::string nodePath = installData.installPath + "\\node-installer.msi"; std::string downloadCmd = "powershell -WindowStyle Hidden -Command \"& {[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; Invoke-WebRequest -Uri '" + nodeUrl + "' -OutFile '" + nodePath + "' -UseBasicParsing}\""; AddLog(L"Скачивание Node.js (это займет 2-3 минуты)..."); SendMessage(hProgress, PBM_SETPOS, 15, 0); if (CreateProcessA(NULL, (LPSTR)downloadCmd.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { WaitForSingleObject(pi.hProcess, 600000); // 10 минут на скачивание GetExitCodeProcess(pi.hProcess, &exitCode); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if (exitCode == 0) { AddLog(L"✓ Node.js скачан (25 MB)"); SendMessage(hProgress, PBM_SETPOS, 25, 0); // Установка Node.js AddLog(L"Установка Node.js (это займет 2-3 минуты)..."); AddLog(L"Пожалуйста, подождите..."); std::string installCmd = "msiexec /i \"" + nodePath + "\" /qn /norestart ADDLOCAL=ALL"; if (CreateProcessA(NULL, (LPSTR)installCmd.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { // Ждём завершения установки WaitForSingleObject(pi.hProcess, 600000); // 10 минут на установку GetExitCodeProcess(pi.hProcess, &exitCode); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); AddLog(L"✓ Node.js установлен"); DeleteFileA(nodePath.c_str()); // Обновляем PATH в текущем процессе char pathBuf[32768]; DWORD size = GetEnvironmentVariableA("PATH", pathBuf, sizeof(pathBuf)); std::string newPath = pathBuf; newPath += ";C:\\Program Files\\nodejs"; SetEnvironmentVariableA("PATH", newPath.c_str()); AddLog(L"✓ PATH обновлён"); Sleep(2000); // Даём время системе nodeInstalled = true; } else { AddLog(L"✗ Ошибка установки Node.js"); } } else { AddLog(L"✗ Ошибка скачивания Node.js"); AddLog(L"Проверьте подключение к интернету"); } } else { AddLog(L"✗ Не удалось запустить PowerShell"); } } SendMessage(hProgress, PBM_SETPOS, 40, 0); // 3. Установка OmniRoute AddLog(L"\nУстановка OmniRoute через npm..."); if (nodeInstalled) { std::string npmCmd = "cmd /c \"C:\\Program Files\\nodejs\\npm.cmd\" install -g omniroute"; if (CreateProcessA(NULL, (LPSTR)npmCmd.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { WaitForSingleObject(pi.hProcess, 180000); // 3 минуты GetExitCodeProcess(pi.hProcess, &exitCode); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if (exitCode == 0) { AddLog(L"✓ OmniRoute установлен"); } else { AddLog(L"⚠ OmniRoute: возможны предупреждения, но установлен"); } } else { AddLog(L"✗ Не удалось запустить npm"); } } else { AddLog(L"✗ Пропуск OmniRoute - Node.js не установлен"); } SendMessage(hProgress, PBM_SETPOS, 60, 0); // 4. Скачивание Claude Code AddLog(L"\nПодготовка Claude Code..."); AddLog(L"Скачивание с Яндекс.Диска..."); std::string claudeDir = installData.installPath + "\\claude"; CreateDirectoryA(claudeDir.c_str(), NULL); std::string claudeUrl = "https://disk.yandex.ru/d/bjIN_6e2j94LhA"; std::string claudeZip = installData.installPath + "\\claude.zip"; // Информация для пользователя AddLog(L"Claude Code нужно скачать вручную:"); AddLog(L"1. Откройте: https://disk.yandex.ru/d/bjIN_6e2j94LhA"); AddLog(L"2. Скачайте архив"); std::wstring claudeDirW = std::wstring(claudeDir.begin(), claudeDir.end()); AddLog((L"3. Распакуйте в: " + claudeDirW).c_str()); SendMessage(hProgress, PBM_SETPOS, 80, 0); // 5. Создание конфигурации AddLog(L"\nСоздание конфигурационных файлов..."); SaveConfig(); CreateLaunchScript(); AddLog(L"✓ Конфигурация создана"); SendMessage(hProgress, PBM_SETPOS, 100, 0); AddLog(L"\n✅ Установка базовых компонентов завершена!"); AddLog(L"Нажмите 'Далее' для настройки API ключа"); // Автоматически переходим к следующему экрану через 3 секунды Sleep(3000); currentPage = 3; ShowPage(hwnd, currentPage); } void SavePageData(HWND hwnd) { char buffer[1024]; switch(currentPage) { case 1: { GetDlgItemTextA(hwnd, IDC_INSTALL_PATH, buffer, sizeof(buffer)); installData.installPath = buffer; break; } case 2: { GetDlgItemTextA(hwnd, IDC_API_KEY, buffer, sizeof(buffer)); installData.apiKey = buffer; break; } case 3: { installData.useProxy = IsDlgButtonChecked(hwnd, IDC_USE_PROXY) == BST_CHECKED; GetDlgItemTextA(hwnd, IDC_PROXY_IP, buffer, sizeof(buffer)); installData.proxyIp = buffer; GetDlgItemTextA(hwnd, IDC_PROXY_PORT, buffer, sizeof(buffer)); installData.proxyPort = buffer; GetDlgItemTextA(hwnd, IDC_PROXY_LOGIN, buffer, sizeof(buffer)); installData.proxyLogin = buffer; GetDlgItemTextA(hwnd, IDC_PROXY_PASSWORD, buffer, sizeof(buffer)); installData.proxyPassword = buffer; break; } case 4: { GetDlgItemTextA(hwnd, IDC_TELEGRAM_TOKEN, buffer, sizeof(buffer)); installData.telegramToken = buffer; break; } } } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: { // Создать кнопки CreateWindowW(L"BUTTON", L"Далее", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 550, 450, 100, 30, hwnd, (HMENU)IDC_NEXT, hInst, NULL); CreateWindowW(L"BUTTON", L"Назад", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 440, 450, 100, 30, hwnd, (HMENU)IDC_BACK, hInst, NULL); CreateWindowW(L"BUTTON", L"Отмена", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 50, 450, 100, 30, hwnd, (HMENU)IDC_CANCEL, hInst, NULL); ShowPage(hwnd, 0); break; } case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_NEXT: { SavePageData(hwnd); if (currentPage == 1) { // После выбора папки - сразу установка currentPage = 2; ShowPage(hwnd, currentPage); PerformInstallation(hwnd); } else if (currentPage == 2) { // После установки пропускаем к API ключу (экран 3) currentPage = 3; ShowPage(hwnd, currentPage); } else if (currentPage == 6) { // Последний экран - закрыть PostQuitMessage(0); } else if (currentPage < 6) { currentPage++; ShowPage(hwnd, currentPage); } break; } case IDC_BACK: { if (currentPage > 0) { currentPage--; ShowPage(hwnd, currentPage); } break; } case IDC_CANCEL: { if (MessageBoxW(hwnd, L"Отменить установку?", L"Подтверждение", MB_YESNO | MB_ICONQUESTION) == IDYES) { PostQuitMessage(0); } break; } case IDC_BROWSE: { BROWSEINFOW bi = {0}; bi.hwndOwner = hwnd; bi.lpszTitle = L"Выберите папку установки"; bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; LPITEMIDLIST pidl = SHBrowseForFolderW(&bi); if (pidl) { wchar_t path[MAX_PATH]; if (SHGetPathFromIDListW(pidl, path)) { SetDlgItemTextW(hwnd, IDC_INSTALL_PATH, path); } CoTaskMemFree(pidl); } break; } } break; } case WM_CLOSE: { if (MessageBoxW(hwnd, L"Закрыть установщик?", L"Подтверждение", MB_YESNO | MB_ICONQUESTION) == IDYES) { DestroyWindow(hwnd); } break; } case WM_DESTROY: { PostQuitMessage(0); break; } default: return DefWindowProcW(hwnd, msg, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { hInst = hInstance; // Инициализация CoInitialize(NULL); InitCommonControls(); // Инициализация данных installData.installPath = GetUserProfilePath() + "\\ClaudeCode"; installData.useProxy = false; installData.proxyPort = "8080"; // Регистрация класса окна WNDCLASSEXW wc = {0}; wc.cbSize = sizeof(WNDCLASSEXW); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszClassName = L"ClaudeInstaller"; RegisterClassExW(&wc); // Создание окна hwndMain = CreateWindowExW( 0, L"ClaudeInstaller", L"Claude Code Installer v1.0", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 750, 550, NULL, NULL, hInstance, NULL); if (!hwndMain) { return 0; } // Центрирование окна RECT rc; GetWindowRect(hwndMain, &rc); int xPos = (GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2; int yPos = (GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 2; SetWindowPos(hwndMain, NULL, xPos, yPos, 0, 0, SWP_NOZORDER | SWP_NOSIZE); ShowWindow(hwndMain, nCmdShow); UpdateWindow(hwndMain); // Цикл сообщений MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } CoUninitialize(); return (int)msg.wParam; }