summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGangzheng Tong <tonggangzheng@gmail.com>2025-09-08 10:24:05 -0700
committerGitHub <noreply@github.com>2025-09-08 17:24:05 +0000
commit3aff764c2b5d613f766538d27e0b9f448e7ed5ca (patch)
tree0d21cd8486bb8914a933cd58841e4c9bb246df70
parent8b512c49d163af1df33e940acc3c4a230f0d00b7 (diff)
Use wide char version of Windows API (#8390)
This PR modernizes the Windows-specific code by replacing ANSI Windows API functions with their Unicode (wide character) counterparts. This change ensures proper handling of Unicode file paths and strings on Windows systems. ### File Operations (`source/core/slang-io.cpp`) - `DeleteFileA` → `DeleteFileW` - `GetTempPathA` → `GetTempPathW` - `GetTempFileNameA` → `GetTempFileNameW` - `RemoveDirectoryA` → `RemoveDirectoryW` - `SHFileOperationA` → `SHFileOperationW` - `GetModuleFileNameA` → `GetModuleFileNameW` with UTF-8 conversion ### Platform Operations (`source/core/slang-platform.cpp`) - `GetModuleHandleExA` → `GetModuleHandleExW` - `LoadLibraryExA` → `LoadLibraryExW` - `LoadLibraryA` → `LoadLibraryW` - `OutputDebugStringA` → `OutputDebugStringW` ### Runtime and Tools - `MessageBoxA` → `MessageBoxW` in slang-rt - `GetCurrentDirectoryA` → `GetCurrentDirectoryW` in slang-fiddle - String literal conversion to wide strings in vk-pipeline-create --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Gangzheng Tong <gtong-nv@users.noreply.github.com> Co-authored-by: slangbot <ellieh+slangbot@nvidia.com> Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
-rw-r--r--source/core/slang-io.cpp69
-rw-r--r--source/core/slang-platform.cpp17
-rw-r--r--source/slang-rt/slang-rt.cpp2
-rw-r--r--tools/slang-fiddle/slang-fiddle-main.cpp9
-rw-r--r--tools/vk-pipeline-create/main.cpp4
5 files changed, 64 insertions, 37 deletions
diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp
index 0720e788f..36c8c560d 100644
--- a/source/core/slang-io.cpp
+++ b/source/core/slang-io.cpp
@@ -48,8 +48,9 @@ namespace Slang
/* static */ SlangResult File::remove(const String& fileName)
{
#ifdef _WIN32
- // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea
- if (DeleteFileA(fileName.getBuffer()))
+
+ // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilew
+ if (DeleteFileW(fileName.toWString()))
{
return SLANG_OK;
}
@@ -77,10 +78,10 @@ namespace Slang
int count = MAX_PATH + 1;
while (true)
{
- char* chars = tempPath.prepareForAppend(count);
+ wchar_t* wideChars = (wchar_t*)_alloca(count * sizeof(wchar_t));
// Gets the temp path env string (no guarantee it's a valid path).
- // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha
- DWORD ret = ::GetTempPathA(count - 1, chars);
+ // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw
+ DWORD ret = ::GetTempPathW(count - 1, wideChars);
if (ret == 0)
{
return SLANG_FAIL;
@@ -90,7 +91,7 @@ namespace Slang
count = ret + 1;
continue;
}
- tempPath.appendInPlace(chars, count);
+ tempPath = String::fromWString(wideChars);
break;
}
}
@@ -104,19 +105,18 @@ namespace Slang
String tempFileName;
{
- int count = MAX_PATH + 1;
- char* chars = tempFileName.prepareForAppend(count);
+ wchar_t wideChars[MAX_PATH + 1];
- // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamea
+ // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamew
// Generates a temporary file name.
// Will create a file with this name.
- DWORD ret = ::GetTempFileNameA(tempPath.getBuffer(), prefix.getBuffer(), 0, chars);
+ DWORD ret = ::GetTempFileNameW(tempPath.toWString(), prefix.toWString(), 0, wideChars);
if (ret == 0)
{
return SLANG_FAIL;
}
- tempFileName.appendInPlace(chars, ::strlen(chars));
+ tempFileName = String::fromWString(wideChars);
}
SLANG_ASSERT(File::exists(tempFileName));
@@ -768,8 +768,8 @@ SlangResult Path::remove(const String& path)
{
case SLANG_PATH_TYPE_FILE:
{
- // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea
- if (DeleteFileA(path.getBuffer()))
+ // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilew
+ if (DeleteFileW(path.toWString()))
{
return SLANG_OK;
}
@@ -777,8 +777,8 @@ SlangResult Path::remove(const String& path)
}
case SLANG_PATH_TYPE_DIRECTORY:
{
- // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya
- if (RemoveDirectoryA(path.getBuffer()))
+ // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectoryw
+ if (RemoveDirectoryW(path.toWString()))
{
return SLANG_OK;
}
@@ -810,20 +810,26 @@ SlangResult Path::remove(const String& path)
// Path::remove() doesn't support remove a non-empty directory, so we need to implement
// a simple function to remove the directory recursively.
#ifdef _WIN32
- // https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shfileoperationa
+ // https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shfileoperationw
// Note: the fromPath requires a double-null-terminated string.
- String newPath = path;
- newPath.append('\0');
- SHFILEOPSTRUCTA file_op = {
+ // Convert to wide string first, then manually create double-null-terminated buffer
+ auto widePath = path.toWString();
+ Index widePathLen = wcslen(widePath);
+ wchar_t* doubleNullPath = (wchar_t*)_alloca((widePathLen + 2) * sizeof(wchar_t));
+ wcscpy(doubleNullPath, widePath);
+ doubleNullPath[widePathLen] = L'\0'; // First null terminator
+ doubleNullPath[widePathLen + 1] = L'\0'; // Second null terminator for SHFileOperationW
+
+ SHFILEOPSTRUCTW file_op = {
NULL,
FO_DELETE,
- newPath.begin(),
+ doubleNullPath,
nullptr,
FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT,
false,
0,
nullptr};
- int ret = SHFileOperationA(&file_op);
+ int ret = SHFileOperationW(&file_op);
if (ret)
{
return SLANG_FAIL;
@@ -973,13 +979,28 @@ static SlangResult _calcExectuablePath(char* outPath, size_t* ioSize)
SLANG_ASSERT(bufferSize > 0);
#if SLANG_WINDOWS_FAMILY
- // https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-getmodulefilenamea
+ // https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-getmodulefilenamew
- DWORD res = ::GetModuleFileNameA(::GetModuleHandle(nullptr), outPath, DWORD(bufferSize));
+ // Use wide character version and convert back to UTF-8
+ wchar_t* widePath = (wchar_t*)_alloca(bufferSize * sizeof(wchar_t));
+ DWORD res = ::GetModuleFileNameW(::GetModuleHandle(nullptr), widePath, DWORD(bufferSize));
// If it fits it's the size not including terminator. So must be less than bufferSize
if (res < bufferSize)
{
- return SLANG_OK;
+ // Convert back to UTF-8
+ int utf8Len = WideCharToMultiByte(
+ CP_UTF8,
+ 0,
+ widePath,
+ -1,
+ outPath,
+ (int)bufferSize,
+ nullptr,
+ nullptr);
+ if (utf8Len > 0)
+ {
+ return SLANG_OK;
+ }
}
return SLANG_E_BUFFER_TOO_SMALL;
#elif SLANG_LINUX_FAMILY
diff --git a/source/core/slang-platform.cpp b/source/core/slang-platform.cpp
index 25e6bc6f0..75c1b96cd 100644
--- a/source/core/slang-platform.cpp
+++ b/source/core/slang-platform.cpp
@@ -122,7 +122,7 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY);
handleOut = nullptr;
if (!platformFileName || strlen(platformFileName) == 0)
{
- if (!GetModuleHandleExA(0, nullptr, (HMODULE*)&handleOut))
+ if (!GetModuleHandleExW(0, nullptr, (HMODULE*)&handleOut))
return SLANG_FAIL;
return SLANG_OK;
}
@@ -131,12 +131,14 @@ SLANG_COMPILE_TIME_ASSERT(E_OUTOFMEMORY == SLANG_E_OUT_OF_MEMORY);
// First attempt tries on the directories explicitly specified with AddDllDirectory(),
// If it failed to find one, we will search over all PATH.
// Windows API made two approaches mutually exclusive and we need to try two times.
- // https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa
- HMODULE h = LoadLibraryExA(platformFileName, nullptr, LOAD_LIBRARY_SEARCH_USER_DIRS);
- // If LoadLibraryExA failed, try again with LoadLibraryA.
- // https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-loadlibrarya
+ // https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw
+ String platformFileNameStr(platformFileName);
+ HMODULE h =
+ LoadLibraryExW(platformFileNameStr.toWString(), nullptr, LOAD_LIBRARY_SEARCH_USER_DIRS);
+ // If LoadLibraryExW failed, try again with LoadLibraryW.
+ // https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-loadlibraryw
if (!h)
- h = LoadLibraryA(platformFileName);
+ h = LoadLibraryW(platformFileNameStr.toWString());
// If still not found, return an error.
if (!h)
{
@@ -356,7 +358,8 @@ static const PlatformFlags s_familyFlags[int(PlatformFamily::CountOf)] = {
/* static */ SlangResult PlatformUtil::outputDebugMessage([[maybe_unused]] const char* text)
{
#ifdef _WIN32
- OutputDebugStringA(text);
+ String textStr(text);
+ OutputDebugStringW(textStr.toWString());
return SLANG_OK;
#else
return SLANG_E_NOT_AVAILABLE;
diff --git a/source/slang-rt/slang-rt.cpp b/source/slang-rt/slang-rt.cpp
index 35ffdb138..d264ae300 100644
--- a/source/slang-rt/slang-rt.cpp
+++ b/source/slang-rt/slang-rt.cpp
@@ -16,7 +16,7 @@ extern "C"
{
fprintf(stderr, "%s", errorMessage.getBuffer());
#if SLANG_WINDOWS_FAMILY
- MessageBoxA(0, errorMessage.getBuffer(), "Slang Runtime Error", MB_ICONERROR);
+ MessageBoxW(0, errorMessage.toWString(), L"Slang Runtime Error", MB_ICONERROR);
#endif
abort();
}
diff --git a/tools/slang-fiddle/slang-fiddle-main.cpp b/tools/slang-fiddle/slang-fiddle-main.cpp
index cf8407995..fea16dafe 100644
--- a/tools/slang-fiddle/slang-fiddle-main.cpp
+++ b/tools/slang-fiddle/slang-fiddle-main.cpp
@@ -425,9 +425,12 @@ int main(int argc, char const* const* argv)
}
fprintf(stderr, "\n");
- char buffer[1024];
- GetCurrentDirectoryA(sizeof(buffer), buffer);
- fprintf(stderr, "cwd: %s\n", buffer);
+ wchar_t wideBuffer[1024];
+ GetCurrentDirectoryW(sizeof(wideBuffer) / sizeof(wideBuffer[0]), wideBuffer);
+
+ // Convert to UTF-8 using String::fromWString
+ String currentDir = String::fromWString(wideBuffer);
+ fprintf(stderr, "cwd: %s\n", currentDir.getBuffer());
return 1;
#endif
diff --git a/tools/vk-pipeline-create/main.cpp b/tools/vk-pipeline-create/main.cpp
index 91abb90bc..5685affb4 100644
--- a/tools/vk-pipeline-create/main.cpp
+++ b/tools/vk-pipeline-create/main.cpp
@@ -278,8 +278,8 @@ void PipelineCreationReplay::initVulkanAPI(IDevice* device)
vkAPI.device = (VkDevice)(handle.handles[2].value);
vkAPI.instance = (VkInstance)(handle.handles[0].value);
#if SLANG_WINDOWS_FAMILY
- auto dynamicLibraryName = "vulkan-1.dll";
- HMODULE module = ::LoadLibraryA(dynamicLibraryName);
+ auto dynamicLibraryName = L"vulkan-1.dll";
+ HMODULE module = ::LoadLibraryW(dynamicLibraryName);
vkAPI.vulkanLibraryHandle = (void*)module;
#define VK_API_GET_GLOBAL_PROC(x) vkAPI.x = (PFN_##x)GetProcAddress(module, #x);
#else