Microsoft Dev Blogs

How can I add an environment variable to a process launched via Shell­Execute­Ex or IContext­Menu?

thumbnail

Adding Environment Variables to a Process Launched via Shell­Execute­Ex or IContext­Menu

To add an environment variable to a process launched via Shell­Execute­Ex or IContext­Menu, you can leverage a custom site and the IShell­Execute­Hook 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 Shell­Execute­Ex 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 Shell­Execute­Ex, 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 IContext­Menu 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.