Jump to content

Screenshot Over TCP?


Recommended Posts

Anyone know why transferring pictures captured using the "_ScreenCapture_Capture" function over TCP screws up the picture? I have made a TCP server-client setup, and I know it works. I take a screen-shot using a separate script, and transfer the file to the client from the server, saving it with the "FileWrite" function, opening it with flag 18, but it comes up as either invalid image in Picasa, or only the first 1/30th or so of the picture comes up at the top.

Any ideas?

403foridden

Link to comment
Share on other sites

Client, sending the picture

#include <ScreenCapture.au3>
#include <File.au3>

TCPStartup()

Global $TCPConnect = TCPConnect(@IPAddress1, 3825)

$ScreenshotName = _TempFile(@ScriptDir, "~", ".jpg")
_ScreenCapture_SetJPGQuality(90)
_ScreenCapture_Capture($ScreenshotName)
$ScreenshotHandle = FileOpen($ScreenshotName, 16)
TCPSend($TCPConnect, FileRead($ScreenshotHandle))
FileClose($ScreenshotHandle)
FileDelete($ScreenshotName)

Server, receiving the picture.

#include <File.au3>

TCPStartup()

Global $TCPListen = TCPListen(@IPAddress1, 3825)

Do
    $TCPAccept = TCPAccept($TCPListen)
Until $TCPAccept <> -1

Do
    $TCPRecv = TCPRecv($TCPAccept, 134217728)
Until $TCPRecv <> ""

$ScreenshotName = _TempFile(@ScriptDir, "~", ".jpg")
$ScreenshotHandle = FileOpen($ScreenshotName, 18)
FileWrite($ScreenshotHandle, $TCPRecv)
FileClose($ScreenshotHandle)
Link to comment
Share on other sites

  • 2 weeks later...
  • 2 years later...

I'm currently working on this as a feature for my script. The problem is that you are trying to send too much data at once. This isn't autoit's problem, it's your network adapter. I'm going to try taking multiple screenshots and combing them, but I doubt that will work.

There are 10 types of people in this world. Those that understand binary, and those that do not

Link to comment
Share on other sites

Here an example how to send an image without saving it to disk first!

It will take a screenshot, convert it to a jpg image and send to the server everything done in the memory!

Client Send - Receive Picture.au3

#include <memory.au3>
#include <screencapture.au3>

_GDIPlus_Startup()

TCPStartup()

Local $ConnectedSocket, $szData
Local $szIPADDRESS = @IPAddress1
Local $nPORT = 33891

$ConnectedSocket = -1

$ConnectedSocket = TCPConnect($szIPADDRESS, $nPORT)

If @error Then Exit MsgBox(4112, "Error", "TCPConnect failed with WSA error: " & @error)

$iMsgBox = MsgBox(4, "Send image", "Send image to server?")
If $iMsgBox = 6 Then
    $hHBITMAP = _ScreenCapture_Capture("", 0, 0, 100, 100)
    $bImage = HBITMAP2BinaryString($hHBITMAP)
    ConsoleWrite(TCPSend($ConnectedSocket, Binary($bImage)) & @LF)
    _WinAPI_DeleteObject($hHBITMAP)
EndIf

_GDIPlus_Shutdown()

Exit

Func HBITMAP2BinaryString($HBITMAP) ;function by Andreik
    Local $BITMAP = _GDIPlus_BitmapCreateFromHBITMAP($HBITMAP)
    Local $JPG_ENCODER = _GDIPlus_EncodersGetCLSID("jpg")
    Local $TAG_ENCODER = _WinAPI_GUIDFromString($JPG_ENCODER)
    Local $PTR_ENCODER = DllStructGetPtr($TAG_ENCODER)
    Local $STREAM = DllCall("ole32.dll", "uint", "CreateStreamOnHGlobal", "ptr", 0, "bool", 1, "ptr*", 0)
    DllCall($ghGDIPDll, "uint", "GdipSaveImageToStream", "ptr", $BITMAP, "ptr", $STREAM[3], "ptr", $PTR_ENCODER, "ptr", 0)
    _GDIPlus_BitmapDispose($BITMAP)
    Local $MEMORY = DllCall("ole32.dll", "uint", "GetHGlobalFromStream", "ptr", $STREAM[3], "ptr*", 0)
    Local $MEM_SIZE = _MemGlobalSize($MEMORY[2])
    Local $MEM_PTR = _MemGlobalLock($MEMORY[2])
    Local $DATA_STRUCT = DllStructCreate("byte[" & $MEM_SIZE & "]", $MEM_PTR)
    Local $DATA = DllStructGetData($DATA_STRUCT, 1)
    Local $tVARIANT = DllStructCreate("word vt;word r1;word r2;word r3;ptr data;ptr")
    Local $aCall = DllCall("oleaut32.dll", "long", "DispCallFunc", "ptr", $STREAM[3], "dword", 8 + 8 * @AutoItX64, "dword", 4, "dword", 23, "dword", 0, "ptr", 0, "ptr", 0, "ptr", DllStructGetPtr($tVARIANT))
    _MemGlobalFree($MEMORY[2])
    Return $DATA
EndFunc   ;==>HBITMAP2BinaryString

Server Send - Receive Picture.au3

#include <guiconstantsex.au3>
#include <gdiplus.au3>
#include <memory.au3>
#include <staticconstants.au3>

Local $szIPADDRESS = @IPAddress1
Local $nPORT = 33891
Local $MainSocket, $edit, $ConnectedSocket, $szIP_Accepted
Local $msg, $recv

TCPStartup()

$MainSocket = TCPListen($szIPADDRESS, $nPORT)

If $MainSocket = -1 Then Exit

GUICreate("My Server (IP: " & $szIPADDRESS & ")", 300, 200, 100, 100, Default, 0x00000008)
$edit = GUICtrlCreateEdit("", 10, 10, 280, 180)
GUISetState()

$ConnectedSocket = -1

Do
    $ConnectedSocket = TCPAccept($MainSocket)
Until $ConnectedSocket <> -1

$szIP_Accepted = SocketToIP($ConnectedSocket)

While 1
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then ExitLoop
    $recv = TCPRecv($ConnectedSocket, 8192, 1)
    If @error Then ExitLoop
    If $recv <> "" Then GUICtrlSetData($edit, $recv)
WEnd

If $ConnectedSocket <> -1 Then TCPCloseSocket($ConnectedSocket)
TCPShutdown()

Global Const $IMAGE_BITMAP = 0
Global Const $STM_SETIMAGE = 0x0172

_GDIPlus_Startup()
$hBitmap = Load_BMP_From_Mem(Binary(GUICtrlRead($edit)), True)

$hGUI = GUICreate("Test", 320, 200)
$idPic = GUICtrlCreatePic("", 0, 0, 320, 200, $SS_CENTERIMAGE)
GUISetState()

_WinAPI_DeleteObject(GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hBitmap))

Do
Until GUIGetMsg() = -3

_WinAPI_DeleteObject($hBitmap)
_GDIPlus_Shutdown()
Exit

Func SocketToIP($SHOCKET)
    Local $sockaddr, $aRet
    $sockaddr = DllStructCreate("short;ushort;uint;char[8]")
    $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, "ptr", DllStructGetPtr($sockaddr), "int*", DllStructGetSize($sockaddr))
    If Not @error And $aRet[0] = 0 Then
        $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3))
        If Not @error Then $aRet = $aRet[0]
    Else
        $aRet = 0
    EndIf
    $sockaddr = 0
    Return $aRet
EndFunc   ;==>SocketToIP

;======================================================================================
; Function Name:    Load_BMP_From_Mem
; Description:          Loads an image which is saved as a binary string and converts it to a bitmap or hbitmap
;
; Parameters:           $bImage:    the binary string which contains any valid image which is supported by GDI+
; Optional:                 $hHBITMAP:  if false a bitmap will be created, if true a hbitmap will be created
;
; Remark:                   hbitmap format is used generally for GUI internal images, $bitmap is more a GDI+ image format
;                               Don't forget _GDIPlus_Startup() and _GDIPlus_Shutdown()
;
; Requirement(s):       GDIPlus.au3, Memory.au3 and _GDIPlus_BitmapCreateDIBFromBitmap() from WinAPIEx.au3
; Return Value(s):  Success: handle to bitmap (GDI+ bitmap format) or hbitmap (WinAPI bitmap format),
;                               Error: 0
; Error codes:              1: $bImage is not a binary string
;                               2: unable to create stream on HGlobal
;                               3: unable to create bitmap from stream
;
; Author(s):                UEZ
; Additional Code:    thanks to progandy for the MemGlobalAlloc and tVARIANT lines and
;                               Yashied for _GDIPlus_BitmapCreateDIBFromBitmap() from WinAPIEx.au3
; Version:                  v0.97 Build 2012-04-10 Beta
;=======================================================================================
Func Load_BMP_From_Mem($bImage, $hHBITMAP = False)
    If Not IsBinary($bImage) Then Return SetError(1, 0, 0)
    Local $aResult
    Local Const $memBitmap = Binary($bImage) ;load image  saved in variable (memory) and convert it to binary
    Local Const $len = BinaryLen($memBitmap) ;get length of image
    Local Const $hData = _MemGlobalAlloc($len, $GMEM_MOVEABLE) ;allocates movable memory  ($GMEM_MOVEABLE = 0x0002)
    Local Const $pData = _MemGlobalLock($hData) ;translate the handle into a pointer
    Local $tMem = DllStructCreate("byte[" & $len & "]", $pData) ;create struct
    DllStructSetData($tMem, 1, $memBitmap) ;fill struct with image data
    _MemGlobalUnlock($hData) ;decrements the lock count  associated with a memory object that was allocated with GMEM_MOVEABLE
    $aResult = DllCall("ole32.dll", "int", "CreateStreamOnHGlobal", "handle", $pData, "int", True, "ptr*", 0) ;Creates a stream object that uses an HGLOBAL memory handle to store the stream contents
    If @error Then Return SetError(2, 0, 0)
    Local Const $hStream = $aResult[3]
    $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromStream", "ptr", $hStream, "int*", 0) ;Creates a Bitmap object based on an IStream COM interface
    If @error Then Return SetError(3, 0, 0)
    Local Const $hBitmap = $aResult[2]
    Local $tVARIANT = DllStructCreate("word vt;word r1;word r2;word r3;ptr data; ptr")
    DllCall("oleaut32.dll", "long", "DispCallFunc", "ptr", $hStream, "dword", 8 + 8 * @AutoItX64, _
                                           "dword", 4, "dword", 23, "dword", 0, "ptr", 0, "ptr", 0, "ptr", DllStructGetPtr($tVARIANT)) ;release memory from $hStream to avoid memory leak
    $tMem = 0
    $tVARIANT = 0
    If $hHBITMAP Then
        Local Const $hHBmp = _GDIPlus_BitmapCreateDIBFromBitmap($hBitmap)
        _GDIPlus_BitmapDispose($hBitmap)
        Return $hHBmp
    EndIf
    Return $hBitmap
EndFunc   ;==>Load_BMP_From_Mem

Func _GDIPlus_BitmapCreateDIBFromBitmap($hBitmap)
    Local $tBIHDR, $Ret, $tData, $pBits, $hResult = 0
    $Ret = DllCall($ghGDIPDll, 'uint', 'GdipGetImageDimension', 'ptr', $hBitmap, 'float*', 0, 'float*', 0)
    If (@error) Or ($Ret[0]) Then Return 0
    $tData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $Ret[2], $Ret[3], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    $pBits = DllStructGetData($tData, 'Scan0')
    If Not $pBits Then Return 0
    $tBIHDR = DllStructCreate('dword;long;long;ushort;ushort;dword;dword;long;long;dword;dword')
    DllStructSetData($tBIHDR, 1, DllStructGetSize($tBIHDR))
    DllStructSetData($tBIHDR, 2, $Ret[2])
    DllStructSetData($tBIHDR, 3, $Ret[3])
    DllStructSetData($tBIHDR, 4, 1)
    DllStructSetData($tBIHDR, 5, 32)
    DllStructSetData($tBIHDR, 6, 0)
    $hResult = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBIHDR), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'dword', 0)
    If (Not @error) And ($hResult[0]) Then
        DllCall('gdi32.dll', 'dword', 'SetBitmapBits', 'ptr', $hResult[0], 'dword', $Ret[2] * $Ret[3] * 4, 'ptr', DllStructGetData($tData, 'Scan0'))
        $hResult = $hResult[0]
    Else
        $hResult = 0
    EndIf
    _GDIPlus_BitmapUnlockBits($hBitmap, $tData)
    Return $hResult
EndFunc   ;==>_GDIPlus_BitmapCreateDIBFromBitmap

Start first Server Send - Receive Picture.au3 and then Client Send - Receive Picture.au3.

Because I'm not familiar with the tcp/ip stuff I took the tcp/ip stuff from the help file!

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

I'm currently working on this as a feature for my script. The problem is that you are trying to send too much data at once. This isn't autoit's problem, it's your network adapter. I'm going to try taking multiple screenshots and combing them, but I doubt that will work.

Did you know you're replying to a conversation that ended over two years ago?

Whenever someone says "pls" because it's shorter than "please", I say "no" because it's shorter than "yes".

Link to comment
Share on other sites

Server (run first)

#Include <APIConstants.au3>
#Include <GDIPlus.au3>
#Include <Memory.au3>
#Include <WinAPIEx.au3>

Global Const $STM_SETIMAGE = 0x0172
Global Const $STM_GETIMAGE = 0x0173

TCPStartup()
$Main = TCPListen(@IPAddress1, 33891)
If @error Then
    Exit
EndIf

GUICreate('MyGUI', 800, 600, @DesktopWidth - 819, @DesktopHeight - 671)
$Pic = GUICtrlCreatePic('', 0, 0, 800, 600)
GUISetState()

Do
    $Socket = TCPAccept($Main)
Until $Socket <> -1

Global $tHeader = DllStructCreate('byte[4]')
Global $pHeader = DllStructGetPtr($tHeader)
Global $bData = 0, $Count = 0

_GDIPlus_Startup()

Do
    If Not IsBinary($bData) Then
        $bData = TCPRecv($Socket, 16384, 1)
        If @error Then
            ExitLoop
        EndIf
    EndIf
    If IsBinary($bData) Then
        If Not $Count Then
            DllStructSetData($tHeader, 1, $bData)
            $tData = DllStructCreate('dword', $pHeader)
            $Size = DllStructGetData($tData, 1)
            $tData = DllStructCreate('byte[' & $Size & ']')
            $pData = DllStructGetPtr($tData)
        EndIf
        $Lenght = BinaryLen($bData)
        $Sum = $Count + $Lenght
        If $Sum > $Size Then
            $dL = $Size - $Count
            $tPart = DllStructCreate('byte[' & $dL & ']', $pData + $Count)
            DllStructSetData($tPart, 1, $bData)
            $tByte = DllStructCreate('byte[' & $Lenght & ']')
            $tRecv = DllStructCreate('byte[' & ($Lenght - $dL) & ']', DllStructGetPtr($tByte) + $dL)
            DllStructSetData($tByte, 1, $bData)
            $bData = DllStructGetData($tRecv, 1)
            $Sum = $Size
        Else
            $tPart = DllStructCreate('byte[' & $Lenght & ']', $pData + $Count)
            DllStructSetData($tPart, 1, $bData)
            $Count = $Sum
            $bData = 0
        EndIf
        If $Sum = $Size Then
            _SetScreenshot($Pic, $tData)
            $Count = 0
        EndIf
    EndIf
Until GUIGetMsg() = -3

_GDIPlus_Shutdown()

TCPCloseSocket($Socket)
TCPShutdown()

Func _SetScreenshot($CtrlID, ByRef $tData, $fUpdate = 0)

    Local $hBitmap, $hPrev, $hScreen, $hMemory, $pMemory, $pStream, $pData, $iSize

    $hWnd = GUICtrlGetHandle($CtrlID)
    If Not $hWnd Then
        Return 0
    EndIf

    $pData = DllStructGetPtr($tData)
    $iSize = DllStructGetData(DllStructCreate('dword', $pData + 4), 1)
    $hMemory = _MemGlobalAlloc($iSize, $GMEM_MOVEABLE)
    $pMemory = _MemGlobalLock($hMemory)
    _MemMoveMemory($pData + 8, $pMemory, $iSize)
    _MemGlobalUnlock($hMemory)
    $pStream = _WinAPI_CreateStreamOnHGlobal($hMemory)
    $hBitmap = _GDIPlus_CreateBitmapFromStream($pStream)
    $hScreen = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    _GDIPlus_BitmapDispose($hBitmap)
    _WinAPI_ReleaseStream($pStream)
    _WinAPI_DeleteObject(_SendMessage($hWnd, $STM_SETIMAGE, $IMAGE_BITMAP, $hScreen))
    $hPrev = _SendMessage($hWnd, $STM_GETIMAGE)
    If $hPrev <> $hScreen Then
        _WinAPI_DeleteObject($hScreen)
    EndIf
    If $fUpdate Then
        _WinAPI_UpdateWindow($hWnd)
    EndIf
    Return 1
EndFunc   ;==>_SetScreenshot

Func _GDIPlus_CreateBitmapFromStream($pStream)

    Local $Ret = DllCall($ghGDIPDll, 'uint', 'GdipCreateBitmapFromStream', 'ptr', $pStream, 'ptr*', 0)

    If (@error) Or ($Ret[0]) Then
        Return SetError(@error, @extended, 0)
    EndIf
    Return $Ret[2]
EndFunc   ;==>_GDIPlus_CreateBitmapFromStream

Client

#Include <APIConstants.au3>
#Include <GDIPlus.au3>
#Include <Memory.au3>
#Include <WinAPIEx.au3>

TCPStartup()
$Socket = TCPConnect(@IPAddress1, 33891)
If @error Then
    Exit
EndIf

_GDIPlus_Startup()

Global $tEncoder = _WinAPI_GUIDFromString(_GDIPlus_EncodersGetCLSID('png'))
Global $pEncoder = DllStructGetPtr($tEncoder)

While 1
    TCPSend($Socket, _GetScreenshot(0, 0, 800, 600))
    If @error Then
        ExitLoop
    EndIf
    Sleep(1000)
WEnd

_GDIPlus_Shutdown()

TCPShutdown()

Func _GetScreenshot($iX = 0, $iY = 0, $iWidth = -1, $iHeight = -1)

    Local $hSrcDC, $hDstDC, $hDstSv, $hBitmap, $hDesktop, $hScreen, $hMemory, $pMemory, $pStream, $tOut, $pOut, $iSize

    If $iWidth = -1 Then
        $iWidth = @DesktopWidth
    EndIf
    If $iHeight = -1 Then
        $iHeight = @DesktopHeight
    EndIf
    $hDesktop = _WinAPI_GetDesktopWindow()
    $hSrcDC = _WinAPI_GetDC($hDesktop)
    $hScreen = _WinAPI_CreateCompatibleBitmap($hSrcDC, $iWidth, $iHeight)
    $hDstDC = _WinAPI_CreateCompatibleDC($hSrcDC)
    $hDstSv = _WinAPI_SelectObject($hDstDC, $hScreen)
    _WinAPI_BitBlt($hDstDC, $iX, $iY, $iWidth, $iHeight, $hSrcDC, $iX, $iY, $SRCCOPY)
    _WinAPI_SelectObject($hDstDC, $hDstSv)
    _WinAPI_ReleaseDC($hDesktop, $hSrcDC)
    _WinAPI_DeleteDC($hDstDC)
    $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hScreen)
    _WinAPI_DeleteObject($hScreen)
    $pStream = _WinAPI_CreateStreamOnHGlobal(0)
    _GDIPlus_SaveImageToStream($hBitmap, $pStream, $pEncoder)
    _GDIPlus_BitmapDispose($hBitmap)
    $hMemory = _WinAPI_GetHGlobalFromStream($pStream)
    $pMemory = _MemGlobalLock($hMemory)
    $iSize = _MemGlobalSize($hMemory)
    $tOut = DllStructCreate('dword;dword;byte[' & ($iSize - Mod($iSize, 4) + 4) & ']')
    $pOut = DllStructGetPtr($tOut)
    DllStructSetData($tOut, 1, DllStructGetSize($tOut))
    DllStructSetData($tOut, 2, $iSize)
    _MemMoveMemory($pMemory, $pOut + 8, $iSize)
    _WinAPI_ReleaseStream($pStream)
    Return DllStructGetData(DllStructCreate('byte[' & DllStructGetSize($tOut) & ']', DllStructGetPtr($tOut)), 1)
EndFunc   ;==>_GetScreenshot

Func _GDIPlus_SaveImageToStream($hImage, $pStream, $pEncoder, $pParams = 0)

    Local $Ret = DllCall($ghGDIPDll, 'uint', 'GdipSaveImageToStream', 'ptr', $hImage, 'ptr', $pStream, 'ptr', $pEncoder, 'ptr', $pParams)

    If (@error) Or ($Ret[0]) Then
        Return SetError(@error, @extended, 0)
    EndIf
    Return 1
EndFunc   ;==>_GDIPlus_SaveImageToStream
Link to comment
Share on other sites

  • 2 weeks later...
  • Moderators

szalaisanyi86,

Welcome to the AutoIt forum. :oops:

You can find them here. :bye:

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

  • 10 months later...

@Yashied

(I know this is an old post but still interesting for me.....)

I tryed your client/server scripts and are working well on the same computer,

when i run the client, i get screenshots from the client script to server script;

but I get only a black screen if server and client are 2 separate computers....

of course i set the ip address of the server at the following line of code in the client script:

$Socket = TCPConnect("10.0.0.222", 33891) ; the ip of the server

why only a black screen in response?

any suggestion is welcome

thanks

Pincopanco

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

.... I found the problem myself,

If the client is started on the remote computer with psexec (like I do) is necessary to use the "-i" parameter in psexec otherwise a black screen is returned by the client.

with the following command for example I receive only a black screen:

psexec remotepc -u domainusername -p password -c client.exe

while withe with this command (added -i) I receive a regular screenshot of the client:

psexec remotepc -u domainusername -p password -i -c client.exe

bye

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

  • 1 year later...

Server (run first)

#Include <APIConstants.au3>
#Include <GDIPlus.au3>
#Include <Memory.au3>
#Include <WinAPIEx.au3>

Global Const $STM_SETIMAGE = 0x0172
Global Const $STM_GETIMAGE = 0x0173

TCPStartup()
$Main = TCPListen(@IPAddress1, 33891)
If @error Then
    Exit
EndIf

GUICreate('MyGUI', 800, 600, @DesktopWidth - 819, @DesktopHeight - 671)
$Pic = GUICtrlCreatePic('', 0, 0, 800, 600)
GUISetState()

Do
    $Socket = TCPAccept($Main)
Until $Socket <> -1

Global $tHeader = DllStructCreate('byte[4]')
Global $pHeader = DllStructGetPtr($tHeader)
Global $bData = 0, $Count = 0

_GDIPlus_Startup()

Do
    If Not IsBinary($bData) Then
        $bData = TCPRecv($Socket, 16384, 1)
        If @error Then
            ExitLoop
        EndIf
    EndIf
    If IsBinary($bData) Then
        If Not $Count Then
            DllStructSetData($tHeader, 1, $bData)
            $tData = DllStructCreate('dword', $pHeader)
            $Size = DllStructGetData($tData, 1)
            $tData = DllStructCreate('byte[' & $Size & ']')
            $pData = DllStructGetPtr($tData)
        EndIf
        $Lenght = BinaryLen($bData)
        $Sum = $Count + $Lenght
        If $Sum > $Size Then
            $dL = $Size - $Count
            $tPart = DllStructCreate('byte[' & $dL & ']', $pData + $Count)
            DllStructSetData($tPart, 1, $bData)
            $tByte = DllStructCreate('byte[' & $Lenght & ']')
            $tRecv = DllStructCreate('byte[' & ($Lenght - $dL) & ']', DllStructGetPtr($tByte) + $dL)
            DllStructSetData($tByte, 1, $bData)
            $bData = DllStructGetData($tRecv, 1)
            $Sum = $Size
        Else
            $tPart = DllStructCreate('byte[' & $Lenght & ']', $pData + $Count)
            DllStructSetData($tPart, 1, $bData)
            $Count = $Sum
            $bData = 0
        EndIf
        If $Sum = $Size Then
            _SetScreenshot($Pic, $tData)
            $Count = 0
        EndIf
    EndIf
Until GUIGetMsg() = -3

_GDIPlus_Shutdown()

TCPCloseSocket($Socket)
TCPShutdown()

Func _SetScreenshot($CtrlID, ByRef $tData, $fUpdate = 0)

    Local $hBitmap, $hPrev, $hScreen, $hMemory, $pMemory, $pStream, $pData, $iSize

    $hWnd = GUICtrlGetHandle($CtrlID)
    If Not $hWnd Then
        Return 0
    EndIf

    $pData = DllStructGetPtr($tData)
    $iSize = DllStructGetData(DllStructCreate('dword', $pData + 4), 1)
    $hMemory = _MemGlobalAlloc($iSize, $GMEM_MOVEABLE)
    $pMemory = _MemGlobalLock($hMemory)
    _MemMoveMemory($pData + 8, $pMemory, $iSize)
    _MemGlobalUnlock($hMemory)
    $pStream = _WinAPI_CreateStreamOnHGlobal($hMemory)
    $hBitmap = _GDIPlus_CreateBitmapFromStream($pStream)
    $hScreen = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    _GDIPlus_BitmapDispose($hBitmap)
    _WinAPI_ReleaseStream($pStream)
    _WinAPI_DeleteObject(_SendMessage($hWnd, $STM_SETIMAGE, $IMAGE_BITMAP, $hScreen))
    $hPrev = _SendMessage($hWnd, $STM_GETIMAGE)
    If $hPrev <> $hScreen Then
        _WinAPI_DeleteObject($hScreen)
    EndIf
    If $fUpdate Then
        _WinAPI_UpdateWindow($hWnd)
    EndIf
    Return 1
EndFunc   ;==>_SetScreenshot

Func _GDIPlus_CreateBitmapFromStream($pStream)

    Local $Ret = DllCall($ghGDIPDll, 'uint', 'GdipCreateBitmapFromStream', 'ptr', $pStream, 'ptr*', 0)

    If (@error) Or ($Ret[0]) Then
        Return SetError(@error, @extended, 0)
    EndIf
    Return $Ret[2]
EndFunc   ;==>_GDIPlus_CreateBitmapFromStream

Client

#Include <APIConstants.au3>
#Include <GDIPlus.au3>
#Include <Memory.au3>
#Include <WinAPIEx.au3>

TCPStartup()
$Socket = TCPConnect(@IPAddress1, 33891)
If @error Then
    Exit
EndIf

_GDIPlus_Startup()

Global $tEncoder = _WinAPI_GUIDFromString(_GDIPlus_EncodersGetCLSID('png'))
Global $pEncoder = DllStructGetPtr($tEncoder)

While 1
    TCPSend($Socket, _GetScreenshot(0, 0, 800, 600))
    If @error Then
        ExitLoop
    EndIf
    Sleep(1000)
WEnd

_GDIPlus_Shutdown()

TCPShutdown()

Func _GetScreenshot($iX = 0, $iY = 0, $iWidth = -1, $iHeight = -1)

    Local $hSrcDC, $hDstDC, $hDstSv, $hBitmap, $hDesktop, $hScreen, $hMemory, $pMemory, $pStream, $tOut, $pOut, $iSize

    If $iWidth = -1 Then
        $iWidth = @DesktopWidth
    EndIf
    If $iHeight = -1 Then
        $iHeight = @DesktopHeight
    EndIf
    $hDesktop = _WinAPI_GetDesktopWindow()
    $hSrcDC = _WinAPI_GetDC($hDesktop)
    $hScreen = _WinAPI_CreateCompatibleBitmap($hSrcDC, $iWidth, $iHeight)
    $hDstDC = _WinAPI_CreateCompatibleDC($hSrcDC)
    $hDstSv = _WinAPI_SelectObject($hDstDC, $hScreen)
    _WinAPI_BitBlt($hDstDC, $iX, $iY, $iWidth, $iHeight, $hSrcDC, $iX, $iY, $SRCCOPY)
    _WinAPI_SelectObject($hDstDC, $hDstSv)
    _WinAPI_ReleaseDC($hDesktop, $hSrcDC)
    _WinAPI_DeleteDC($hDstDC)
    $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hScreen)
    _WinAPI_DeleteObject($hScreen)
    $pStream = _WinAPI_CreateStreamOnHGlobal(0)
    _GDIPlus_SaveImageToStream($hBitmap, $pStream, $pEncoder)
    _GDIPlus_BitmapDispose($hBitmap)
    $hMemory = _WinAPI_GetHGlobalFromStream($pStream)
    $pMemory = _MemGlobalLock($hMemory)
    $iSize = _MemGlobalSize($hMemory)
    $tOut = DllStructCreate('dword;dword;byte[' & ($iSize - Mod($iSize, 4) + 4) & ']')
    $pOut = DllStructGetPtr($tOut)
    DllStructSetData($tOut, 1, DllStructGetSize($tOut))
    DllStructSetData($tOut, 2, $iSize)
    _MemMoveMemory($pMemory, $pOut + 8, $iSize)
    _WinAPI_ReleaseStream($pStream)
    Return DllStructGetData(DllStructCreate('byte[' & DllStructGetSize($tOut) & ']', DllStructGetPtr($tOut)), 1)
EndFunc   ;==>_GetScreenshot

Func _GDIPlus_SaveImageToStream($hImage, $pStream, $pEncoder, $pParams = 0)

    Local $Ret = DllCall($ghGDIPDll, 'uint', 'GdipSaveImageToStream', 'ptr', $hImage, 'ptr', $pStream, 'ptr', $pEncoder, 'ptr', $pParams)

    If (@error) Or ($Ret[0]) Then
        Return SetError(@error, @extended, 0)
    EndIf
    Return 1
EndFunc   ;==>_GDIPlus_SaveImageToStream

 

Hello all,

I'm aware, that this is a very old thread. Still the mentioned method is the best, I've found so far, to stream a remote screen.

Now I have two questions about this, and hopefully somebody can help:

1. Is it possible, to decrease the picture resolution? This should have two advantages:

- You can see the entire remote screen, even if the remote computer uses a higher resolution.

- It should load quicker, as a smaller amount of data is being transfered.

2. Is it possible to use this method to stream the webcam picture instead of the screen picture?

I tried but failed on both so far.

Thanks a lot!

Link to comment
Share on other sites

Regarding

1.

Check out _GDIPlus_ImageScale() and _GDIPlus_ImageResize() but have in mind that resizing costs time which can decrease the FPS.

2.

I don't have a web cam but it should be possible, too.

 

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...