133 lines
3.5 KiB
C++
133 lines
3.5 KiB
C++
#include "chrome_launcher.h"
|
|
|
|
#include <cstdio>
|
|
#include <string>
|
|
|
|
#ifdef _WIN32
|
|
# define WIN32_LEAN_AND_MEAN
|
|
# include <windows.h>
|
|
#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
|