diff --git a/spec/support/time.cr b/spec/support/time.cr index 2b4738b5d71e..080ba4830c57 100644 --- a/spec/support/time.cr +++ b/spec/support/time.cr @@ -66,9 +66,9 @@ end fun SetDynamicTimeZoneInformation(lpTimeZoneInformation : DYNAMIC_TIME_ZONE_INFORMATION*) : BOOL end - private SeTimeZonePrivilege = Crystal::System.to_wstr("SeTimeZonePrivilege") - module Crystal::System::Time + private SeTimeZonePrivilege = System.wstr_literal "SeTimeZonePrivilege" + # Enable the `SeTimeZonePrivilege` privilege before changing the system time # zone. This is necessary because the privilege is by default granted but # disabled for any new process. This only needs to be done once per run. diff --git a/src/crystal/system/win32/mime.cr b/src/crystal/system/win32/mime.cr index 54d6fddd87c3..e171296b1cb9 100644 --- a/src/crystal/system/win32/mime.cr +++ b/src/crystal/system/win32/mime.cr @@ -1,7 +1,7 @@ require "./windows_registry" module Crystal::System::MIME - CONTENT_TYPE = "Content Type".to_utf16 + CONTENT_TYPE = System.wstr_literal "Content Type" # Load MIME types from operating system source. def self.load diff --git a/src/crystal/system/win32/time.cr b/src/crystal/system/win32/time.cr index 9b547226130a..df53e95d70df 100644 --- a/src/crystal/system/win32/time.cr +++ b/src/crystal/system/win32/time.cr @@ -192,10 +192,10 @@ module Crystal::System::Time return stdname, dstname end - REGISTRY_TIME_ZONES = %q(SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones).to_utf16 - Std = "Std".to_utf16 - Dlt = "Dlt".to_utf16 - TZI = "TZI".to_utf16 + REGISTRY_TIME_ZONES = System.wstr_literal %q(SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones) + Std = System.wstr_literal "Std" + Dlt = System.wstr_literal "Dlt" + TZI = System.wstr_literal "TZI" # Searches the registry for an English name of a time zone named *stdname* or *dstname* # and returns the English name. diff --git a/src/crystal/system/win32/user.cr b/src/crystal/system/win32/user.cr index 4a06570c72b8..5776df2aa2a0 100644 --- a/src/crystal/system/win32/user.cr +++ b/src/crystal/system/win32/user.cr @@ -172,8 +172,8 @@ module Crystal::System::User end end - private REGISTRY_PROFILE_LIST = %q(SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList).to_utf16 - private ProfileImagePath = "ProfileImagePath".to_utf16 + private REGISTRY_PROFILE_LIST = System.wstr_literal %q(SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList) + private ProfileImagePath = System.wstr_literal "ProfileImagePath" private def self.lookup_home_directory(uid : String, username : String) : String? # If this user has logged in at least once their home path should be stored diff --git a/src/crystal/system/win32/windows_sdk.cr b/src/crystal/system/win32/windows_sdk.cr index 471826f71f94..e7df50969d09 100644 --- a/src/crystal/system/win32/windows_sdk.cr +++ b/src/crystal/system/win32/windows_sdk.cr @@ -1,11 +1,11 @@ require "./windows_registry" module Crystal::System::WindowsSDK - REGISTRY_WIN10_SDK_64 = %q(SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v10.0).to_utf16 - REGISTRY_WIN10_SDK_32 = %q(SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0).to_utf16 + REGISTRY_WIN10_SDK_64 = System.wstr_literal %q(SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) + REGISTRY_WIN10_SDK_32 = System.wstr_literal %q(SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) - InstallationFolder = "InstallationFolder".to_utf16 - ProductVersion = "ProductVersion".to_utf16 + InstallationFolder = System.wstr_literal "InstallationFolder" + ProductVersion = System.wstr_literal "ProductVersion" def self.find_win10_sdk_libpath : ::Path? # ported from Common7\Tools\vsdevcmd\core\winsdk.bat (loaded by the MSVC diff --git a/src/crystal/system/windows.cr b/src/crystal/system/windows.cr index 90b38396cf8f..16bb2d1e7ee7 100644 --- a/src/crystal/system/windows.cr +++ b/src/crystal/system/windows.cr @@ -16,6 +16,22 @@ module Crystal::System str.check_no_null_byte(name).to_utf16.to_unsafe end + # Converts the string literal *str* into a `Slice` of UTF-16 code points. + # *str* must not contain embedded null characters. + # + # This is equivalent to the macro `StringLiteral#to_utf16` if slice literals + # are available, and the normal `String#to_utf16` otherwise. This is useful + # for passing constant string arguments to Win32 functions. + {% if compare_versions(Crystal::VERSION, "1.16.0") >= 0 %} + macro wstr_literal(str) + \{{ str.to_utf16 }} + end + {% else %} + macro wstr_literal(str) + (\{{ str }}).check_no_null_byte.to_utf16 + end + {% end %} + def self.sid_to_s(sid : LibC::SID*) : String if LibC.ConvertSidToStringSidW(sid, out ptr) == 0 raise RuntimeError.from_winerror("ConvertSidToStringSidW") diff --git a/src/crystal/tracing.cr b/src/crystal/tracing.cr index 7d853ed066bc..912a4bad171b 100644 --- a/src/crystal/tracing.cr +++ b/src/crystal/tracing.cr @@ -147,6 +147,7 @@ module Crystal {% if flag?(:win32) %} buf = uninitialized UInt16[256] + # FIXME: use `System.wstr_literal` after #15746 is available name = UInt16.static_array({% for chr in "CRYSTAL_TRACE".chars %}{{chr.ord}}, {% end %} 0) len = LibC.GetEnvironmentVariableW(name, buf, buf.size) parse_sections(buf.to_slice[0...len]) if len > 0