Solved

Sending a screen capture to another pc via winsock

Posted on 2001-08-23
20
1,016 Views
Last Modified: 2013-11-13
I am trying to make a monitor of a pc on another pc.

All it should do is sent its screen to the other pc.

How should this be done?  Using constant screen captures i presume... but how do i constantly send this to the other pc using winsock.  I mean do i have to create a file and send the file or can i just send the actual picture somehow.. if so how?

Thanks,

Joshyy
0
Comment
Question by:Joshyy
  • 8
  • 6
  • 3
  • +3
20 Comments
 
LVL 6

Expert Comment

by:anthony_glenwright
ID: 6417557
This may be of interest:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/termserv/hh/termserv/wtsapi_3orp.asp

Btw, Windows XP Pro has a "share desktop" feature that does exactly what you are trying to do.  Microsoft Netmeeting can also share a desktop...

You can also have a look at the Netmeeting API here:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmeet/hh/netmeet/nm3com1_8m09.asp
0
 
LVL 14

Expert Comment

by:wsh2
ID: 6417631
<pinging> for the links.. Thank YOU AG
0
 

Expert Comment

by:ravininave
ID: 6417940
I don't know whether it is correct or not but do one thing Capture ur screen using API's after a particular seconds using timer.  Save it to a db.  In other machine u can access those files and see it using timer.  Don't know whether it is correct or not.
0
 
LVL 1

Expert Comment

by:krees
ID: 6418239
First, you have to create a Server, a small resident program in the machine that will capture the screen and opens a port to be connected.

Then, with a Client Program, will connect to that server port and start receiving input data from the server.
You can receive packed data with the actual image compressed in a special format you make (or JPG) to minimize the network traffic.

Then, the client decodes this "bytes" into the actual image to be shown. It's easy to do this.

Maybe you will need a tmp file to compress the image, but this is not necesary because you can work in streams in memory, it's easier to work with a tmp file but is better with streams.

To transfer the data you can use the winsock packet send functions, which is a bit difficult to use or you can save to the temp file and use the upload file method.

In overall, the easier scenario is to save to a file, compress the file and send it to winsock.

The better is to create streams, compress in memory and send them in packets to the client.
0
 
LVL 1

Author Comment

by:Joshyy
ID: 6419516
krees that is exacyly what i want to do... send an image (in memory) to the client side without saving any files(jpg or etc)...

i know how to get a screen capture...

now what i need to do is send this capture to the client side... this streaming method seems good.. explain
0
 
LVL 1

Expert Comment

by:krees
ID: 6419552
Ok, how are you capturing the bitmap?

I mean, what is your function, what does it return?
0
 
LVL 1

Author Comment

by:Joshyy
ID: 6422015
using the foolwoing:

Public Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Public Declare Function GetDesktopWindow Lib "user32" () As Long
Public Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long

Public Const SRCCOPY = &HCC0020

Public Sub ScreenShot(DestinationDC As Long)
Dim ScreenWidth As Long, ScreenHeight As Long, ScreenDC As Long, retval As Long
  ScreenWidth = Screen.Width / Screen.TwipsPerPixelX
  ScreenHeight = Screen.Height / Screen.TwipsPerPixelY
  ScreenDC = GetDC(GetDesktopWindow)
  retval = BitBlt(DestinationDC, 0, 0, ScreenWidth, ScreenHeight, ScreenDC, 0, 0, SRCCOPY)
End Sub

i would specify a picture box using it's hdc value and this sub would fill in the screen shot in the desk top
0
 
LVL 6

Expert Comment

by:anthony_glenwright
ID: 6422075
Joshyy:  Cool method...  Thanks - I'm sure I'll use that one day...
0
 
LVL 1

Author Comment

by:Joshyy
ID: 6422127
Thanks anthony....
does any know how i can transfer this image (in memory) to another computer?
0
 
LVL 6

Expert Comment

by:anthony_glenwright
ID: 6422238
Well, as a first step, I managed to get the image to save to disk with:

Private Sub Command1_Click()
  ScreenShot Picture1.hDC
  SavePicture Picture1.Image, "c:\test.bmp"
End Sub

Using your ScreenShot() code.  Because the picture control is sooo old (dates back to vb1), it doesn't support any nice interfaces like IStream, etc, so this might be the only way to get at the bytes that make up the image.

The image that I saved was 593k, so it *should* transfer to another computer reasonably quickly.

But, of course, saving to/reading from a file is fairly clumsy.  I wrote another test program with the screen capture in a timer, and another program with a Image1.Image=LoadPicture("c:\test.bmp") in a timer, and as you might expect, it got errors because it was trying to read the file at the same time the capture program was writing it...You could try rotating the name of the file, or using GetTempFileName() for each capture but it would still be a bit iffy...
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 1

Author Comment

by:Joshyy
ID: 6423375
I already thought of that method.... but like u said it's clumsy

is there a variable of type image or picture? not the control though... maybe that could be a way of sending the image
0
 
LVL 6

Expert Comment

by:anthony_glenwright
ID: 6424294
I'm not familliar with the area of graphics.  This is as far as I got.

(Don't get your hopes up, it doesn't actually work...)

Option Explicit

Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long

Private Const SRCCOPY = &HCC0020

Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long

Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long

Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long

Private Const DIB_RGB_COLORS = 0 '  color table in RGBs

Private Type BITMAP '14 bytes
  bmType As Long
  bmWidth As Long
  bmHeight As Long
  bmWidthBytes As Long
  bmPlanes As Integer
  bmBitsPixel As Integer
  bmBits As Long
End Type

Private Type BITMAPINFOHEADER '40 bytes
  biSize As Long
  biWidth As Long
  biHeight As Long
  biPlanes As Integer
  biBitCount As Integer
  biCompression As Long
  biSizeImage As Long
  biXPelsPerMeter As Long
  biYPelsPerMeter As Long
  biClrUsed As Long
  biClrImportant As Long
End Type

Private Type RGBQUAD
  rgbBlue As Byte
  rgbGreen As Byte
  rgbRed As Byte
  rgbReserved As Byte
End Type


Private Type BITMAPINFO
  bmiHeader As BITMAPINFOHEADER
  bmiColors As RGBQUAD
End Type

Public Sub ScreenShot(DestinationDC As Long)
  Dim ScreenWidth As Long, ScreenHeight As Long, ScreenDC As Long, retval As Long
 
 ScreenWidth = Screen.Width / Screen.TwipsPerPixelX
 ScreenHeight = Screen.Height / Screen.TwipsPerPixelY
 ScreenDC = GetDC(GetDesktopWindow)
 retval = BitBlt(DestinationDC, 0, 0, ScreenWidth, ScreenHeight, ScreenDC, 0, 0, SRCCOPY)
 
End Sub


Private Sub Command1_Click()
  Dim lngDC As Long
  Dim lngBitmap As Long
  Dim lngOldObj As Long
  Dim udtBitmap As BITMAP
  Dim strBits As String
 
  Dim udtBitmapInfo As BITMAPINFO
 
  ' create a device context
  lngDC = CreateCompatibleDC(GetDC(GetDesktopWindow))
 
  ' CreateCompatibleDC will create a monochrome DC, 1 pixel by 1 pixel.
  ' We need to use CreateCompatibleBitmap to make the DC bigger, and
  ' to tell it to use the same colour depth as the desktop window
  lngBitmap = CreateCompatibleBitmap(GetDC(GetDesktopWindow), Screen.Width / Screen.TwipsPerPixelX, Screen.Height / Screen.TwipsPerPixelY)
 
  ' "select" the newly created bitmap into the DC we created.  Normally,
  ' we should hang onto the result of SelectObject so we can restore the
  ' previously selected object into the DC when we are done, but
  ' we just created it, so it should return 0 every time (I think!)...
  lngOldObj = SelectObject(lngDC, lngBitmap)
 
  ' Capture the screenshot
  ScreenShot lngDC
 
  ' I only put this code in so I could have a look at the udtBitmap structure in the
  ' debug window to verify the success (or otherwise) of the previous calls.
  '   You can look at the bitmap size (bmHeight/bmWidth), colour depth (bmBitsPixel), etc
  GetObject lngBitmap, Len(udtBitmap), udtBitmap
 
  ' GetDIBits returns a pointer to the actual bytes...
 
  ' First call to get the number of scanlines
 
  ' must set to the size of the BITMAPINFOHEADER structure
  udtBitmapInfo.bmiHeader.biBitCount = 40
 
  ' The API says we need to un-hook the bitmap structure from the DC before making this
  ' call
  SelectObject lngDC, lngOldObj
 
  GetDIBits lngDC, lngBitmap, 0, 0, ByVal 0, udtBitmapInfo, DIB_RGB_COLORS
 
  ' second call gets the data
  strBits = String(udtBitmapInfo.bmiHeader.biSizeImage, Chr$(0))
  GetDIBits lngDC, lngBitmap, 0, 0, ByVal StrPtr(strBits), udtBitmapInfo, DIB_RGB_COLORS
 
  ' clean up
  DeleteObject lngBitmap
  DeleteDC lngDC
 
 
End Sub



0
 
LVL 6

Expert Comment

by:anthony_glenwright
ID: 6424296
The GetDIBits call doesn't seem to work, though.
0
 
LVL 6

Expert Comment

by:anthony_glenwright
ID: 6424322
PS:  I'm still working on it..
0
 
LVL 6

Expert Comment

by:anthony_glenwright
ID: 6424361
Ok, heres some code that nearly works...  I am still saving to file, but for testing purposes...

The bmp that is saved *nearly* works.  I can load it in paintbrush, but the colours are all mucked up.  You should be able to tack on some winsock communications and complete it, though.

Option Explicit

Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long

Private Const SRCCOPY = &HCC0020

Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long

Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long

Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
'Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPCOREHEADER, ByVal wUsage As Long) As Long
Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFOHEADER, ByVal wUsage As Long) As Long

Private Const DIB_RGB_COLORS = 0 '  color table in RGBs

Private Type BITMAP '14 bytes
  bmType As Long
  bmWidth As Long
  bmHeight As Long
  bmWidthBytes As Long
  bmPlanes As Integer
  bmBitsPixel As Integer
  bmBits As Long
End Type

Private Type BITMAPFILEHEADER
  bfType As Integer
  bfSize As Long
  bfReserved1 As Integer
  bfReserved2 As Integer
  bfOffBits As Long
End Type

Private Type BITMAPINFOHEADER '40 bytes
  biSize As Long
  biWidth As Long
  biHeight As Long
  biPlanes As Integer
  biBitCount As Integer
  biCompression As Long
  biSizeImage As Long
  biXPelsPerMeter As Long
  biYPelsPerMeter As Long
  biClrUsed As Long
  biClrImportant As Long
End Type

Private Type BITMAPCOREHEADER '12 bytes
  bcSize As Long
  bcWidth As Integer
  bcHeight As Integer
  bcPlanes As Integer
  bcBitCount As Integer
End Type

Private Type RGBQUAD
  rgbBlue As Byte
  rgbGreen As Byte
  rgbRed As Byte
  rgbReserved As Byte
End Type

Public Sub ScreenShot(DestinationDC As Long)
  Dim ScreenWidth As Long, ScreenHeight As Long, ScreenDC As Long, retval As Long
 
 ScreenWidth = Screen.Width / Screen.TwipsPerPixelX
 ScreenHeight = Screen.Height / Screen.TwipsPerPixelY
 ScreenDC = GetDC(GetDesktopWindow)
 retval = BitBlt(DestinationDC, 0, 0, ScreenWidth, ScreenHeight, ScreenDC, 0, 0, SRCCOPY)
 
End Sub


Private Sub Command1_Click()
  Dim lngDC As Long
  Dim lngBitmap As Long
  Dim lngOldObj As Long
  Dim udtBitmap As BITMAP
  Dim strBits As String
  Dim lngScanLines As Integer
  Dim udtCoreHeader As BITMAPCOREHEADER
  Dim intFilenum As Integer
  Dim udtBitMapFileHeader As BITMAPFILEHEADER
  Dim udtInfoHeader As BITMAPINFOHEADER
  ' create a device context
  lngDC = CreateCompatibleDC(GetDC(GetDesktopWindow))
 
  ' CreateCompatibleDC will create a monochrome DC, 1 pixel by 1 pixel.
  ' We need to use CreateCompatibleBitmap to make the DC bigger, and
  ' to tell it to use the same colour depth as the desktop window
  lngBitmap = CreateCompatibleBitmap(GetDC(GetDesktopWindow), Screen.Width / Screen.TwipsPerPixelX, Screen.Height / Screen.TwipsPerPixelY)
 
  ' "select" the newly created bitmap into the DC we created.  Normally,
  ' we should hang onto the result of SelectObject so we can restore the
  ' previously selected object into the DC when we are done, but
  ' we just created it, so it should return 0 every time (I think!)...
  lngOldObj = SelectObject(lngDC, lngBitmap)
 
  ' Capture the screenshot
  ScreenShot lngDC
 
  ' Retrieve bitmap data for the call to GetDIBits
  GetObject lngBitmap, Len(udtBitmap), udtBitmap
 
  ' The API says we need to un-hook the bitmap structure from the DC before making this
  ' call
  SelectObject lngDC, lngOldObj
 
  ' GetDIBits returns a pointer to the actual bytes.
  'udtCoreHeader.bcSize = Len(udtCoreHeader)
  'udtCoreHeader.bcWidth
  'udtCoreHeader.bcHeight
  'udtCoreHeader.bcPlanes
  'udtCoreHeader.bcBitCount
   
  ' get the data
  strBits = String(udtBitmap.bmWidth * udtBitmap.bmHeight * udtBitmap.bmBitsPixel, Chr$(0))
  'lngScanLines = GetDIBits(lngDC, lngBitmap, 0, 768, ByVal StrPtr(strBits), udtCoreHeader, DIB_RGB_COLORS)
 
  udtInfoHeader.biSize = Len(udtInfoHeader)
  udtInfoHeader.biHeight = udtBitmap.bmHeight
  udtInfoHeader.biWidth = udtBitmap.bmWidth
  udtInfoHeader.biPlanes = udtBitmap.bmPlanes
  udtInfoHeader.biBitCount = udtBitmap.bmBitsPixel
  lngScanLines = GetDIBits(lngDC, lngBitmap, 0, 768, ByVal StrPtr(strBits), udtInfoHeader, DIB_RGB_COLORS)
 
  ' now the data should be in strBits
 
  ' save to file for test
  On Error Resume Next
  Kill "c:\test.bmp"
  On Error GoTo 0
 
  udtBitMapFileHeader.bfType = 19778   ' bitmap
  udtBitMapFileHeader.bfSize = Len(udtBitMapFileHeader) + Len(udtInfoHeader) + Len(strBits)
  udtBitMapFileHeader.bfReserved1 = 0
  udtBitMapFileHeader.bfReserved2 = 0
  udtBitMapFileHeader.bfOffBits = Len(udtBitMapFileHeader) + Len(udtInfoHeader)
 
  ' BMP file format specified at http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/BMP.txt
  intFilenum = FreeFile
  Open "c:\test.bmp" For Binary As intFilenum
  Put #intFilenum, , udtBitMapFileHeader
  Put #intFilenum, , udtInfoHeader
  'Put #intFilenum, , 0  ' null color table
  'Put #intFilenum, , 0
  Put #intFilenum, , strBits
  Close intFilenum
 
  ' clean up
  DeleteObject lngBitmap
  DeleteDC lngDC
 
 
End Sub


0
 
LVL 6

Expert Comment

by:anthony_glenwright
ID: 6424429
Erk.. after doing all that code, I found a link that might help you

http://support.microsoft.com/support/kb/articles/Q161/2/99.ASP

0
 
LVL 1

Expert Comment

by:krees
ID: 6426780
i still cant find the api that converts your hdc into actual bytes, but having that, with the winsock method, SendData you will be able to tackle your problem!

0
 
LVL 1

Author Comment

by:Joshyy
ID: 6427747
is this the function you were refering to? GetBitmapBits
0
 
LVL 1

Author Comment

by:Joshyy
ID: 6427749
Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long

if so... explain its parameters
0
 
LVL 15

Accepted Solution

by:
JackOfPH earned 50 total points
ID: 6430940
sorry
i know i am late but i asked that all ready...
just want to help...
here's the link
http://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=visualbasic&qid=20160781
hope taht will help you.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Enums (shorthand for ‘enumerations’) are not often used by programmers but they can be quite valuable when they are.  What are they? An Enum is just a type of variable like a string or an Integer, but in this case one that you create that contains…
Whether you’re a college noob or a soon-to-be pro, these tips are sure to help you in your journey to becoming a programming ninja and stand out from the crowd.
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

746 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

9 Experts available now in Live!

Get 1:1 Help Now