-
I am writing a graphical interface to a monitor process running on one of our Tandem systems, using the WinSock SendData and GetData subroutines. The number of bytes (112) that I think I am sending does not equal the number of bytes (113) received by the monitor process. The extra byte at the end of the record is a NULL. Everything else in the record looks good.
The monitor process will be written in C. At the moment, I am sending to a test server (also written in C) that does some checking of the header info and sends back a simple text message. The header contains the total record byte count. Since it is off by one, an error occurs.
I am hoping someone can tell me where I am picking up the extra byte and if it is an error or not. If it's not an error, then I will just have to increment the record size by 1 and handle the extra byte in the monitor process.
Here is the code involved:
<snippets>
' Globals -------------------------------------------------
Public Type dclStdHeader
ttl_len As Long ' long ttl_len;
msgtype As Long ' long msgtype;
orig_id As Long ' long orig_id;
seq_num As Long ' long seq_num;
tran_type As Long ' long tran_type;
user_def(32) As Byte ' char user_def[32];
End Type
Public Type dclMonitorReq
req_hdr As dclStdHeader
reqid As Integer ' short req;
sysname As String * 8 ' char sys[8];
byCust As String * 8 ' char byCust[8];
byProc As String * 8 ' char byProc[8];
byType As Integer ' short byType;
getProcs As Integer ' short getProcs;
getExceps As Integer ' short getExceps;
End Type
Public MonitorRequest As dclMonitorReq
Public sizeofMonitorReq As Integer
Public ByteArray() As Byte
Public Declare Sub CopyMemory Lib "KERNEL32" _
Alias "RtlMoveMemory" (hpvDest As Any, _
hpvSource As Any, _
ByVal cbCopy As Long)
' Code ----------------------------------------------------
sizeofMonitorReq = LenB(MonitorRequest) ' computes to 112
Public Sub Send_Request(ByVal RecNum As Integer)
' Send the request
Dim bArray() As Byte
Dim vTData As Variant
Dim lLen As Long
' 1st we need to store the record length in the header
' and then convert the record to a byte array so that
' it can be assigned to a variant
With MonitorRequest
.req_hdr.ttl_len = sizeofMonitorReq
lLen = LenB(.req_hdr.ttl_len)
ReDim ByteArray(lLen)
CopyMemory ByteArray(0), .req_hdr.ttl_len, lLen
Swap_Endian lLen ' convert to big endian
CopyMemory .req_hdr.ttl_len, ByteArray(0), lLen
End With
ReDim bArray(sizeofMonitorReq) As Byte
CopyMemory bArray(0), MonitorRequest, sizeofMonitorReq
vTData = bArray
tcpClient.SendData vTData
End Sub
</snippets>
I suspect that a variant ends with a NULL character, but I haven't found anything to confirm this. If so, then in the statement vTData = bArray, bArray is copied to vTData and a NULL is appended increasing the length to 113. If not, then my guess would be that the SendData routine is appending the extra byte.
If all of the above are wrong, then I must be doing something wrong, but I have no idea what that may be.
Can anyone set me straight?
-
You're almost correct
It took a while to find this but it is in the Books Online of VB5... Search for GetData then find the 'Creating a Custom Data Format' and 'GetData Method (DataObject Object)'
The byte array returned by GetData will be larger than the actual data when running on some operating systems, with arbitrary bytes at the end of the array. The reason for this is that Visual Basic does not know the data's format, and knows only the amount of memory that the operating system has allocated for the data. This allocation of memory is often larger than is actually required for the data. Therefore, there may be extraneous bytes near the end of the allocated memory segment. As a result, you must use appropriate functions to interpret the returned data in a meaningful way (such as truncating a string at a particular length with the Left function if the data is in a text format).
Caution Retrieving your custom data format with the GetData method may yield unpredictable results.
Because Visual Basic doesn’t understand your custom data format (because you defined it), it doesn’t have a way to determine the size of the data. Visual Basic can determine the memory size of the Byte array because it has been allocated by Windows, but the operating system usually assigns more memory than is needed.
Therefore, when you retrieve a custom data format, you get back a Byte array containing at least, and possibly more than, the number of bytes that the source actually placed into the DataObject object. You must then correctly interpret your custom data format when it is retrieved from the DataObject object. For example, in a simple string, you have to search for the NULL character and then truncate the string to that length.
That's why
Glacius Cool
Concept Designer
-
First item: I want to apologize for the lack of formatting in the code that I provided. I used copy/paste to create the message in Notepad and then did a copy/paste into my message. I didn't notice that the code lost its format. Makes it kind of tough to read.
Second item: I must plead ignorance here as I am fairly new to VB. Where is this "Books Online of VB5" that you mentioned? At Microsoft's site or somewhere else?
Third item: My problem is actually with the SendData method. The server that first receives the data is running on a Tandem computer (an entirely different OS: Tandem NonStop Kernel). This server (it's actually a router program) does some edits and then uses header information to pass the record on to the server that will actually process the request.
One of the edits is to look at the record length field in the record header and compare the value to the received byte count that is provided by the sockets API. The extra byte caused an error condition.
In your description of GetData, you used the term "extraneous bytes ". I assume that the same is true for SendData. If the number is consistent, I can deal with it by incrementing the value in the header. If it is a randem thing, then that could be a major problem.
I can handle the records coming back by looking at the integer value in bytes 53-54. The value is specific to the record type. The same is true with the server on the Tandem that will actually process the request. I can use the same value to cast the buffer to the correct record format.
I just need to get past the length edit on the router server.
Hmmm, I just had a thought. Maybe I can move my record in the variant and get the number of bytes (LenB(variant)), populate the header field with the length and then move the record into the variant again. Let me try that!