Solved

Send Byte Array

Posted on 2004-09-21
30
452 Views
Last Modified: 2013-11-13
I need to send a byte array over winsock.
This is what it looks like...

ReDim Bits(0 To 3, 0 To bmWidth - 1, 0 To bmHeight - 1) As Byte

GetBitmapBits Picture1.Image, bmSize, Bits(0, 0, 0)
   
    For Y = 0 To bmHeight - 1
        For X = 0 To bmWidth - 1
            Bits(2, X, Y) = Bits(2, X, Y) 'Red Bits
            Bits(1, X, Y) = Bits(1, X, Y) 'Green Bits
            Bits(0, X, Y) = Bits(0, X, Y) 'Blue Bits
        Next X
    Next Y

...
Now how do I send Bits(0, 0, 0) through winsock??? I'm thinking Bits(0, 0, 0) contains alot of information but when I look to see what it is all it says is 128. I know it contains more than that. So whats the easyest way to send it through winsock? Also can someone please explain how byte arrays work, I see them all the time but I cant figure out how to use them. Thanks.
0
Comment
Question by:Rickyman45
  • 17
  • 13
30 Comments
 

Author Comment

by:Rickyman45
Comment Utility
please someone help me
0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
Firstly, I think you want to use the GetDIBits function to read RGB bitmaps.

Second, why are you assigning each value to itself?
Bits(2, X, Y) = Bits(2, X, Y) 'Red Bits
...

Make sure you are using pixel scalemode in your picturebox (not the default twips)

Here is a short sample which uses SetDIBits:
http://www.vb-helper.com/howto_setdibits.html



To send your data you may try:

dim vtdata as Variant

vtdata = Bits

WinSock1.SendData vtdata
0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
Here is an example of using GetBitmapBits:

'Create a new project, add a command button and a picture box to the project, load a picture into the picture box.
'Paste this code into Form1
Private Type BITMAP
    bmType As Long
    bmWidth As Long
    bmHeight As Long
    bmWidthBytes As Long
    bmPlanes As Integer
    bmBitsPixel As Integer
    bmBits As Long
End Type
Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Dim PicBits() As Byte, PicInfo As BITMAP
Dim Cnt As Long, BytesPerLine as Long
Private Sub Command1_Click()
    'KPD-Team 1999
    'URL: http://www.allapi.net/
    'E-Mail: KPDTeam@Allapi.net
    'Get information (such as height and width) about the picturebox
    GetObject Picture1.Image, Len(PicInfo), PicInfo
    'reallocate storage space
    BytesPerLine = (PicInfo.bmWidth * 3 + 3) And &HFFFFFFFC
    ReDim PicBits(1 To BytesPerLine * PicInfo.bmHeight * 3) As Byte
    'Copy the bitmapbits to the array
    GetBitmapBits Picture1.Image, UBound(PicBits), PicBits(1)

'________________________________________________
'From here on it's modifying then reading the image back to the picturebox
'________________________________________________
    'Invert the bits
    For Cnt = 1 To UBound(PicBits)
        PicBits(Cnt) = 255 - PicBits(Cnt)
    Next Cnt
    'Set the bits back to the picture
    SetBitmapBits Picture1.Image, UBound(PicBits), PicBits(1)
    'refresh
    Picture1.Refresh
End Sub
0
 

Author Comment

by:Rickyman45
Comment Utility
Erick37 when ever i try to make it a Variant it says "ByRef argument type mishmatch"
0
 

Author Comment

by:Rickyman45
Comment Utility
If someone can explain to me what bit array is and how to use it ill give them the points.
0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
What is the line which gives the error?

Typically, the "mismatch" error is thrown when you pass a variable of one type to a variable of another type which is incompatible.  For example, if you are using an API solution to winsock, then you cannot use variants.  The Winsock control which comes with VB accepts variant data.
0
 

Author Comment

by:Rickyman45
Comment Utility
Im trying to send a picture using this example http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=37691&lngWId=1
 but I cant figure out how to send Bits(0, 0, 0)

Hope this helps
0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
What are you using for winsock?
0
 

Author Comment

by:Rickyman45
Comment Utility
winsock control 6.0
0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
Hi Rickyman,

I modified the code from PSC a bit so that it reads the image into a single dimension byte array.  I'm assuming you do not need to manipulate RGB image data, so using using a 3 dimension array is not necessary.  The code below reads the picture into the array and sends it out via winsock.  I assume you have worked out the send and receive details in winsock.

Since you are only sending raw image RGB data to the remote computer, it is imperative that the code on the other side know the dimensions of the picturebox in advance and in order to properly interpret the data.  That means that the picturebox on the receive end must be identical in size (and scalemode) to the original picturebox.

Here's the code, good luck!

Private Sub cmdNegative_Click()
    'Private variable declarations
    Dim bmWidth As Long
    Dim bmHeight As Long
    Dim bmSize As Long
    Dim bmBits() As Byte
    Dim x As Long, y As Long
   
    'Get picture's Width and Height
    bmWidth = Picture1.Width
    bmHeight = Picture1.Height
   
    'Store size of bitmap in total pixels
    bmSize = 3 * bmWidth * bmHeight
   
    'ReDefine Bit array to hold all pixels from picture box
    ReDim bmBits(bmSize - 1)
   
    'Grab picture's pixels and load to Bit array
    GetBitmapBits Picture1.Image, bmSize, bmBits(0)
   
    Winsock1.SendData bmBits() '<< Send the byte array

End Sub



0
 

Author Comment

by:Rickyman45
Comment Utility
I use something in winsock that makes it easier to send lots of data http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=22320&lngWId=1 but for some reason when I do Send_Data picture, bmBits() it gives me the error "ByRef argument type mishmatch" Please help me. PS: I'll give you lots more points if you can help me with this.
0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
I am trying to get this to work.  I'm still working on it.
0
 
LVL 32

Accepted Solution

by:
Erick37 earned 405 total points
Comment Utility
Ok, here is a very simple Client/Server sample which sends picturebox images from the client to the server.
This is by no means a full blown application.  There is no error handling, and no means of detecting lost or coprrupt data packets.  The code is for example only and I'm surprised myself that I got it to work at all.

The Client application sends a byte array to the server.  The first 4 bytes of the array store the size of the remaining picture portion of the array.  The picture data is retrieved from the picturebox using GetBitmapBits.

Here is the Client code::

'This is the Client application which sends a bitmap image via raw data to the Server application
'Start a new project and place a picturebox and a command button on the form
'You must customize the code where you see '********
'
'

Option Explicit

'API declarations
Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Dim bError As Boolean

Private Sub Form_Load()
    Me.Caption = "Client"
   
    Command1.Caption = "Send Picture"
   
    'setup the picturebox
    With Picture1
    .ScaleMode = vbPixels
    .BorderStyle = 0
   
    '*********
    .Picture = LoadPicture("c:\tcptest.bmp")
    '*********
   
    .Width = ScaleX(.Picture.Width, vbHimetric, ScaleMode)
    .Height = ScaleY(.Picture.Height, vbHimetric, ScaleMode)
    Debug.Print "Picture dimensions:", .ScaleWidth, .ScaleHeight
    End With
   
    'setup winsock
    With Winsock1
    .Protocol = sckTCPProtocol
    'Turn off firewall and/or open port 5163 on router.
   
    '********
    .RemoteHost = "192.168.1.100" 'Configure to your server
    .RemotePort = 5163 'Any unused port will do
    '********
   
    End With
End Sub

Private Sub Command1_Click()
   
    'Private variable declarations
    Dim bmWidth As Long
    Dim bmHeight As Long
    Dim bmSize As Long
    Dim bmBits() As Byte
    Dim x As Long, y As Long
   
    'Get picture's Width and Height
    bmWidth = Picture1.ScaleWidth
    bmHeight = Picture1.ScaleHeight
   
    'Store size of bitmap in total pixels
    bmSize = 3 * bmWidth * bmHeight
   
    'ReDefine Bit array to hold all pixels from picture box
    ReDim bmBits(bmSize + 3)
   
    'write the size of the bitmap buffer to the beginning of the array
    Call CopyMemory(bmBits(0), bmSize, 4)
   
    'Grab picture's pixels and load to Bit array
    'Start at the 5th location, because we store the size of the buffer in the first 4 bytes
    GetBitmapBits Picture1.Image, bmSize, bmBits(4)
   
    Winsock1.Close
    Winsock1.Connect
   
    Command1.Enabled = False
    bError = False
   
    Do While (Winsock1.State <> sckConnected) And (Not bError)
        Call Sleep(100)
        DoEvents
        If bError Then Exit Do 'check for errors
    Loop
   
    Command1.Enabled = True
   
    If (Winsock1.State = sckConnected) Then
        Winsock1.SendData bmBits
    End If
   
End Sub

Private Sub Winsock1_Error(ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
    Debug.Print "Winsock Error #" & CStr(Number) & " " & Description
    bError = True
End Sub

0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
And here is the Server application.

Note:  Make sure that the picturebox on the client and server have the same dimensions.

'Server code
'Open a new instance of VB and create a new project
'On the form, place a picturebox and a winsock control
'Code marked with '******** needs to be customized to fit your application

Option Explicit

'API declarations
Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private Sub Form_Load()
    Me.Caption = "Server"
   
    'Setup the receiving picturebox
    With Picture1
    .AutoRedraw = True
    .BorderStyle = 0
    .ScaleMode = vbPixels
    '//You must hardcode the picturebox dimensions to be exactly
    '//   the same as the client picturebox.  In this case 200x150 pixels.
   
    '********
    .Width = ScaleX(200, vbPixels, ScaleMode)
    .Height = ScaleY(150, vbPixels, ScaleMode)
    '********
   
    End With

    'setup winsock
    With Winsock1
   
    '********
    .LocalPort = 5163 'must match Client port
    '********
   
    .Listen
    End With
End Sub

Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long)
    With Winsock1
    .Close
    .Accept requestID
    Debug.Print "Server: ConnectionRequest"
    End With
End Sub

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
    Static lBytesReceived As Long
    Static lBuffSize As Long
    Static bData() As Byte
    Dim bTmpData() As Byte
    Dim lRet As Long
   
    If (lBuffSize = 0) Then 'This is the first packet
        'peek at the first 4 bytes and store in lBuffSize
        Winsock1.PeekData lBuffSize, vbLong, 4
        Debug.Print "Image Buffer Size: " & CStr(lBuffSize)
        'Size the buffer to accept all data
        ReDim bData(lBuffSize + 3)
    End If
   
    'Get this chunk
    Winsock1.GetData bTmpData
   
    'Copy the data to the buffer
    Call CopyMemory(bData(lBytesReceived), bTmpData(0), bytesTotal)
   
    'Update our counter
    lBytesReceived = lBytesReceived + bytesTotal
       
    If (lBytesReceived >= lBuffSize) Then 'Finished draw picture
        'Load Bit array to picture box
        lRet = SetBitmapBits(Picture1.Image, lBuffSize, bData(4))
        'SetBitmapBits normally triggers a redraw event,
        'but just in case it doesn't, we'll do one now
        Picture1.Refresh
        'Done: reset variables
        ReDim bData(0)
        lBytesReceived = 0
        lBuffSize = 0
        Debug.Print "Done!"
       
        Winsock1.Close
        Winsock1.Listen

    End If
   
End Sub

0
 

Author Comment

by:Rickyman45
Comment Utility
Works for me
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 

Author Comment

by:Rickyman45
Comment Utility
for some reason when i make the picture the same size it gives me an error but when i make them different its all blury
0
 

Author Comment

by:Rickyman45
Comment Utility
after messing with it for a while I figured it out, You are my hero! I've been trying to get this code for a very long time. Thank you so much.
0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
You're welcome, glad it worked.
0
 

Author Comment

by:Rickyman45
Comment Utility
even though I accecpted your answer I still have a question. For some reason when I try to send 2 pictures the first one will work but the second will freeze the program I dont even get an error. So im thinking one of the variables wasnt cleared. Do you have any ideas?
0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
Which side freezes, client or server?
Does this happen when sending the same picture twice, or different pictures?
0
 

Author Comment

by:Rickyman45
Comment Utility
server, and sometimes its the same pic sometimes its different.
0
 

Author Comment

by:Rickyman45
Comment Utility
I've got it 100% working except for the freezeing problem I get this error Visual Basic has encountered a problem and needs to close.  We are sorry for the inconvenience. and i can send the error or dont send it. But everything else is working great the picture will load on the other computer in just a few milli seconds, which is exactly what I needed.
0
 

Author Comment

by:Rickyman45
Comment Utility
I figured something else out that might help, when I delete the lines
lBytesReceived = 0
lBuffSize = 0
it doesnt crash but I get the error "Script out of range" and it highlights the line
Call CopyMemory(bData(lBytesReceived), bTmpData(0), bytesTotal)
I dont see why I even need to reset the variables because it should just write over them when it gets the next picture. I think it will work if I can just fix this error but I dont know what "script out of range" means.
0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
In the Server code:

Static lBytesReceived As Long
Static lBuffSize As Long

Both are declared as Static, that means that they retain their values even when the function ends.  I had to make them static because the DataArrival event is triggered several times while all of the data arrives in chunks and their values are needed to tell when all of the data arrives.

When lBytesReceived >= lBuffSize then we know all of the data has been received and then we can draw the picture.  That is when we reset all of the Static variables.  The error "subscript out of range" means that the index you passed to an array was too big or too little.  In the case of bData(lBytesReceived), unless lBytesReceived is reset to 0, it will get too big and point to an index "out of range" of the array.

If VB is crashing and burning it's probably the CopyMemory line that is causing it.  If lBuffSize is not correct then CopyMemory may be attempting to write data to memory outside the applications allocated heap.  This will crash the app.

It is very important to make sure the size of the buffer is correct on both sides, client and server.  I have updated the Sever code to do some checking before the CopyMemory call.  It will not solve the problem, but it will probably keep the app from crashing while you debug why the buffer is too small.

Here's the updated Server code:

'Server code
'Open a new instance of VB and create a new project
'On the form, place a picturebox and a winsock control
'Code marked with '******** needs to be customized to fit your application

Option Explicit

'API declarations
Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private Sub Form_Load()
    Me.Caption = "Server"
   
    'Setup the receiving picturebox
    With Picture1
    .AutoRedraw = True
    .BorderStyle = 0
    .ScaleMode = vbPixels
    '//You must hardcode the picturebox dimensions to be exactly
    '//   the same as the client picturebox.  In this case 200x150 pixels.
   
    '********
    .Width = ScaleX(200, vbPixels, ScaleMode)
    .Height = ScaleY(150, vbPixels, ScaleMode)
    '********
   
    End With

    'setup winsock
    With Winsock1
   
    '********
    .LocalPort = 5163 'must match Client port
    '********
   
    .Listen
    End With
End Sub

Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long)
    With Winsock1
    .Close
    .Accept requestID
    Debug.Print "Server: ConnectionRequest"
    End With
End Sub

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
    Static lBytesReceived As Long
    Static lBuffSize As Long
    Static bData() As Byte
    Dim bTmpData() As Byte
    Dim lRet As Long
   
    If (lBuffSize = 0) Then 'This is the first packet
        'peek at the first 4 bytes and store in lBuffSize
        Winsock1.PeekData lBuffSize, vbLong, 4
        Debug.Print "Image Buffer Size: " & CStr(lBuffSize)
        'Size the buffer to accept all data
        ReDim bData(lBuffSize + 3)
    End If
   
    'Get this chunk
    Winsock1.GetData bTmpData
   
    '~~~~~~~~~~NEW~~~~~~~~~~~~~~~~~~~~~~~
    If (lBytesReceived + bytesTotal <= lBuffSize + 4) Then
        'Copy the data to the buffer
        Call CopyMemory(bData(lBytesReceived), bTmpData(0), bytesTotal)
    Else
        MsgBox "Buffer is too small", vbCritical, App.Title
        'Reset variables
        ReDim bData(0)
        lBytesReceived = 0
        lBuffSize = 0
        Winsock1.Close
        Winsock1.Listen
        Exit Sub
    End If
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   
    'Update our counter
    lBytesReceived = lBytesReceived + bytesTotal
       
    If (lBytesReceived >= lBuffSize) Then 'Finished draw picture
        'Load Bit array to picture box
        lRet = SetBitmapBits(Picture1.Image, lBuffSize, bData(4))
        'SetBitmapBits normally triggers a redraw event,
        'but just in case it doesn't, we'll do one now
        Picture1.Refresh
        'Done: reset variables
        ReDim bData(0)
        lBytesReceived = 0
        lBuffSize = 0
        Debug.Print "Done!"
       
        Winsock1.Close
        Winsock1.Listen

    End If
   
End Sub

0
 

Author Comment

by:Rickyman45
Comment Utility
i changed bmSize = 3 * bmWidth * bmHeight to bmSize = 4 * bmWidth * bmHeight because it cut off 1/4 of the picture when set to 3. So when I change it back to 3 it works but it still only shows 3/4 of the picture.
0
 

Author Comment

by:Rickyman45
Comment Utility
i got it working I dont know why it is but it is. I changed If (lBytesReceived >= lBuffSize) Then to If (lBytesReceived > lBuffSize) Then but... I now have another problem when every I try to transfer it to 127.0.0.1 which is local it only takes about 1/2 second which is what I need but when I send it over lan it takes about 15 seconds why??? It's a big picture but its just a picture how come it takes so long??
0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
If your picture is 640 x 480, then the image data is 640 x 480 x 3 = 921,600 bytes!  It's going to take time to send that amount of data through the network, depending on traffic and network speed.
0
 

Author Comment

by:Rickyman45
Comment Utility
why do I have to multyply it by 3? what happens if I dont?
0
 

Author Comment

by:Rickyman45
Comment Utility
921,600 is only 0.87890625 megabytes that should not take 15 seconds to send through a network. Its got to be something else that slows it down.
0
 
LVL 32

Expert Comment

by:Erick37
Comment Utility
3 bytes per pixel, one for red, green, blue.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Python Encoding Problem \u2013 4 84
Microsoft Access combo box help 2 28
message box in access 4 33
using web browser with BING 40 83
Having just graduated from college and entered the workforce, I don’t find myself always using the tools and programs I grew accustomed to over the past four years. However, there is one program I continually find myself reverting back to…R.   So …
If you haven’t already, I encourage you to read the first article (http://www.experts-exchange.com/articles/18680/An-Introduction-to-R-Programming-and-R-Studio.html) in my series to gain a basic foundation of R and R Studio.  You will also find the …
This tutorial will introduce the viewer to VisualVM for the Java platform application. This video explains an example program and covers the Overview, Monitor, and Heap Dump tabs.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now