How can I add an environment variable to a process launched via ShellExecuteEx or IContextMenu?

Adding Environment Variables to a Process Launched via ShellExecuteEx or IContextMenu
To add an environment variable to a process launched via ShellExecuteEx or IContextMenu, you can leverage a custom site and the IShellExecuteHook interface. This interface allows you to customize the creation of processes by adding a site object that can modify the execution process.
Here is an example in C++ using the C++/WinRT library:
// Create a custom site that sets an environment variable
struct CustomSite : winrt::implements<CustomSite, winrt::IUnknown, IShellExecuteHook>
{
HRESULT STDMETHODCALLTYPE Execute(
IUnknown* pUnknown,
LPCWSTR pszWorkingDir,
LPCWSTR pszCmdLine,
LPCWSTR pszEnvVar)
{
// Set the environment variable
SetEnvironmentVariable(pszEnvVar, L"custom_value");
// Return the result of the original Execute method
return pUnknown->QueryInterface<IShellExecuteHook>()->Execute(
pszWorkingDir, pszCmdLine, pszEnvVar);
}
};
// Launch a process via ShellExecuteEx and pass a custom site
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.fMask = SEE_MASK_HMONITOR;
sei.lpVerb = L"runas";
sei.lpFile = L"notepad.exe";
sei.lpParameters = L"";
sei.hwnd = hwnd;
sei.nShow = SW_SHOWDEFAULT;
sei.hInstApp = GetModuleHandle(NULL);
sei.lpIDList = NULL;
sei.lpClass = NULL;
sei.hkeyClass = NULL;
sei.dwHotKey = 0;
sei.hIcon = NULL;
sei.hMonitor = NULL;
sei.pfnHook = nullptr; // Remove existing hook
sei.lpfnHook = [](HWND, UINT, WPARAM, LPARAM) -> HRESULT
{
// Create and return the custom site
return winrt::make<CustomSite>().as<IShellExecuteHook>().copy_to(INT_PTR(&sei.pfnHook));
};
// Execute the process
BOOL success = ShellExecuteEx(&sei);
This code creates a custom site (implemented as CustomSite) that sets an environment variable (pszEnvVar) with a custom value. It then calls the original Execute method to proceed with the execution of the process.
To pass the custom site to ShellExecuteEx, we assign it to the SHELLEXECUTEINFO struct's pfnHook member. We also set the SEE_MASK_HMONITOR flag to indicate that our pfnHook member contains a valid hook function.
For IContextMenu usage, you need to explicitly set your custom site as the context menu's site.
Remember that this code is just a starting point, and you should handle exceptions and memory management appropriately in a real application.