I used ShellExecuteEx() to call an executable file. And the following are the parameters I set for SHELLEXECUTEINFO structure.
SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS|SEE_MASK_UNICODE;// Set Unicode Flag
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpParameters = TEXT ("/s");
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOWNORMAL;
ShExecInfo.hInstApp = NULL;
ShExecInfo.lpFile = TEXT ( ".\\bin\\x86\\installerx86.exe" );
The ShExecInfo.fMask is set for Unicode, but the ShExecInfo.lpFile is not prepended with "\\?\".
In this case, is my code compatible with Unicode?
You are mixing up concepts. All path strings are Unicode by the time the kernel code uses these strings. The non-Unicode version of ShellExecuteEx (named ShellExecuteExA) simply translates all strings and converts the SHELLEXECUTEINFOA structure to a SHELLEXECUTEINFOW structure, then calls the real api function, ShellExecuteW(). You don’t see these real identifier names in your code since a macro selects between them, but you can certainly see them in the ShellAPI.h SDK #include file.
The
SEE_MASK_UNICODEis a fairly mysterious option, hard to set correctly for one. I think it is related to theCREATE_UNICODE_ENVIRONMENToption for CreateProcess, indicating that the environment for the new process may contain Unicode characters.The
\\?\prefix on the path string selects between Win32 path names and the native Windows kernel path names. Win32 is an API layer on top of the native operating system. There used to be multiple api layers, OS/2 and Posix were once supported but fell out of use. The native operating system is very unlike Win32, it resembles the VMS operating system, the one David Cutler worked on before he got hired by Microsoft to design NT. No such thing as a C: drive there, it only knows, say,\Device\Harddisk0\Partition0.The API layer translates between these two worlds. By prefixing the path string with
\\?\you tell Win32 to use the path string as-is. Which then makes it acquire the capabilities of a native path string, having support for paths as long as 32726 characters and bypassing the infamous Win32 MAX_PATH limitation. These strings being Unicode is implied, that’s all the kernel can handle. ShellExecuteA will otherwise happily convert an 8-bit encoded string that contains this prefix for you.Long story short: it is not automatic. You have to do this explicitly by programming the prefix yourself.