2

I am on Windows 10, and want to use boost process to start a child. When the child's working directory is too long, I get an exception:

CreateProcess failed: The directory name is invalid.

I wrote a test program to debug this:

#include <boost/process.hpp>
#include <boost/process/async.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <iostream>
#include <iomanip>
#include <thread>
#include <string>
#include <filesystem>

namespace bp = boost::process;

void test(const std::filesystem::path& wdir)
{
  boost::asio::io_context io;
  bp::child child;
  try
  {
    std::filesystem::create_directories(wdir);
    std::cout << "exists " << std::filesystem::exists(wdir) << " len " << wdir.generic_wstring().size() << '\n';
    std::cout << "start proc\n";
    child = bp::child(
      "C:/WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe",
      std::vector<std::string> { "ls" },
      io,
      boost::process::start_dir = LR"(\\?\)" + wdir.generic_wstring());
    std::this_thread::sleep_for(std::chrono::seconds{ 3 });
    child.wait();
  }
  catch (const std::exception& e)
  {
    std::cout << "EXCEPTION " << e.what() << "\n";
  }
  std::cout << "done\n";
}

int main()
{
  std::cout << "short path\n";
  test("D:/tmp/10378020400asdfasdfqw4retf");

  std::cout << "\nlong path\n";
  test("D:/tmp/10378020400826168668/unicode/qwe/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiertzertz/aaaqqqwwwiiiiertzertz/eertz/"
    "iiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiii"
    "iiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiii"
    "iiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"
    "i/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqw"
    "wwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiii"
    "iiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiii"
    "iiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiii"
    "iiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/a"
    "aaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwi"
    "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiii"
    "iiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiii"
    "iiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiii"
    "iiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaq"
    "qqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiii"
    "iiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii/aaaqqqwwwiiiiiiiiiiiii"
    "iiiiiiiiiiiiiiiiiii/");
  return 0;
}

I get this output:

short path
exists 1 len 33
start proc
done

long path
exists 1 len 2177
start proc
EXCEPTION  CreateProcess failed: The directory name is invalid.
done

It seems the problem comes from the internally called CreateProcessW.

The documentation does not mention any limit for lpCurrentDirectory, and also allows UNC paths (hence I tried adding the prefix \\?\), but it does not make any difference whether I use the UNC syntax or not.

My questions are:

  1. Is this an inherent limitation of Windows?
  2. Is there any way to circumvent this limitation using boost?
  3. Is there any way to circumvent this limitation using some other Win32 API function?

What I tired: using normal and UNC paths.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Something hinting at this being an inherent problem can be found [here](https://github.com/MicrosoftDocs/feedback/issues/1441#issuecomment-506574206), but i am not sure if there is a way around this / this also impacts `CreateProcessW` – Raphael Grimm Dec 13 '22 at 16:44
  • This answer may help depending on your use case: [https://stackoverflow.com/a/40305489/487892](https://stackoverflow.com/a/40305489/487892) – drescherjm Dec 13 '22 at 16:44
  • Have a read of [WinAPI - Maximum Path Length Limitation](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry) Specifically _"..To specify an extended-length path, use the "\\?\" prefix..."_ – Richard Critten Dec 13 '22 at 16:59
  • @RichardCritten The ```\\?\``` prefix doesn't work with `CreateProcess()`. – Remy Lebeau Dec 13 '22 at 19:06
  • Per a comment on https://github.com/MicrosoftDocs/feedback/issues/1441: "*Note that we need to be mindful when setting the current directory to a long path in Windows 10. **`CreateProcess` does not support a current directory path length that exceeds `MAX_PATH - 2` characters** (not counting the trailing backslash and null terminator). If the current directory path length is longer than this, `CreateProcess` will fail with an invalid-parameter error when we pass `lpCurrentDirectory` as NULL (i.e. inherit the current directory), though this is a normal and common value for this parameter.*" – Remy Lebeau Dec 13 '22 at 19:06
  • @drescherjm I’ve set this for my application. Otherwise I would not be able to create the long path via `std::filesystem::create_directories` and `std::filesystem::exists` would always return `false` for the long path. – Raphael Grimm Dec 14 '22 at 07:59
  • @RichardCritten I am already adding `\\?\` as a prefix and it does not work. – Raphael Grimm Dec 14 '22 at 08:03
  • @RemyLebeau I saw (and linked) this issue, but hoped there might be a way around this using some other WINAPI function. – Raphael Grimm Dec 14 '22 at 08:04
  • As far as I'm concerned, it is an inherent limitation of Windows, and there is no suitable api to circumvent this limitation. – Jeaninez - MSFT Dec 15 '22 at 03:07

0 Answers0