4
votes

I'm using CreateFile to open device. Everything is ok untill device name is too long.

In documentation it is said:

In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. For more information, see Naming Files, Paths, and Namespaces.

I'm trying to use CreateFileW and prepend "\\?\" to the path, but getting invalid handle and

The system cannot find the path specified.

in GetLastError().

So, is this trick valid only for filenames, not for device names? Are there any other ways to avoid this problem?

UPD1: Device name without prepend looks like:

\\.\devicename\EndsBy:\name1.exe|EndsBy:\name2.exe.

Code:

CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0));

2
Do you literally prepend "\\?\" or do you actually prepend "\\\\?\\"?ghostofstandardspast
What does the device name actually look like? What does your code look like?Remy Lebeau
@ghostofstandardspast actually I prepend "\\\\?\\", also trying to prepend ""\\\\?" and some others.nicolausYes
One thing to keep in mind, "\\?\" requires an absolute path to follow. It will also skip some normalization steps like processing . and .., or removing trailing dots and spaces.asveikau
Pleasr edit your question and include your code and other relevant information there instead of in a comment.Captain Obvlious

2 Answers

4
votes

The \\? prefix sends paths straight to the file-system with no preprocessing.

The \\. prefix bypasses the file namespace and uses the Win32 device namespace.

They have separate purposes and cannot be mixed together.

You can try this yourself. For example, this will open the null device:

HANDLE hDevice = ::CreateFileW(L"\\\\.\\NUL", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);

But if you change the path to L"\\\\?\\\\.\\NUL" it will fail.

To answer your question, yes, prefixing paths with \\? is only valid for file-system paths.

2
votes

Some things to try:

  • You can usually replace \\.\ with \\?\ ; it is my understanding that this will not always work, but I don't know what the rules are.

  • If you're on Windows 8 try using CreateFile2 with the \\.\ format; the documentation doesn't mention a path length limitation.

  • Try contacting the vendor of the device driver, who should have realized that this would be a problem and hopefully has a workaround.

  • Try using DefineDosDevice to create an alias for your long path, and opening \\.\myalias with CreateFile. I'm not sure of the proper syntax for the path you're aliasing, but you can use QueryDosDevice to look at the existing aliases for guidance. I believe you will want to use the DDD_RAW_TARGET_PATH flag.

  • Failing all that, you may need to resort to NtCreateFile. You should be able to use CreateFile to open \\.\devicename and then use that handle as the root directory for the call to NtCreateFile. The downside here is that the API is not guaranteed to remain compatible in future versions of Windows.