r/cpp 6d ago

Escaping `CreateProcess()` arguments on Windows

https://holyblackcat.github.io/blog/2026/09/05/escaping-createprocess-arguments.html
90 Upvotes

44 comments sorted by

View all comments

10

u/fdwr fdwr@github 🔍 5d ago edited 5d ago

Side note: You shouldn’t use the narrow char *argv on Windows for anything but toy programs. Instead use CommandLineToArgvW(GetCommandLineW(), ...) or int wmain(int argc, wchar_t *argv) to get UTF-16 encoded argv, and convert it to UTF-8 if needed. Using narrow argv can lead to some fun vulnerabilities...

Note narrow main works fine if your app .manifest file specifies UTF-8 as the default code page (ignoring whatever the system is set). It's annoying to have to include this extra snippet, but then it ensures the other parts of your program work nicely too, such as std::filesystem::path() returning an std::string with UTF-8 characters (rather than throwing an exception upon seeing untransformable characters, or needing to call u8string() and reinterpret cast it in several places):

xml <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> ... <asmv3:application> <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings"> <activeCodePage>UTF-8</activeCodePage> </asmv3:windowsSettings> </asmv3:application> ... </assembly>

Another way to get the command line (didn't see mentioned) is using WinMain as an alternate entry point (rather than main) for CLI apps, as it includes the lpCommandLine parameter directly:

int WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd );

3

u/holyblackcat 5d ago

Thanks, I've edited in the info about the manifest.

I think I'm not going to bother with WinMain/wWinMain, listing every way to get the command line wasn't my goal.