diff --git a/qrenderdoc/Code/Interface/QRDInterface.cpp b/qrenderdoc/Code/Interface/QRDInterface.cpp index b0418970b..b7720d64e 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.cpp +++ b/qrenderdoc/Code/Interface/QRDInterface.cpp @@ -4,69 +4,46 @@ #include #include "Code/QRDUtils.h" -QString EnvironmentModification::GetTypeString() const -{ - QString ret; - - if(type == EnvMod::Append) - ret = QString("Append, %1").arg(ToQStr(separator)); - else if(type == EnvMod::Prepend) - ret = QString("Prepend, %1").arg(ToQStr(separator)); - else - ret = "Set"; - - return ret; -} - -QString EnvironmentModification::GetDescription() const -{ - QString ret; - - if(type == EnvMod::Append) - ret = QString("Append %1 with %2 using %3").arg(variable).arg(value).arg(ToQStr(separator)); - else if(type == EnvMod::Prepend) - ret = QString("Prepend %1 with %2 using %3").arg(variable).arg(value).arg(ToQStr(separator)); - else - ret = QString("Set %1 to %2").arg(variable).arg(value); - - return ret; -} - -EnvironmentModification::operator QVariant() const +QVariant EnvModToVariant(const EnvironmentModification &env) { QVariantMap ret; - ret["variable"] = variable; - ret["value"] = value; - ret["type"] = ToQStr(type); - ret["separator"] = ToQStr(separator); + ret["variable"] = ToQStr(env.name); + ret["value"] = ToQStr(env.value); + ret["type"] = ToQStr(env.mod); + ret["separator"] = ToQStr(env.sep); return ret; } -EnvironmentModification::EnvironmentModification(const QVariant &v) +EnvironmentModification EnvModFromVariant(const QVariant &v) { QVariantMap data = v.toMap(); - variable = data["variable"].toString(); - value = data["value"].toString(); + + EnvironmentModification ret; + + ret.name = data["variable"].toString().toUtf8().data(); + ret.value = data["value"].toString().toUtf8().data(); QString t = data["type"].toString(); if(t == ToQStr(EnvMod::Append)) - type = EnvMod::Append; + ret.mod = EnvMod::Append; else if(t == ToQStr(EnvMod::Prepend)) - type = EnvMod::Prepend; + ret.mod = EnvMod::Prepend; else - type = EnvMod::Set; + ret.mod = EnvMod::Set; QString s = data["separator"].toString(); if(s == ToQStr(EnvSep::SemiColon)) - separator = EnvSep::SemiColon; + ret.sep = EnvSep::SemiColon; else if(s == ToQStr(EnvSep::Colon)) - separator = EnvSep::Colon; + ret.sep = EnvSep::Colon; else if(s == ToQStr(EnvSep::Platform)) - separator = EnvSep::Platform; + ret.sep = EnvSep::Platform; else - separator = EnvSep::NoSep; + ret.sep = EnvSep::NoSep; + + return ret; } CaptureSettings::CaptureSettings() @@ -88,7 +65,7 @@ CaptureSettings::operator QVariant() const QVariantList env; for(int i = 0; i < Environment.size(); i++) - env.push_back((QVariant)Environment[i]); + env.push_back(EnvModToVariant(Environment[i])); ret["Environment"] = env; QVariantMap opts; @@ -122,7 +99,7 @@ CaptureSettings::CaptureSettings(const QVariant &v) QVariantList env = data["Environment"].toList(); for(int i = 0; i < env.size(); i++) { - EnvironmentModification e(env[i]); + EnvironmentModification e = EnvModFromVariant(env[i]); Environment.push_back(e); } diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index 540e7b62b..5fed346e6 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -43,28 +43,6 @@ class QWidget; struct ICaptureContext; -struct EnvironmentModification -{ - EnvironmentModification() - { - type = EnvMod::Set; - separator = EnvSep::NoSep; - } - - QString variable; - QString value; - - EnvMod type; - EnvSep separator; - - QString GetTypeString() const; - QString GetDescription() const; - - VARIANT_CAST(EnvironmentModification); -}; - -DECLARE_REFLECTION_STRUCT(EnvironmentModification); - struct CaptureSettings { CaptureSettings(); diff --git a/qrenderdoc/Code/RenderManager.cpp b/qrenderdoc/Code/RenderManager.cpp index 6159ce7f7..9cce10ca1 100644 --- a/qrenderdoc/Code/RenderManager.cpp +++ b/qrenderdoc/Code/RenderManager.cpp @@ -355,11 +355,7 @@ uint32_t RenderManager::ExecuteAndInject(const QString &exe, const QString &work const QList &env, const QString &logfile, CaptureOptions opts) { - void *envList = RENDERDOC_MakeEnvironmentModificationList(env.size()); - - for(int i = 0; i < env.size(); i++) - RENDERDOC_SetEnvironmentModification(envList, i, env[i].variable.toUtf8().data(), - env[i].value.toUtf8().data(), env[i].type, env[i].separator); + rdctype::array envList = env.toVector().toStdVector(); uint32_t ret = 0; @@ -376,8 +372,6 @@ uint32_t RenderManager::ExecuteAndInject(const QString &exe, const QString &work opts, false); } - RENDERDOC_FreeEnvironmentModificationList(envList); - return ret; } diff --git a/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp b/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp index 8fff3514c..8e090d87a 100644 --- a/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp +++ b/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp @@ -37,6 +37,26 @@ #define JSON_ID "rdocCaptureSettings" #define JSON_VER 1 +static QString GetDescription(const EnvironmentModification &env) +{ + QString ret; + + if(env.mod == EnvMod::Append) + ret = QString("Append %1 with %2 using %3") + .arg(ToQStr(env.name)) + .arg(ToQStr(env.value)) + .arg(ToQStr(env.sep)); + else if(env.mod == EnvMod::Prepend) + ret = QString("Prepend %1 with %2 using %3") + .arg(ToQStr(env.name)) + .arg(ToQStr(env.value)) + .arg(ToQStr(env.sep)); + else + ret = QString("Set %1 to %2").arg(ToQStr(env.name)).arg(ToQStr(env.value)); + + return ret; +} + Q_DECLARE_METATYPE(CaptureSettings); CaptureDialog::CaptureDialog(ICaptureContext &ctx, OnCaptureMethod captureCallback, @@ -662,7 +682,7 @@ void CaptureDialog::SetEnvironmentModifications(const QListenvVar->setText(envModText); diff --git a/qrenderdoc/Windows/Dialogs/EnvironmentEditor.cpp b/qrenderdoc/Windows/Dialogs/EnvironmentEditor.cpp index 4c17958ba..96355acc6 100644 --- a/qrenderdoc/Windows/Dialogs/EnvironmentEditor.cpp +++ b/qrenderdoc/Windows/Dialogs/EnvironmentEditor.cpp @@ -29,6 +29,20 @@ #include "Code/QRDUtils.h" #include "ui_EnvironmentEditor.h" +static QString GetTypeString(const EnvironmentModification &env) +{ + QString ret; + + if(env.mod == EnvMod::Append) + ret = QString("Append, %1").arg(ToQStr(env.sep)); + else if(env.mod == EnvMod::Prepend) + ret = QString("Prepend, %1").arg(ToQStr(env.sep)); + else + ret = "Set"; + + return ret; +} + Q_DECLARE_METATYPE(EnvironmentModification); EnvironmentEditor::EnvironmentEditor(QWidget *parent) @@ -115,17 +129,17 @@ void EnvironmentEditor::on_variables_currentItemChanged(QTreeWidgetItem *current EnvironmentModification mod = sel[0]->data(0, Qt::UserRole).value(); - if(!mod.variable.isEmpty()) + if(!mod.value.empty()) { - ui->name->setText(mod.variable); - ui->value->setText(mod.value); - ui->separator->setCurrentIndex((int)mod.separator); + ui->name->setText(ToQStr(mod.name)); + ui->value->setText(ToQStr(mod.value)); + ui->separator->setCurrentIndex((int)mod.sep); - if(mod.type == EnvMod::Set) + if(mod.mod == EnvMod::Set) ui->setValue->setChecked(true); - else if(mod.type == EnvMod::Append) + else if(mod.mod == EnvMod::Append) ui->appendValue->setChecked(true); - else if(mod.type == EnvMod::Prepend) + else if(mod.mod == EnvMod::Prepend) ui->prependValue->setChecked(true); } } @@ -133,16 +147,16 @@ void EnvironmentEditor::on_variables_currentItemChanged(QTreeWidgetItem *current void EnvironmentEditor::on_addUpdate_clicked() { EnvironmentModification mod; - mod.variable = ui->name->text(); - mod.value = ui->value->text(); - mod.separator = (EnvSep)ui->separator->currentIndex(); + mod.name = ui->name->text().toUtf8().data(); + mod.value = ui->value->text().toUtf8().data(); + mod.sep = (EnvSep)ui->separator->currentIndex(); if(ui->appendValue->isChecked()) - mod.type = EnvMod::Append; + mod.mod = EnvMod::Append; else if(ui->prependValue->isChecked()) - mod.type = EnvMod::Prepend; + mod.mod = EnvMod::Prepend; else - mod.type = EnvMod::Set; + mod.mod = EnvMod::Set; addModification(mod, false); @@ -174,7 +188,7 @@ int EnvironmentEditor::existingIndex() void EnvironmentEditor::addModification(EnvironmentModification mod, bool silent) { - if(mod.variable.trimmed() == "") + if(mod.name.empty()) { if(!silent) RDDialog::critical(this, tr("Invalid variable"), @@ -189,15 +203,15 @@ void EnvironmentEditor::addModification(EnvironmentModification mod, bool silent if(idx < 0) { - node = makeTreeNode({mod.variable, mod.GetTypeString(), mod.value}); + node = makeTreeNode({ToQStr(mod.name), GetTypeString(mod), ToQStr(mod.value)}); ui->variables->addTopLevelItem(node); } else { node = ui->variables->topLevelItem(idx); - node->setText(0, mod.variable); - node->setText(1, mod.GetTypeString()); - node->setText(2, mod.value); + node->setText(0, ToQStr(mod.name)); + node->setText(1, GetTypeString(mod)); + node->setText(2, ToQStr(mod.value)); } node->setData(0, Qt::UserRole, QVariant::fromValue(mod)); @@ -225,7 +239,7 @@ QList EnvironmentEditor::modifications() EnvironmentModification mod = ui->variables->topLevelItem(i)->data(0, Qt::UserRole).value(); - if(!mod.variable.isEmpty()) + if(!mod.name.empty()) ret.push_back(mod); } diff --git a/qrenderdoc/Windows/MainWindow.cpp b/qrenderdoc/Windows/MainWindow.cpp index e5b6fe830..025f8910e 100644 --- a/qrenderdoc/Windows/MainWindow.cpp +++ b/qrenderdoc/Windows/MainWindow.cpp @@ -371,20 +371,13 @@ void MainWindow::OnInjectTrigger(uint32_t PID, const QList envList = env.toVector().toStdVector(); + + LambdaThread *th = new LambdaThread([this, PID, envList, name, opts, callback]() { QString logfile = m_Ctx.TempLogFilename(name); - void *envList = RENDERDOC_MakeEnvironmentModificationList(env.size()); - - for(int i = 0; i < env.size(); i++) - RENDERDOC_SetEnvironmentModification(envList, i, env[i].variable.toUtf8().data(), - env[i].value.toUtf8().data(), env[i].type, - env[i].separator); - uint32_t ret = RENDERDOC_InjectIntoProcess(PID, envList, logfile.toUtf8().data(), opts, false); - RENDERDOC_FreeEnvironmentModificationList(envList); - GUIInvoke::call([this, PID, ret, callback]() { if(ret == 0) { diff --git a/renderdoc/api/replay/control_types.h b/renderdoc/api/replay/control_types.h index cae2ec6ca..3bc9cae06 100644 --- a/renderdoc/api/replay/control_types.h +++ b/renderdoc/api/replay/control_types.h @@ -487,3 +487,23 @@ struct TargetControlMessage }; DECLARE_REFLECTION_STRUCT(TargetControlMessage); + +DOCUMENT("A modification to a single environment variable."); +struct EnvironmentModification +{ + EnvironmentModification() : mod(EnvMod::Set), sep(EnvSep::NoSep), name(""), value("") {} + EnvironmentModification(EnvMod m, EnvSep s, const char *n, const char *v) + : mod(m), sep(s), name(n), value(v) + { + } + DOCUMENT("The :class:`modification ` to use."); + EnvMod mod; + DOCUMENT("The :class:`separator ` to use if needed."); + EnvSep sep; + DOCUMENT("The name of the environment variable."); + rdctype::str name; + DOCUMENT("The value to use with the modification specified in :data:`mod`."); + rdctype::str value; +}; + +DECLARE_REFLECTION_STRUCT(EnvironmentModification); diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index 5e49eb8e8..ca92ee276 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -931,14 +931,15 @@ This happens on the remote system, so all paths are relative to the remote files directory containing the application is used. :param str cmdLine: The command line to use when running the application, it will be processed in a platform specific way to generate arguments. -:param env: Any environment variable modifications that should be made when running the program. +:param list env: Any :class:`EnvironmentModification` that should be made when running the program. :param CaptureOptions opts: The capture options to use when injecting into the program. :return: The ident where the new application is listening for target control, or 0 if something went wrong. :rtype: ``int`` )"); virtual uint32_t ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, - void *env, const CaptureOptions &opts) = 0; + const rdctype::array &env, + const CaptureOptions &opts) = 0; DOCUMENT(R"(Take ownership over a capture file. @@ -1231,7 +1232,7 @@ DOCUMENT(R"(Launch an application and inject into it to allow capturing. directory containing the application is used. :param str cmdLine: The command line to use when running the application, it will be processed in a platform specific way to generate arguments. -:param env: Any environment variable modifications that should be made when running the program. +:param list env: Any :class:`EnvironmentModification` that should be made when running the program. :param CaptureOptions opts: The capture options to use when injecting into the program. :param bool waitForExit: If ``True`` this function will block until the process exits. :return: The ident where the new application is listening for target control, or 0 if something went @@ -1239,21 +1240,23 @@ DOCUMENT(R"(Launch an application and inject into it to allow capturing. :rtype: ``int`` )"); extern "C" RENDERDOC_API uint32_t RENDERDOC_CC -RENDERDOC_ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, void *env, - const char *logfile, const CaptureOptions &opts, bool32 waitForExit); +RENDERDOC_ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, + const rdctype::array &env, const char *logfile, + const CaptureOptions &opts, bool32 waitForExit); DOCUMENT(R"(Where supported by operating system and permissions, inject into a running process. :param int pid: The Process ID (PID) to inject into. -:param env: Any environment variable modifications that should be made when running the program. +:param list env: Any :class:`EnvironmentModification` that should be made when running the program. :param CaptureOptions opts: The capture options to use when injecting into the program. :param bool waitForExit: If ``True`` this function will block until the process exits. :return: The ident where the new application is listening for target control, or 0 if something went wrong. :rtype: ``int`` )"); -extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_InjectIntoProcess( - uint32_t pid, void *env, const char *logfile, const CaptureOptions &opts, bool32 waitForExit); +extern "C" RENDERDOC_API uint32_t RENDERDOC_CC +RENDERDOC_InjectIntoProcess(uint32_t pid, const rdctype::array &env, + const char *logfile, const CaptureOptions &opts, bool32 waitForExit); DOCUMENT(R"(When debugging RenderDoc it can be useful to capture itself by doing a side-build with a temporary name. This function wraps up the use of the in-application API to start a capture. @@ -1350,16 +1353,6 @@ DOCUMENT("Internal function for setting a config setting."); extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetConfigSetting(const char *name, const char *value); -DOCUMENT("Internal function for making an environment modification list."); -extern "C" RENDERDOC_API void *RENDERDOC_CC RENDERDOC_MakeEnvironmentModificationList(int numElems); - -DOCUMENT("Internal function for setting an element in an environment modification list."); -extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetEnvironmentModification( - void *mem, int idx, const char *variable, const char *value, EnvMod type, EnvSep separator); - -DOCUMENT("Internal function for freeing an environment modification list."); -extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_FreeEnvironmentModificationList(void *mem); - DOCUMENT("Internal function for enumerating android devices."); extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_EnumerateAndroidDevices(rdctype::str *deviceList); diff --git a/renderdoc/core/remote_server.cpp b/renderdoc/core/remote_server.cpp index 82ca14bbf..09c8aaa68 100644 --- a/renderdoc/core/remote_server.cpp +++ b/renderdoc/core/remote_server.cpp @@ -72,9 +72,9 @@ string ToStrHelper::Get(const EnvSep &el) } template <> -void Serialiser::Serialise(const char *name, Process::EnvironmentModification &el) +void Serialiser::Serialise(const char *name, EnvironmentModification &el) { - ScopedContext scope(this, name, "Process::EnvironmentModification", 0, true); + ScopedContext scope(this, name, "EnvironmentModification", 0, true); Serialise("mod", el.mod); Serialise("sep", el.sep); @@ -438,12 +438,8 @@ static void ActiveRemoteClientThread(void *data) recvser->Serialise("cmdLine", cmdLine); recvser->Serialise("opts", opts); - uint64_t envListSize = 0; - Process::EnvironmentModification *env = NULL; - recvser->Serialise("envListSize", envListSize); - - if(envListSize > 0) - recvser->SerialiseComplexArray("env", env, envListSize); + rdctype::array env; + recvser->Serialise("env", env); uint32_t ident = uint32_t(ReplayStatus::NetworkIOFailed); @@ -457,8 +453,6 @@ static void ActiveRemoteClientThread(void *data) RDCWARN("Requested to execute program - disallowing based on configuration"); } - SAFE_DELETE_ARRAY(env); - sendType = eRemoteServer_ExecuteAndInject; sendSer.Serialise("ident", ident); } @@ -894,7 +888,8 @@ public: return ret; } - uint32_t ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, void *env, + uint32_t ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, + const rdctype::array &env, const CaptureOptions &opts) { const char *host = hostname().c_str(); @@ -905,34 +900,12 @@ public: string workstr = workingDir && workingDir[0] ? workingDir : ""; string cmdstr = cmdLine && cmdLine[0] ? cmdLine : ""; - Process::EnvironmentModification *envList = (Process::EnvironmentModification *)env; - Serialiser sendData("", Serialiser::WRITING, false); sendData.Serialise("app", appstr); sendData.Serialise("workingDir", workstr); sendData.Serialise("cmdLine", cmdstr); sendData.Serialise("opts", (CaptureOptions &)opts); - - uint64_t envListSize = 0; - if(envList) - { - Process::EnvironmentModification *it = envList; - for(;;) - { - if(it->name == "") - break; - envListSize++; - it++; - } - - // include terminator - envListSize++; - } - - sendData.Serialise("envListSize", envListSize); - - if(envListSize > 0) - sendData.SerialiseComplexArray("env", envList, envListSize); + sendData.Serialise("env", (rdctype::array &)env); Send(eRemoteServer_ExecuteAndInject, sendData); @@ -1185,9 +1158,9 @@ RemoteServer_RemoteSupportedReplays(IRemoteServer *remote, rdctype::arrayRemoteSupportedReplays(); } -extern "C" RENDERDOC_API uint32_t RENDERDOC_CC -RemoteServer_ExecuteAndInject(IRemoteServer *remote, const char *app, const char *workingDir, - const char *cmdLine, void *env, const CaptureOptions &opts) +extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RemoteServer_ExecuteAndInject( + IRemoteServer *remote, const char *app, const char *workingDir, const char *cmdLine, + const rdctype::array &env, const CaptureOptions &opts) { return remote->ExecuteAndInject(app, workingDir, cmdLine, env, opts); } diff --git a/renderdoc/driver/vulkan/vk_layer.cpp b/renderdoc/driver/vulkan/vk_layer.cpp index 28b65e2f0..b792aad99 100644 --- a/renderdoc/driver/vulkan/vk_layer.cpp +++ b/renderdoc/driver/vulkan/vk_layer.cpp @@ -51,7 +51,7 @@ class VulkanHook : LibraryHook bool CreateHooks(const char *libName) { // we assume the implicit layer is registered - the UI will prompt the user about installing it. - Process::RegisterEnvironmentModification(Process::EnvironmentModification( + Process::RegisterEnvironmentModification(EnvironmentModification( EnvMod::Set, EnvSep::NoSep, "ENABLE_VULKAN_RENDERDOC_CAPTURE", "1")); // check options to set further variables, and apply @@ -63,7 +63,7 @@ class VulkanHook : LibraryHook void EnableHooks(const char *libName, bool enable) { // set the env var to 0 to disable the implicit layer - Process::RegisterEnvironmentModification(Process::EnvironmentModification( + Process::RegisterEnvironmentModification(EnvironmentModification( EnvMod::Set, EnvSep::NoSep, "ENABLE_VULKAN_RENDERDOC_CAPTURE", enable ? "1" : "0")); Process::ApplyEnvironmentModification(); @@ -74,11 +74,11 @@ class VulkanHook : LibraryHook if(RenderDoc::Inst().GetCaptureOptions().APIValidation) { Process::RegisterEnvironmentModification( - Process::EnvironmentModification(EnvMod::Append, EnvSep::Platform, "VK_INSTANCE_LAYERS", - "VK_LAYER_LUNARG_standard_validation")); + EnvironmentModification(EnvMod::Append, EnvSep::Platform, "VK_INSTANCE_LAYERS", + "VK_LAYER_LUNARG_standard_validation")); Process::RegisterEnvironmentModification( - Process::EnvironmentModification(EnvMod::Append, EnvSep::Platform, "VK_DEVICE_LAYERS", - "VK_LAYER_LUNARG_standard_validation")); + EnvironmentModification(EnvMod::Append, EnvSep::Platform, "VK_DEVICE_LAYERS", + "VK_LAYER_LUNARG_standard_validation")); } else { diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index f0007aa90..94ab2f096 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -5579,8 +5579,8 @@ ReplayStatus Vulkan_CreateReplayDevice(const char *logfile, IReplayDriver **driv RDCDEBUG("Creating a VulkanReplay replay device"); // disable the layer env var, just in case the user left it set from a previous capture run - Process::RegisterEnvironmentModification(Process::EnvironmentModification( - EnvMod::Set, EnvSep::NoSep, "ENABLE_VULKAN_RENDERDOC_CAPTURE", "0")); + Process::RegisterEnvironmentModification( + EnvironmentModification(EnvMod::Set, EnvSep::NoSep, "ENABLE_VULKAN_RENDERDOC_CAPTURE", "0")); Process::ApplyEnvironmentModification(); void *module = Process::LoadModule(VulkanLibraryName); diff --git a/renderdoc/os/os_specific.h b/renderdoc/os/os_specific.h index 07ecd8f66..357e83367 100644 --- a/renderdoc/os/os_specific.h +++ b/renderdoc/os/os_specific.h @@ -48,25 +48,13 @@ struct CaptureOptions; namespace Process { -struct EnvironmentModification -{ - EnvironmentModification() : mod(EnvMod::Set), sep(EnvSep::NoSep), name(""), value("") {} - EnvironmentModification(EnvMod m, EnvSep s, const char *n, const char *v) - : mod(m), sep(s), name(n), value(v) - { - } - EnvMod mod; - EnvSep sep; - string name; - string value; -}; void RegisterEnvironmentModification(EnvironmentModification modif); void ApplyEnvironmentModification(); void StartGlobalHook(const char *pathmatch, const char *logfile, const CaptureOptions &opts); -uint32_t InjectIntoProcess(uint32_t pid, EnvironmentModification *env, const char *logfile, - const CaptureOptions &opts, bool waitForExit); +uint32_t InjectIntoProcess(uint32_t pid, const rdctype::array &env, + const char *logfile, const CaptureOptions &opts, bool waitForExit); struct ProcessResult { string strStdout, strStderror; @@ -75,8 +63,9 @@ struct ProcessResult uint32_t LaunchProcess(const char *app, const char *workingDir, const char *cmdLine, ProcessResult *result = NULL); uint32_t LaunchAndInjectIntoProcess(const char *app, const char *workingDir, const char *cmdLine, - EnvironmentModification *env, const char *logfile, - const CaptureOptions &opts, bool waitForExit); + const rdctype::array &env, + const char *logfile, const CaptureOptions &opts, + bool waitForExit); void *LoadModule(const char *module); void *GetFunctionAddress(void *module, const char *function); uint32_t GetCurrentPID(); diff --git a/renderdoc/os/posix/posix_process.cpp b/renderdoc/os/posix/posix_process.cpp index 9e9cf3c09..a2fb75bb3 100644 --- a/renderdoc/os/posix/posix_process.cpp +++ b/renderdoc/os/posix/posix_process.cpp @@ -72,9 +72,9 @@ static const string GetAbsoluteAppPathFromName(const string &appName) return string(); } -static vector &GetEnvModifications() +static vector &GetEnvModifications() { - static vector envCallbacks; + static vector envCallbacks; return envCallbacks; } @@ -155,7 +155,7 @@ static string shellExpand(const string &in) return path; } -void Process::RegisterEnvironmentModification(Process::EnvironmentModification modif) +void Process::RegisterEnvironmentModification(EnvironmentModification modif) { GetEnvModifications().push_back(modif); } @@ -178,11 +178,11 @@ void Process::ApplyEnvironmentModification() { EnvironmentModification &m = modifications[i]; - string value = currentEnv[m.name]; + string value = currentEnv[m.name.c_str()]; switch(m.mod) { - case EnvMod::Set: value = m.value; break; + case EnvMod::Set: value = m.value.c_str(); break; case EnvMod::Append: { if(!value.empty()) @@ -192,7 +192,7 @@ void Process::ApplyEnvironmentModification() else if(m.sep == EnvSep::SemiColon) value += ";"; } - value += m.value; + value += m.value.c_str(); break; } case EnvMod::Prepend: @@ -206,7 +206,7 @@ void Process::ApplyEnvironmentModification() } else { - value = m.value; + value = m.value.c_str(); } break; } @@ -403,8 +403,8 @@ static pid_t RunProcess(const char *app, const char *workingDir, const char *cmd return childPid; } -uint32_t Process::InjectIntoProcess(uint32_t pid, EnvironmentModification *env, const char *logfile, - const CaptureOptions &opts, bool waitForExit) +uint32_t Process::InjectIntoProcess(uint32_t pid, const rdctype::array &env, + const char *logfile, const CaptureOptions &opts, bool waitForExit) { RDCUNIMPLEMENTED("Injecting into already running processes on linux"); return 0; @@ -460,7 +460,8 @@ uint32_t Process::LaunchProcess(const char *app, const char *workingDir, const c } uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workingDir, - const char *cmdLine, EnvironmentModification *envList, + const char *cmdLine, + const rdctype::array &envList, const char *logfile, const CaptureOptions &opts, bool waitForExit) { @@ -475,21 +476,8 @@ uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workin map env = EnvStringToEnvMap((const char **)currentEnvironment); vector &modifications = GetEnvModifications(); - if(envList) - { - for(;;) - { - EnvironmentModification e = *envList; - e.name = trim(e.name); - - if(e.name == "") - break; - - modifications.push_back(e); - - envList++; - } - } + for(const EnvironmentModification &e : envList) + modifications.push_back(e); if(logfile == NULL) logfile = ""; @@ -529,11 +517,11 @@ uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workin { EnvironmentModification &m = modifications[i]; - string &value = env[m.name]; + string &value = env[m.name.c_str()]; switch(m.mod) { - case EnvMod::Set: value = m.value; break; + case EnvMod::Set: value = m.value.c_str(); break; case EnvMod::Append: { if(!value.empty()) @@ -543,7 +531,7 @@ uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workin else if(m.sep == EnvSep::SemiColon) value += ";"; } - value += m.value; + value += m.value.c_str(); break; } case EnvMod::Prepend: @@ -557,7 +545,7 @@ uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workin } else { - value = m.value; + value = m.value.c_str(); } break; } diff --git a/renderdoc/os/win32/sys_win32_hooks.cpp b/renderdoc/os/win32/sys_win32_hooks.cpp index 653df66fc..58abbc398 100644 --- a/renderdoc/os/win32/sys_win32_hooks.cpp +++ b/renderdoc/os/win32/sys_win32_hooks.cpp @@ -317,8 +317,10 @@ private: if(inject) { + rdctype::array env; + // inherit logfile and capture options - uint32_t ident = RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId, NULL, + uint32_t ident = RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId, env, RenderDoc::Inst().GetLogFile(), RenderDoc::Inst().GetCaptureOptions(), false); @@ -401,8 +403,10 @@ private: if(inject) { + rdctype::array env; + // inherit logfile and capture options - uint32_t ident = RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId, NULL, + uint32_t ident = RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId, env, RenderDoc::Inst().GetLogFile(), RenderDoc::Inst().GetCaptureOptions(), false); diff --git a/renderdoc/os/win32/win32_process.cpp b/renderdoc/os/win32/win32_process.cpp index 5cf1cd3f5..bc2abb657 100644 --- a/renderdoc/os/win32/win32_process.cpp +++ b/renderdoc/os/win32/win32_process.cpp @@ -44,9 +44,9 @@ static wstring lowercase(wstring in) return ret; } -static vector &GetEnvModifications() +static vector &GetEnvModifications() { - static vector envCallbacks; + static vector envCallbacks; return envCallbacks; } @@ -78,7 +78,7 @@ static map EnvStringToEnvMap(const wchar_t *envstring) return ret; } -void Process::RegisterEnvironmentModification(Process::EnvironmentModification modif) +void Process::RegisterEnvironmentModification(EnvironmentModification modif) { GetEnvModifications().push_back(modif); } @@ -102,7 +102,7 @@ void Process::ApplyEnvironmentModification() // set all names to lower case so we can do case-insensitive lookups, but // preserve the original name so that added variables maintain the same case - wstring name = StringFormat::UTF82Wide(m.name); + wstring name = StringFormat::UTF82Wide(m.name.c_str()); wstring lowername = lowercase(name); string value; @@ -116,7 +116,7 @@ void Process::ApplyEnvironmentModification() switch(m.mod) { - case EnvMod::Set: value = m.value; break; + case EnvMod::Set: value = m.value.c_str(); break; case EnvMod::Append: { if(!value.empty()) @@ -126,7 +126,7 @@ void Process::ApplyEnvironmentModification() else if(m.sep == EnvSep::Colon) value += ":"; } - value += m.value; + value += m.value.c_str(); break; } case EnvMod::Prepend: @@ -140,7 +140,7 @@ void Process::ApplyEnvironmentModification() } else { - value = m.value; + value = m.value.c_str(); } break; } @@ -172,7 +172,7 @@ extern "C" __declspec(dllexport) void __cdecl INTERNAL_SetLogFile(const char *lo RenderDoc::Inst().SetLogFile(log); } -static Process::EnvironmentModification tempEnvMod; +static EnvironmentModification tempEnvMod; extern "C" __declspec(dllexport) void __cdecl INTERNAL_EnvModName(const char *name) { @@ -480,8 +480,8 @@ static PROCESS_INFORMATION RunProcess(const char *app, const char *workingDir, c return pi; } -uint32_t Process::InjectIntoProcess(uint32_t pid, EnvironmentModification *env, const char *logfile, - const CaptureOptions &opts, bool waitForExit) +uint32_t Process::InjectIntoProcess(uint32_t pid, const rdctype::array &env, + const char *logfile, const CaptureOptions &opts, bool waitForExit) { wstring wlogfile = logfile == NULL ? L"" : StringFormat::UTF82Wide(logfile); @@ -753,29 +753,29 @@ uint32_t Process::InjectIntoProcess(uint32_t pid, EnvironmentModification *env, wstring cmdWithEnv; - if(env) + if(!env.empty()) { cmdWithEnv = paramsAlloc; - for(;;) + for(const EnvironmentModification &e : env) { - string name = trim(env->name); - string value = env->value; + string name = trim(e.name.c_str()); + string value = e.value.c_str(); if(name == "") break; cmdWithEnv += L" +env-"; - switch(env->mod) + switch(e.mod) { case EnvMod::Set: cmdWithEnv += L"replace"; break; case EnvMod::Append: cmdWithEnv += L"append"; break; case EnvMod::Prepend: cmdWithEnv += L"prepend"; break; } - if(env->mod != EnvMod::Set) + if(e.mod != EnvMod::Set) { - switch(env->sep) + switch(e.sep) { case EnvSep::Platform: cmdWithEnv += L"-platform"; break; case EnvSep::SemiColon: cmdWithEnv += L"-semicolon"; break; @@ -806,8 +806,6 @@ uint32_t Process::InjectIntoProcess(uint32_t pid, EnvironmentModification *env, cmdWithEnv += L"\"" + StringFormat::UTF82Wide(name) + L"\" "; cmdWithEnv += L"\"" + StringFormat::UTF82Wide(value) + L"\" "; - - env++; } commandLine = (wchar_t *)cmdWithEnv.c_str(); @@ -870,14 +868,14 @@ uint32_t Process::InjectIntoProcess(uint32_t pid, EnvironmentModification *env, InjectFunctionCall(hProcess, loc, "INTERNAL_GetTargetControlIdent", &controlident, sizeof(controlident)); - if(env) + if(!env.empty()) { - for(;;) + for(const EnvironmentModification &e : env) { - string name = trim(env->name); - string value = env->value; - EnvMod mod = env->mod; - EnvSep sep = env->sep; + string name = trim(e.name.c_str()); + string value = e.value.c_str(); + EnvMod mod = e.mod; + EnvSep sep = e.sep; if(name == "") break; @@ -888,13 +886,11 @@ uint32_t Process::InjectIntoProcess(uint32_t pid, EnvironmentModification *env, value.size() + 1); InjectFunctionCall(hProcess, loc, "INTERNAL_EnvSep", &sep, sizeof(sep)); InjectFunctionCall(hProcess, loc, "INTERNAL_EnvMod", &mod, sizeof(mod)); - - env++; } // parameter is unused - InjectFunctionCall(hProcess, loc, "INTERNAL_ApplyEnvMods", env, - sizeof(EnvironmentModification)); + void *dummy = NULL; + InjectFunctionCall(hProcess, loc, "INTERNAL_ApplyEnvMods", &dummy, sizeof(dummy)); } } @@ -959,7 +955,8 @@ uint32_t Process::LaunchProcess(const char *app, const char *workingDir, const c } uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workingDir, - const char *cmdLine, EnvironmentModification *env, + const char *cmdLine, + const rdctype::array &env, const char *logfile, const CaptureOptions &opts, bool waitForExit) { diff --git a/renderdoc/replay/entry_points.cpp b/renderdoc/replay/entry_points.cpp index ff4d14631..09633516a 100644 --- a/renderdoc/replay/entry_points.cpp +++ b/renderdoc/replay/entry_points.cpp @@ -260,21 +260,23 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetConfigSetting(const char extern "C" RENDERDOC_API void *RENDERDOC_CC RENDERDOC_MakeEnvironmentModificationList(int numElems) { - return new Process::EnvironmentModification[numElems + 1]; // last one is a terminator + rdctype::array *ret = new rdctype::array(); + create_array_uninit(*ret, (size_t)numElems); + return ret; } extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetEnvironmentModification( void *mem, int idx, const char *variable, const char *value, EnvMod type, EnvSep separator) { - Process::EnvironmentModification *mods = (Process::EnvironmentModification *)mem; + rdctype::array *mods = (rdctype::array *)mem; - mods[idx] = Process::EnvironmentModification(type, separator, variable, value); + mods->elems[idx] = EnvironmentModification(type, separator, variable, value); } extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_FreeEnvironmentModificationList(void *mem) { - Process::EnvironmentModification *mods = (Process::EnvironmentModification *)mem; - delete[] mods; + rdctype::array *mods = (rdctype::array *)mem; + delete mods; } extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetDebugLogFile(const char *log) @@ -400,11 +402,11 @@ RENDERDOC_CreateReplayRenderer(const char *logfile, float *progress, IReplayRend } extern "C" RENDERDOC_API uint32_t RENDERDOC_CC -RENDERDOC_ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, void *env, - const char *logfile, const CaptureOptions &opts, bool32 waitForExit) +RENDERDOC_ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, + const rdctype::array &env, const char *logfile, + const CaptureOptions &opts, bool32 waitForExit) { - return Process::LaunchAndInjectIntoProcess(app, workingDir, cmdLine, - (Process::EnvironmentModification *)env, logfile, opts, + return Process::LaunchAndInjectIntoProcess(app, workingDir, cmdLine, env, logfile, opts, waitForExit != 0); } @@ -420,11 +422,11 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartGlobalHook(const char Process::StartGlobalHook(pathmatch, logfile, opts); } -extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_InjectIntoProcess( - uint32_t pid, void *env, const char *logfile, const CaptureOptions &opts, bool32 waitForExit) +extern "C" RENDERDOC_API uint32_t RENDERDOC_CC +RENDERDOC_InjectIntoProcess(uint32_t pid, const rdctype::array &env, + const char *logfile, const CaptureOptions &opts, bool32 waitForExit) { - return Process::InjectIntoProcess(pid, (Process::EnvironmentModification *)env, logfile, opts, - waitForExit != 0); + return Process::InjectIntoProcess(pid, env, logfile, opts, waitForExit != 0); } static void writeToByteVector(void *context, void *data, int size) diff --git a/renderdoccmd/renderdoccmd.cpp b/renderdoccmd/renderdoccmd.cpp index 2b296e4d1..367440784 100644 --- a/renderdoccmd/renderdoccmd.cpp +++ b/renderdoccmd/renderdoccmd.cpp @@ -320,9 +320,11 @@ struct CaptureCommand : public Command std::cout << std::endl; + rdctype::array env; + uint32_t ident = RENDERDOC_ExecuteAndInject( executable.c_str(), workingDir.empty() ? "" : workingDir.c_str(), - cmdLine.empty() ? "" : cmdLine.c_str(), NULL, logFile.empty() ? "" : logFile.c_str(), opts, + cmdLine.empty() ? "" : cmdLine.c_str(), env, logFile.empty() ? "" : logFile.c_str(), opts, parser.exist("wait-for-exit")); if(ident == 0) @@ -382,7 +384,9 @@ struct InjectCommand : public Command std::cout << "Injecting into PID " << PID << std::endl; - uint32_t ident = RENDERDOC_InjectIntoProcess(PID, NULL, logFile.empty() ? "" : logFile.c_str(), + rdctype::array env; + + uint32_t ident = RENDERDOC_InjectIntoProcess(PID, env, logFile.empty() ? "" : logFile.c_str(), opts, parser.exist("wait-for-exit")); if(ident == 0) @@ -566,7 +570,8 @@ struct CapAltBitCommand : public Command int numEnvs = int(rest.size() / 3); - void *env = RENDERDOC_MakeEnvironmentModificationList(numEnvs); + rdctype::array env; + env.create(numEnvs); for(int i = 0; i < numEnvs; i++) { @@ -623,12 +628,10 @@ struct CapAltBitCommand : public Command else { std::cerr << "Invalid generated capaltbit env '" << rest[i * 3 + 0] << std::endl; - RENDERDOC_FreeEnvironmentModificationList(env); return 0; } - RENDERDOC_SetEnvironmentModification(env, i, rest[i * 3 + 1].c_str(), rest[i * 3 + 2].c_str(), - type, sep); + env[i] = EnvironmentModification(type, sep, rest[i * 3 + 1].c_str(), rest[i * 3 + 2].c_str()); } string debuglog = parser.get("debuglog"); @@ -638,8 +641,6 @@ struct CapAltBitCommand : public Command int ret = RENDERDOC_InjectIntoProcess(parser.get("pid"), env, parser.get("log").c_str(), cmdopts, false); - RENDERDOC_FreeEnvironmentModificationList(env); - return ret; } };