Jump to content

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


 Share

Go to solution Solved by TheXman,

Recommended Posts

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

Link to comment
Share on other sites

  • Solution

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
Link to comment
Share on other sites

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

Link to comment
Share on other sites

Link to comment
Share on other sites

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
 Share

×
×
  • Create New...