#include "chrome_launcher.h" #include #include #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN # include #endif namespace navegator { namespace { #ifdef _WIN32 const char* kChromePaths[] = { "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", }; bool file_exists_w(const char* path) { DWORD attrs = GetFileAttributesA(path); return (attrs != INVALID_FILE_ATTRIBUTES) && !(attrs & FILE_ATTRIBUTE_DIRECTORY); } std::string find_chrome() { for (const char* p : kChromePaths) { if (file_exists_w(p)) return p; } return ""; } // Quote para argv en CreateProcess (rules de MSVCR / Chromium): // envolver en " y escapar las " internas con \" y los \ que preceden a " con \\. std::string quote_arg(const std::string& a) { if (a.empty()) return "\"\""; bool needs = a.find_first_of(" \t\"") != std::string::npos; if (!needs) return a; std::string out = "\""; int backslashes = 0; for (char c : a) { if (c == '\\') { ++backslashes; out += c; } else if (c == '"') { // Duplicar las \\ acumuladas + escapar la " for (int i = 0; i < backslashes; ++i) out += '\\'; backslashes = 0; out += "\\\""; } else { backslashes = 0; out += c; } } // Cerrar: duplicar \\ pendientes. for (int i = 0; i < backslashes; ++i) out += '\\'; out += '"'; return out; } #endif } // namespace LaunchResult launch_chrome(const LaunchOpts& opts) { LaunchResult r; #ifndef _WIN32 (void)opts; r.error = "launch_chrome: solo Windows en v0"; return r; #else std::string chrome = opts.chrome_path.empty() ? find_chrome() : opts.chrome_path; if (chrome.empty()) { r.error = "chrome.exe no encontrado en Program Files"; return r; } if (opts.user_data_dir.empty()) { r.error = "user_data_dir obligatorio para aislar perfil"; return r; } // Crear el directorio si no existe (ignoramos errores, Chrome se queja si no puede). CreateDirectoryA(opts.user_data_dir.c_str(), nullptr); char port_buf[32]; std::snprintf(port_buf, sizeof(port_buf), "--remote-debugging-port=%d", opts.port); std::string cmd; cmd = quote_arg(chrome); cmd += " "; cmd += quote_arg(port_buf); cmd += " --remote-allow-origins=*"; cmd += " "; cmd += quote_arg(std::string("--user-data-dir=") + opts.user_data_dir); cmd += " --no-first-run --no-default-browser-check"; if (opts.headless) { cmd += " --headless=new --disable-gpu"; } if (!opts.start_url.empty()) { cmd += " "; cmd += quote_arg(opts.start_url); } else { cmd += " about:blank"; } STARTUPINFOA si{}; si.cb = sizeof(si); PROCESS_INFORMATION pi{}; // CreateProcess modifica el commandline buffer — copia mutable. std::string mutable_cmd = cmd; BOOL ok = CreateProcessA( nullptr, mutable_cmd.data(), nullptr, nullptr, FALSE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, nullptr, nullptr, &si, &pi); if (!ok) { DWORD err = GetLastError(); char buf[64]; std::snprintf(buf, sizeof(buf), "CreateProcess failed (err=%lu)", (unsigned long)err); r.error = buf; return r; } r.ok = true; r.pid = (uint32_t)pi.dwProcessId; CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return r; #endif } } // namespace navegator