Direct.h from Windows

Lately, I started using Swift on Windows. I noticed that, having imported WinSDK and ucrt, symbols from direct.h such as these ones are still missing. If I edit ucrt.modulemap and include direct.h, the problem goes away.

I'm wondering what's the plan for ucrt.modulemap? It hasn't been touched for a while yet it contains some stuff winsdk.modulemap doesn't. Should I put up a PR that adds this header and call it a day? What's the guideline for this type of things?

cc @compnerd

Awesome! Can’t wait to see what you do with it :slight_smile:

There’s no plan for it per se. It serves a purpose, and seems to be relatively complete for most needs.

Correct, that’s by design. It is the C library, not the windows SDK, and it’s rather stable. It’s similar to the Darwin.C module, which doesn’t seem to have changed in many years either and contains things not in the rest of the Darwin SDK (WinSDK basically covers nearly 50% of the SDK, as modularizibg it is difficult, and so it’s been built up a small amount at a time).

Yes please, though, I don’t think that it should be a complete sub module (I would say, let’s try to match the header to what the equivalent of it or on Unix and see how that is mapped).

The one thing that I’d recommend though: use foundation instead. The file system stuff there is well tested and handles the Unicode conversion and path separator issues, etc.

1 Like

BTW, this is my reasoning for not wanting to encourage people to use this API is that the correct usage for this API is something along the lines of:

func mkdir(_ path: String) throws {
  // The path is limited to `MAX_PATH` (i.e. 260) in the FSR form, including the null terminator.
  // Because the length of the string does not include the null terminator, we need to subtract one.
  guard path.length <= MAX_PATH - 1 {
    throw SystemError(HRESULT: 0x80000135)
  }

  // TODO: filter out invalid characters in the path, ensure that the file system is NTFS, etc.

  // String is UTF-8 encoded, which is _not_ a valid encoding; convert to UTF-16
  // to ensure that any non-ASCII characters are translated correctly.
  _ = try path.withCString(encodedAs: UTF16.self) {
    guard _wmkdir($0) == 0 else {
      throw SystemError(errno: errno)
    }
  }
}

Alternatively, you could check if the path is greater than MAX_PATH - 1, convert to the FSR representation, convert UTF-8 to UTF-16, convert Win32 representation to NT representation, and then make the call to CreateDirectoryExW.

My recommendation is to just use FileManager.default.createDirectory(at:withIntermediateDirectories:attributes:) and not worry about the differences about the underlying system. All of these annoying cases are accounted for, tested, and solved.

If your intent is to implement a VFS layer that abstracts over the file system issues then please ignore this post, it doesn't apply to your work.

1 Like

Thank you for the replies! My intent is precisely to add windows support for a file system library.

I suggest we move the discussion over to the PR: stdlib: Add direct.h to ucrt.modulemap by dduan · Pull Request #32009 · apple/swift · GitHub.