diff --git a/.vscode/launch.json b/.vscode/launch.json index 6e47e5d7..675aa3eb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,18 +4,18 @@ "type": "swift-lldb", "request": "launch", "name": "test_app", - "program": "${workspaceFolder:swiftwinrt}\\out\\${command:cmake.activeBuildPresetName}\\bin\\test_app.exe", + "program": "${workspaceFolder}\\out\\${command:cmake.activeBuildPresetName}\\bin\\test_app.exe", "args": [], - "cwd": "${workspaceFolder:swiftwinrt}/tests", + "cwd": "${workspaceFolder}/tests", "preLaunchTask": "Install" }, { "type": "cppvsdbg", "request": "launch", "name": "test_app (pdb)", - "program": "${workspaceFolder:swiftwinrt}\\out\\${command:cmake.activeBuildPresetName}\\bin\\test_app", + "program": "${workspaceFolder}\\out\\${command:cmake.activeBuildPresetName}\\bin\\test_app", "args": [], - "cwd": "${workspaceFolder:swiftwinrt}/tests", + "cwd": "${workspaceFolder}/tests", "preLaunchTask": "Install" } ] diff --git a/swiftwinrt/Resources/Support/HString.swift b/swiftwinrt/Resources/Support/HString.swift index d7c7d2bb..54e84d52 100644 --- a/swiftwinrt/Resources/Support/HString.swift +++ b/swiftwinrt/Resources/Support/HString.swift @@ -10,10 +10,24 @@ final public class HString { internal private(set) var hString: HSTRING? public init(_ string: String) throws { - self.hString = try string.withCString(encodedAs: UTF16.self) { - var result: HSTRING? - try CHECKED(WindowsCreateString($0, UINT32(wcslen($0)), &result)) - return result + let codeUnitCount = string.utf16.count + var pointer: UnsafeMutablePointer? = nil + var hStringBuffer: HSTRING_BUFFER? = nil + + // Note: Methods like String.withCString are not used here because they do a copy to create a null + // terminated string, and requires an additional copy to create an HSTRING. Instead, a single copy is + // done by using WindowsPreallocateStringBuffer to allocate a buffer and directly copying the string into it. + try CHECKED(WindowsPreallocateStringBuffer(UInt32(codeUnitCount), &pointer, &hStringBuffer)); + guard let pointer else { throw Error(hr: E_FAIL) } + _ = UnsafeMutableBufferPointer(start: pointer, count: codeUnitCount).initialize(from: string.utf16) + + do { + var hString: HSTRING? = nil + try CHECKED(WindowsPromoteStringBuffer(hStringBuffer, &hString)); + self.hString = hString + } catch { + WindowsDeleteStringBuffer(hStringBuffer) + throw error } }