Solved Winsock recv function is crashing Access

Papa_Bear1

Member
Local time
Today, 04:14
Joined
Feb 28, 2020
Messages
137
I'm trying to do something very much like @nectorch references in their post:
("Challenges with Ms Access VBA with socket programming", at https://www.access-programmers.co.u...ms-access-vba-with-socket-programming.318926/).

I've made it through a few hurdles with the earliest steps of starting up winsock, and connecting and opening a socket, getting a socket ID, and sending the 1st "send" command (which in my case happens to be JSON-formatted). Those steps appear to be working now. I'm now stuck on the "recv" command causing Access to just crash and close.

The reference used (Agilent-sourced examples intended for Excel it seems...) has a "RecvAscii" routine (...shown below, but with my comments added...) where they retrieve values - apparently one character at a time - which I'm not expecting to need to do - but - it should work regardless - right? Anyway - it crashes on the first time it tries to run the "count = Recv(socketId, c, 1, 0) line.

I've tried opening up the c variable to not be restricted to one character - no dice.
I've tried using a different dll that I happened to see in a different source/reference (ws2_32.dll rather than wsock32.dll) - no dice.

Curious if anyone has experienced this or has any advice.

Code:
Function RecvAscii(dataBuf As String, ByVal MaxLength As Integer) As Integer
   
    Dim c As String * 1
    Dim length As Integer
    Dim count As Long
   
    '---------------------------------------------------------------------------------------
    'This routine came from the Agilent document example code for Excel, and they read
    '  in one character at a time, looking for a Line-Feed character to know they're done.
    'The "c" variable, that the character is read into, was dimensioned to a fixed length
    '  of one for this reason.
    '---------------------------------------------------------------------------------------
   
    '---------------------------------------------------------------------------------------
    'Initialize.
   
    dataBuf = ""
   
    '---------------------------------------------------------------------------------------
    'Begin process of cycling through reading values from the socket.
   
    While length < MaxLength
        DoEvents
        'Read one character at a time.
        count = Recv(socketId, c, 1, 0)
        'Check if error occurred.
        '(Not sure why this is not specifically checking for -1.)
        If count < 1 Then
            RecvAscii = RECV_ERROR
            dataBuf = Chr$(0)
            Exit Function
        End If
        'Check if we are done (LF character)
        If c = Chr$(10) Then
           dataBuf = dataBuf + Chr$(0)
           RecvAscii = NO_ERROR
           Exit Function
        End If
        'Concatenate and move on.
        length = length + count
        dataBuf = dataBuf + c
    Wend
   
    '---------------------------------------------------------------------------------------
    'If we made it to here, then something went wrong.
   
    RecvAscii = RECV_ERROR
   
End Function
 
Last edited:
I just wanted to follow up with progress made on this during the course of today's work. I was actually able to get this issue resolved.

It turns out that the example code in that Agilent document had some pieces that just didn't work for me. One was where they had a variable set to Integer, but a port value was too big - so I had to change it to a Long (which luckily was OK as the related functions had it set to Long actually as well.) More importantly, though, directly related to more serious above-mentioned issue - they happened to take an approach where they requested one character at a time, and it seems that providing a size of 1 for the buffer is what made it vaporize.

I tried a different source as a basis for some trial-and-error, where data is read in in chunks (rather than one character at a time), and it ended up working fine. Whew! I used code from the following reference as a basis: http://www.jasinskionline.com/windowsapi/ref/r/recv.html

In case it helps anyone, at the heart of the solution - the difference really is with these lines:
Code:
        strBuffer = Space(4096)
        lngRetVal = Recv(socketId, ByVal strBuffer, Len(strBuffer), 0)
 
Well done for persevering. :)
 
Great that you found a solution already.
If you want to understand the problem you encountered ...
Dim c As String * 1
There are two problems with this declaration.
  1. Strings in VBA are Unicode Strings and each character is represented by two bytes. So, your c variable has a length of two, not one, as far as the Recv function is concerned.
  2. The (ByRef) As Any declaration of the buffer of Recv function will pass a pointer to the original variable to the API. This is problematic with strings, as, in addition to the first issue above, they are COM Strings (BSTR) instead of typical WinApi Strings (LPSTR). Using ByVal will first marshal the VBA Strings as a WinApi compatible string before passing it's pointer to the API.
The solution would be:
Code:
Dim c as Byte
Or, if you want to retrieve more data at once, as a Byte array. (pass a pointer to the first item to the API)

Your approach of passing a string to the API *may* cause problems if there are one or more consecutive NULL chars in the data, as these signal the end of an LPSTR string, which might be interpreted accordingly by some functions during post-processing of the result.
 

Users who are viewing this thread

Back
Top Bottom