oHenry Posted October 1, 2023 Share Posted October 1, 2023 (edited) Hi, I am having a problem invoking the "IdnToAscii" (documentation) function to convert an IDN hostname into its "Punycode" form. Description: I'm encountering a problem with the "IdnToAscii" function, when trying to convert an Internationalized Domain Name (IDN) to its ASCII equivalent using the "normaliz.dll" library. While the function call itself doesn't result in an error (returns 0), the output buffer doesn't contain the expected ASCII representation of the IDN. Details: I've confirmed that the "normaliz.dll" library is loaded correctly. The parameters passed to the "IdnToAscii" function, including the Unicode string and buffer sizes, appear to be correct. I'm using the following flags: 0x01 for IDN_ALLOW_UNASSIGNED. Issue: Despite these preparations, the function doesn't return the expected ASCII representation of the IDN in the output buffer. I've checked the function's return value, and it doesn't indicate an error. I'm try to understand why the "IdnToAscii" function isn't providing the correct result. Any insights, suggestions, or guidance would be greatly appreciated. Thank you in advance for your help! Code: #include <WinAPI.au3> #include <Array.au3> Local $dll = DllOpen(@SystemDir & "\normaliz.dll") Local $unicodeDomain = "bücher.example.com" Local $unicodeDomainPtr = DllStructCreate("wchar[" & StringLen($unicodeDomain) + 1 & "]") DllStructSetData($unicodeDomainPtr, 1, $unicodeDomain) Local $bufferSize = 255 ;Note that IDN names have a maximum length. Local $output = DllStructCreate("wchar[" & $bufferSize & "]") Local $returnValue = DllCall($dll, "wstr", "IdnToAscii", _ "dword", 0x01, _ "wstr", DllStructGetPtr($unicodeDomainPtr), _ "int", StringLen($unicodeDomain), _ "ptr", DllStructGetPtr($output), _ "int", $bufferSize) If @error Or Not IsArray($returnValue) Then MsgBox(16, "Error converting to Punycode", @error) Else _ArrayDisplay($returnValue) MsgBox(64, "Punycode value", DllStructGetData($output, 1, 0)) _WinAPI_GetLastErrorMessage() ConsoleWrite( @error & @CRLF) EndIf DllClose($dll) Edited October 2, 2023 by oHenry Regards. Henry Link to comment Share on other sites More sharing options...
Solution TheXman Posted October 1, 2023 Solution Share Posted October 1, 2023 (edited) You can compare the script below to your original one to see the differences. If you have additional questions, feel free to ask. int IdnToAscii( [in] DWORD dwFlags, [in] LPCWSTR lpUnicodeCharStr, [in] int cchUnicodeChar, [out, optional] LPWSTR lpASCIICharStr, [in] int cchASCIIChar ); #include <WinAPI.au3> #include <Array.au3> ;IDN (International Domain Name) Flags Const $IDN_ALLOW_UNASSIGNED = 0x01, _ ;Allow unassigned "query" behavior per RFC 3454 $IDN_USE_STD3_ASCII_RULES = 0x02, _ ;Enforce STD3 ASCII restrictions for legal characters $IDN_EMAIL_ADDRESS = 0x04, _ ;Enable EAI algorithmic fallback for email local parts behavior $IDN_RAW_PUNYCODE = 0x08 ;Disable validation and mapping of punycode. Global $hDll = DllOpen("normaliz.dll") Global $sUnicodeDomain = "bücher.example.com" Global $tOutput = DllStructCreate("wchar[255]") ;Note that IDN names have a maximum length. Global $aResult = DllCall($hDll, "int", "IdnToAscii", _ "dword", $IDN_ALLOW_UNASSIGNED, _ "wstr" , $sUnicodeDomain, _ "int" , StringLen($sUnicodeDomain), _ "wstr" , DllStructGetPtr($tOutput), _ "int" , DllStructGetSize($tOutput) _ ) If @error Then MsgBox(16, "DllCall Error", "@error = " & @error) ElseIf $aResult[0] = 0 Then MsgBox(16, "Bad return code from DllCall", "Return value: " & $aResult[0]) ConsoleWrite("ERROR: " & _WinAPI_GetLastErrorMessage() & @CRLF) Else _ArrayDisplay($aResult) MsgBox(64, "Punycode value", $aResult[4]) EndIf DllClose($hDll) Click below to see the potential and/or actual issues with the script in your original post: Spoiler If you run your script on a 64bit version of Windows, and run the script using the 32bit AutoIt interpreter, then @SystemDir will return "C:\Windows\SysWOW64". Therefore, your DllOpen() will fail because the DLL file only exists in ""C:\Windows\System32". Since "C:\Windows\System32" is in the PATH, you can just reference the DLL file itself. The API's return value is an INT, not WSTR. The output buffer size for 255 wchars is 510, not 255. In the DllCall(), you reference the ouput using a PTR. If you do it that way, then you will need to de-reference the PTR to a WSTR. If you define it as a WSTR to start with, then it will be correctly referenced without any need for de-referencing/casting. Edited October 1, 2023 by TheXman oHenry 1 CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein "If you think you're a big fish, it's probably because you only swim in small ponds." ~TheXman Link to comment Share on other sites More sharing options...
Developers Jos Posted October 1, 2023 Developers Share Posted October 1, 2023 Moved to the appropriate forum. Moderation Team SciTE4AutoIt3 Full installer Download page - Beta files Read before posting How to post scriptsource Forum etiquette Forum Rules Live for the present, Dream of the future, Learn from the past. Link to comment Share on other sites More sharing options...
oHenry Posted October 2, 2023 Author Share Posted October 2, 2023 7 hours ago, TheXman said: You can compare the script below to your original one to see the differences. If you have additional questions, feel free to ask. int IdnToAscii( [in] DWORD dwFlags, [in] LPCWSTR lpUnicodeCharStr, [in] int cchUnicodeChar, [out, optional] LPWSTR lpASCIICharStr, [in] int cchASCIIChar ); #include <WinAPI.au3> #include <Array.au3> ;IDN (International Domain Name) Flags Const $IDN_ALLOW_UNASSIGNED = 0x01, _ ;Allow unassigned "query" behavior per RFC 3454 $IDN_USE_STD3_ASCII_RULES = 0x02, _ ;Enforce STD3 ASCII restrictions for legal characters $IDN_EMAIL_ADDRESS = 0x04, _ ;Enable EAI algorithmic fallback for email local parts behavior $IDN_RAW_PUNYCODE = 0x08 ;Disable validation and mapping of punycode. Global $hDll = DllOpen("normaliz.dll") Global $sUnicodeDomain = "bücher.example.com" Global $tOutput = DllStructCreate("wchar[255]") ;Note that IDN names have a maximum length. Global $aResult = DllCall($hDll, "int", "IdnToAscii", _ "dword", $IDN_ALLOW_UNASSIGNED, _ "wstr" , $sUnicodeDomain, _ "int" , StringLen($sUnicodeDomain), _ "wstr" , DllStructGetPtr($tOutput), _ "int" , DllStructGetSize($tOutput) _ ) If @error Then MsgBox(16, "DllCall Error", "@error = " & @error) ElseIf $aResult[0] = 0 Then MsgBox(16, "Bad return code from DllCall", "Return value: " & $aResult[0]) ConsoleWrite("ERROR: " & _WinAPI_GetLastErrorMessage() & @CRLF) Else _ArrayDisplay($aResult) MsgBox(64, "Punycode value", $aResult[4]) EndIf DllClose($hDll) Click below to see the potential and/or actual issues with the script in your original post: Reveal hidden contents If you run your script on a 64bit version of Windows, and run the script using the 32bit AutoIt interpreter, then @SystemDir will return "C:\Windows\SysWOW64". Therefore, your DllOpen() will fail because the DLL file only exists in ""C:\Windows\System32". Since "C:\Windows\System32" is in the PATH, you can just reference the DLL file itself. The API's return value is an INT, not WSTR. The output buffer size for 255 wchars is 510, not 255. In the DllCall(), you reference the ouput using a PTR. If you do it that way, then you will need to de-reference the PTR to a WSTR. If you define it as a WSTR to start with, then it will be correctly referenced without any need for de-referencing/casting. Hi TheXman, Excellent! Thank you very much for taking the time to list the problems my script had. I really appreciate it. Regards. Henry Link to comment Share on other sites More sharing options...
TheXman Posted October 2, 2023 Share Posted October 2, 2023 You're welcome! CryptoNG UDF: Cryptography API: Next Gen jq UDF: Powerful and Flexible JSON Processor | jqPlayground: An Interactive JSON Processor Xml2Json UDF: Transform XML to JSON | HttpApi UDF: HTTP Server API | Roku Remote: Example Script About Me How To Ask Good Questions On Technical And Scientific Forums (Detailed) | How to Ask Good Technical Questions (Brief) "Any fool can know. The point is to understand." -Albert Einstein "If you think you're a big fish, it's probably because you only swim in small ponds." ~TheXman Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now