Results 1 to 9 of 9

Thread: [RESOLVED] WideCharToMultiByte problem

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Jun 2011
    Posts
    461

    Resolved [RESOLVED] WideCharToMultiByte problem

    I can't manage to upload binary files via WinHTTP (i.e. send post data in byte type), because it appears that there is a problem with function that converts string to bytes - WideCharToMultiByte (I have tried to put CP_UNICODE in CodePage parameter but again it won't convert properly). Can someone help me in solving this?
    (...)

    EDIT: Finally found a working function here: ToCPString(String, CP_ACP)
    Last edited by MikiSoft; Apr 13th, 2015 at 08:58 AM.

  2. #2
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: [RESOLVED] WideCharToMultiByte problem

    You get yourself in trouble when you do things wrong, and trying to use String expressions blindly with binary data is about as wrong as things get.

    You don't want a String body payload. That just means numerous gyrations pouring data from glass to glass to glass doing multiple potentially unsafe character encoding conversions.

    I fail to see why so many people try to do this and then have to attempt exotic manipulations on top of it, hoping to compensate for the mess. Instead consider using a sort of "binary string builder" as implemented in the attachment.

    Code:
    Option Explicit
    
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
        ByRef Destination As Any, _
        ByRef Source As Any, _
        ByVal Length As Long)
    
    Private Const BINARY_CHUNK As Long = 256
    
    Private Binary() As Byte
    Private BinaryNext As Long
    
    Private Sub ClearBinary()
        Binary = "" 'Creates an initialized but empty Byte array.
        ResetBinary
    End Sub
    
    Private Sub ResetBinary()
        BinaryNext = 0 'Retain allocated space for reuse.
    End Sub
    
    Private Sub CatBinary(ByRef Bytes() As Byte)
        Dim BytesLen As Long
    
        BytesLen = UBound(Bytes) - LBound(Bytes) + 1
        If BinaryNext + BytesLen - 1 > UBound(Binary) Then
            If BytesLen > BINARY_CHUNK Then
                ReDim Preserve Binary(BinaryNext + BytesLen - 1)
            Else
                ReDim Preserve Binary(BinaryNext + BINARY_CHUNK - 1)
            End If
        End If
        CopyMemory Binary(BinaryNext), Bytes(LBound(Bytes)), BytesLen
        BinaryNext = BinaryNext + BytesLen
    End Sub
    
    Private Sub CatBinaryString(ByRef Text As String)
        Dim Bytes() As Byte
    
        Bytes = StrConv(Text, vbFromUnicode) 'Safe if Text only has valid 7-bit US-ASCII chars.
        CatBinary Bytes
    End Sub
    
    Private Sub TrimBinary()
        If BinaryNext > 0 Then
            ReDim Preserve Binary(BinaryNext - 1)
        Else
            ClearBinary
        End If
    End Sub
    The attachment is large because it includes a sample PDF document to be wrapped as a payload. The sample program writes the result to disk so you can view it.
    Attached Files Attached Files
    Last edited by dilettante; Mar 2nd, 2015 at 01:04 AM.

  3. #3

    Thread Starter
    Hyperactive Member
    Join Date
    Jun 2011
    Posts
    461

    Re: [RESOLVED] WideCharToMultiByte problem

    Thanks for this, it will help me alot!
    Last edited by MikiSoft; Mar 2nd, 2015 at 08:56 AM.

  4. #4

    Thread Starter
    Hyperactive Member
    Join Date
    Jun 2011
    Posts
    461

    Re: WideCharToMultiByte problem

    I'm facing a problem right now. Why this code below causes crash after executing CopyMemory?
    VB Code:
    1. Private Declare Function WideCharToMultiByte Lib "Kernel32.dll" ( _
    2.     ByVal CodePage As Long, _
    3.     ByVal dwFlags As Long, _
    4.     ByVal lpWideCharStr As Long, _
    5.     ByVal cchWideChar As Long, _
    6.     ByVal lpMultiByteStr As Long, _
    7.     ByVal cbMultiByte As Long, _
    8.     ByVal lpDefaultChar As Long, _
    9.     ByVal lpUsedDefaultChar As Long _
    10. ) As Long
    11.  
    12. Private Const CP_ACP        As Long = 0
    13.  
    14. Private Declare Function CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal _
    15.         dest As Long, ByVal src As Long, ByVal Length As Long) As Long
    16.  
    17. Private Const BINARY_CHUNK As Long = 256
    18.  
    19. Private Function ToCPString(ByRef the_sValue As String) As Byte()
    20.  
    21.     Dim abytOutput()                As Byte
    22.     Dim nValueLen                   As Long
    23.     Dim nOutputByteLen              As Long
    24.  
    25.     ' Cache the input length.
    26.     nValueLen = Len(the_sValue)
    27.  
    28.     ' See how big the output buffer will be.
    29.     nOutputByteLen = WideCharToMultiByte(CP_ACP, 0&, StrPtr(the_sValue), nValueLen, 0&, 0&, 0&, 0&)
    30.  
    31.     If nOutputByteLen > 0 Then
    32.         ' Resize output byte array to the size of the UTF-8 string.
    33.         ReDim abytOutput(1 To nOutputByteLen)
    34.  
    35.         ' Make this API call again, this time giving a pointer to the output byte array.
    36.         WideCharToMultiByte CP_ACP, 0&, StrPtr(the_sValue), nValueLen, VarPtr(abytOutput(1)), nOutputByteLen, 0&, 0&
    37.     End If
    38.  
    39.     ' Return the array.
    40.     ToCPString = abytOutput()
    41.  
    42. End Function
    43.  
    44. Private Sub CatBinary(bytData() As Byte, Bytes() As Byte)
    45.     Dim BytesLen As Long, BinaryNext As Long
    46.    
    47.     BinaryNext = UBound(bytData) + 1
    48.     BytesLen = UBound(Bytes) - LBound(Bytes) + 1
    49.     If BinaryNext + BytesLen - 1 > BinaryNext Then
    50.         If BytesLen > BINARY_CHUNK Then
    51.             ReDim Preserve bytData(BinaryNext + BytesLen - 1)
    52.         Else
    53.             ReDim Preserve bytData(BinaryNext + BINARY_CHUNK - 1)
    54.         End If
    55.     End If
    56.     CopyMemory bytData(BinaryNext), Bytes(LBound(Bytes)), BytesLen
    57. End Sub
    58.  
    59. Private Sub CatBinaryString(bytData() As Byte, Text As String)
    60.     Dim Bytes() As Byte
    61.    
    62.     Bytes = ToCPString(Text)
    63.     CatBinary bytData, Bytes
    64. End Sub
    65.  
    66. Private Sub TrimBinary(bytData() As Byte)
    67.     If UBound(bytData) > 0 Then
    68.         ReDim Preserve bytData(UBound(bytData) - 1)
    69.     Else
    70.         bytData = ""
    71.     End If
    72. End Sub
    73.  
    74. Sub Main()
    75. Dim bytData() As Byte: bytData = ""
    76. CatBinaryString bytData, "test"
    77. MsgBox StrConv(bytData, vbUnicode)
    78. End Sub
    Last edited by MikiSoft; Apr 13th, 2015 at 08:30 AM.

  5. #5
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: WideCharToMultiByte problem

    When copymemory crashes, likely one or both of these are the reason:

    1. BinaryNext + BytesLen - 1 > UBound(bytData)
    2. LBound(Bytes) + BytesLen - 1 > UBound(Bytes)

    You should verify this & if either are true, your calculations are off
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  6. #6

    Thread Starter
    Hyperactive Member
    Join Date
    Jun 2011
    Posts
    461

    Re: WideCharToMultiByte problem

    Can you test it, I think that it's all right with what you said? Just put the code above into a module and run it.
    Last edited by MikiSoft; Apr 13th, 2015 at 08:51 AM.

  7. #7
    Addicted Member Wolfgang Enzinger's Avatar
    Join Date
    Apr 2014
    Location
    Munich, Germany
    Posts
    160

    Re: WideCharToMultiByte problem

    Quote Originally Posted by MikiSoft View Post
    I'm facing a problem right now. Why this code below causes crash after executing CopyMemory?
    Code:
    Private Declare Function CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal _
            dest As Long, ByVal src As Long, ByVal Length As Long) As Long
    With dest and src declared as ByVal parameters, you must pass VarPtrs:

    Code:
    CopyMemory VarPtr(bytData(BinaryNext)), VarPtr(Bytes(LBound(Bytes))), _ 
    BytesLen
    HTH, Wolfgang

  8. #8
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: WideCharToMultiByte problem

    It's the API declaration and API call that are the problem, ByVal vs ByRef

    Either

    1. Pass your parameters ByVal vs ByRef in your CopyMemory call, i.e.,
    CopyMemory VarPtr(bytData(BinaryNext)), VarPtr(Bytes(LBound(Bytes))), BytesLen

    2. Or redefine your CopyMemory API definition and remove the ByVal for the 1st two parameters
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  9. #9

    Thread Starter
    Hyperactive Member
    Join Date
    Jun 2011
    Posts
    461

    Re: WideCharToMultiByte problem

    Thanks from both of you, it works! I've put VarPtr as you said.
    But, I have now another problem with this:
    VB Code:
    1. Sub Main()
    2. Dim bytData() As Byte: bytData = ""
    3. CatBinaryString bytData, "aa"
    4. CatBinaryString bytData, "bb"
    5. CatBinaryString bytData, "cc"
    6. TrimBinary bytData
    7. Debug.Print UBound(bytData)
    8. MsgBox StrConv(bytData, vbUnicode)
    9. End Sub
    It only displays me "aa" in message box?

    UPDATE: Solved it now (just had to remove BINARY_CHUNK), here's the final code:
    VB Code:
    1. Private Declare Function WideCharToMultiByte Lib "Kernel32.dll" ( _
    2.     ByVal CodePage As Long, _
    3.     ByVal dwFlags As Long, _
    4.     ByVal lpWideCharStr As Long, _
    5.     ByVal cchWideChar As Long, _
    6.     ByVal lpMultiByteStr As Long, _
    7.     ByVal cbMultiByte As Long, _
    8.     ByVal lpDefaultChar As Long, _
    9.     ByVal lpUsedDefaultChar As Long _
    10. ) As Long
    11.  
    12. Private Const CP_ACP        As Long = 0
    13.  
    14. Private Declare Function CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal _
    15.         dest As Long, ByVal src As Long, ByVal Length As Long) As Long
    16.  
    17. Private Function ToCPString(ByRef the_sValue As String) As Byte()
    18.  
    19.     Dim abytOutput()                As Byte
    20.     Dim nValueLen                   As Long
    21.     Dim nOutputByteLen              As Long
    22.  
    23.     ' Cache the input length.
    24.     nValueLen = Len(the_sValue)
    25.  
    26.     ' See how big the output buffer will be.
    27.     nOutputByteLen = WideCharToMultiByte(CP_ACP, 0&, StrPtr(the_sValue), nValueLen, 0&, 0&, 0&, 0&)
    28.  
    29.     If nOutputByteLen > 0 Then
    30.         ' Resize output byte array to the size of the UTF-8 string.
    31.         ReDim abytOutput(1 To nOutputByteLen)
    32.  
    33.         ' Make this API call again, this time giving a pointer to the output byte array.
    34.         WideCharToMultiByte CP_ACP, 0&, StrPtr(the_sValue), nValueLen, VarPtr(abytOutput(1)), nOutputByteLen, 0&, 0&
    35.     End If
    36.  
    37.     ' Return the array.
    38.     ToCPString = abytOutput()
    39.  
    40. End Function
    41.  
    42. Private Sub CatBinary(bytData() As Byte, Bytes() As Byte)
    43.     Dim BytesLen As Long, BinaryNext As Long
    44.    
    45.     BinaryNext = UBound(bytData) + 1
    46.     BytesLen = UBound(Bytes) - LBound(Bytes) + 1
    47.     If BinaryNext + BytesLen > BinaryNext Then ReDim Preserve bytData(BinaryNext + BytesLen - 1)
    48.     CopyMemory VarPtr(bytData(BinaryNext)), VarPtr(Bytes(LBound(Bytes))), BytesLen
    49. End Sub
    50.  
    51. Private Sub CatBinaryString(bytData() As Byte, Text As String)
    52.     Dim Bytes() As Byte
    53.    
    54.     Bytes = ToCPString(Text)
    55.     CatBinary bytData, Bytes
    56. End Sub
    57.  
    58. Sub Main()
    59. Dim bytData() As Byte: bytData = ""
    60. CatBinaryString bytData, "aa"
    61. CatBinaryString bytData, "bb"
    62. CatBinaryString bytData, "cc"
    63. MsgBox StrConv(bytData, vbUnicode)
    64. End Sub
    I think that it's good now (if someone thinks opposite then correct me).
    Last edited by MikiSoft; Apr 13th, 2015 at 09:33 AM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width