Jump to content

DLL Function Call Issue: Missing Expected Return Value - (Moved)


Go to solution Solved by TheXman,

Recommended Posts

Posted (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 by oHenry

Regards.

Henry

  • Solution
Posted (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)

image.png.13bbf644e97c09ea2c09472285965494.png

image.png.808eb6353b76fd3b76b035682ed043ef.png

Click below to see the potential and/or actual issues with the script in your original post:

Spoiler
  1. 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.
  2. The API's return value is an INT, not WSTR.
  3. The output buffer size for 255 wchars is 510, not 255.
  4. 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 by TheXman
Posted
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)

image.png.13bbf644e97c09ea2c09472285965494.png

image.png.808eb6353b76fd3b76b035682ed043ef.png

Click below to see the potential and/or actual issues with the script in your original post:

  Reveal hidden contents
  1. 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.
  2. The API's return value is an INT, not WSTR.
  3. The output buffer size for 255 wchars is 510, not 255.
  4. 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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...