Jump to content

Recommended Posts

Posted

I stumbled upon the code of @Yashied here at this thread https://www.autoitscript.com/forum/topic/108145-screenshot-over-tcp/?tab=comments#comment-969161 about sending Secreenshots through TCP without saving a physical file to the drive. I tried editing the code and found an error i cant figure it out. can anyone help ?

Server

#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(@IPAddress4, 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(@IPAddress4, 33891)
If @error Then
    Exit
EndIf

_GDIPlus_Startup()

Global $tEncoder = _WinAPI_GUIDFromString(_GDIPlus_EncodersGetCLSID('png'))
Global $pEncoder = DllStructGetPtr($tEncoder)
Local $iWidth = @DesktopWidth
 Local $iHeight = @DesktopHeight
 Local $iX = 0
 Local $iY = 0

While 1
    TCPSend($Socket, _GetScreenshot($iX, $iY, $iWidth, $iHeight))
    If @error Then
       ExitLoop
   EndIf
    Sleep(1000)
WEnd

_GDIPlus_Shutdown()

TCPShutdown()

Func _GetScreenshot($iX,$iY, $iWidth, $iHeight)

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

    $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,$pParams)
    _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


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

    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

the error on the attached file

er.png

  • Moderators
Posted

BlackSnoww,

The $ghGDIPDll DLL name within the various GDI #include files was renamed a long time ago to $__g_hGDIPDll - try changing that in the calling line and see if it works.

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

 

Posted

@Melba23

Thanks for your help i have this fully working on TCP.

on the side note i have implemented this using Mailslots UDF as the TCP version made a bottleneck in sending the screenshots lol.

I was hoping this would make is faster.

 

So my problem is

Running the mailslots on the same PC runs without a problem. Problem arise when its run on the different PC.

the mailslot name used on the same PC  "Both server and client is using the same name"

Global Const $sMailSlotName = "\\.\mailslot\RandomNameForThisTest"

 

 

On the different PC

Name for host

Global Const $sMailSlotName = "\\.\mailslot\RandomNameForThisTest"

Name for Client where localuser-PC is the computer name of the host

Global Const $sMailSlotName = "\\localuser-PC\mailslot\RandomNameForThisTest"

Mailslot naming was made to this due to the reading made from this site https://www.codeproject.com/Articles/8527/Using-Mailslots-for-Interprocess-Communication "after the introduction part"

my the Client returns a error code of 2 which the UDF documentation states "WriteFile function or call to it failed." and i dont know why.

can you help me ? maybe u know whats my problem because in my digging u have been using mailslots alot xD

 

Server

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include "MailSlot.au3"
#Include <APIConstants.au3>
#Include <GDIPlus.au3>
#Include <Memory.au3>
#Include <WinAPIEx.au3>


Global Const $sMailSlotName = "\\.\mailslot\RandomNameForThisTest"
Global $hMailSlot = _MailSlotCreate($sMailSlotName)
If @error Then
    MsgBox(48 + 262144, "MailSlot", "Failed to create new account!" & @CRLF & "Probably one using that 'address' already exists.")
    Exit
EndIf


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


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

_GDIPlus_Startup()

Do
      _ReadMessage($hMailSlot)
      $bData = $sData


    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()

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($__g_hGDIPDll, 'uint', 'GdipCreateBitmapFromStream', 'ptr', $pStream, 'ptr*', 0)

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


Func _ReadMessage($hHandle)

    Local $iSize = _MailSlotCheckForNextMessage($hHandle)

    If $iSize Then
         $sData = _MailSlotRead($hMailSlot, $iSize, 0)
    ;   $iNumberOfMessagesOverall += 1
    ;   GUICtrlSetData($hEdit, "Message No" & $iNumberOfMessagesOverall & " , Size = " & $iSize & " :" & @CRLF & @CRLF & $sData)
    Else
    ;   MsgBox(64, "Nothing read", "MailSlot is empty", 0, $hGUI)
    EndIf
EndFunc   ;==>_ReadMessage

Client

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#Include <APIConstants.au3>
#Include <GDIPlus.au3>
#Include <Memory.au3>
#Include <WinAPIEx.au3>
#include <File.au3>
#include <MsgBoxConstants.au3>
#include "MailSlot.au3"


_GDIPlus_Startup()

Global Const $sMailSlotName = "\\localuser-PC\mailslot\RandomNameForThisTest"

Global $tEncoder = _WinAPI_GUIDFromString(_GDIPlus_EncodersGetCLSID('png'))
Global $pEncoder = DllStructGetPtr($tEncoder)
Local $iWidth = @DesktopWidth
 Local $iHeight = @DesktopHeight
 Local $iX = 0
 Local $iY = 0
 Global $time = 0

Global $Loops = 10
Global $begin = TimerInit()


While 1
      $ret =  _GetScreenshot($iX, $iY, $iWidth, $iHeight)
      _MailSlotWrite($sMailSlotName, $ret,0)
      Switch @error
            Case 1
                MsgBox(48, "MailSlot demo error", "Account that you try to send to likely doesn't exist!")
                Exit
            Case 2
                MsgBox(48, "MailSlot demo error", "Message is blocked!")
            Case 3
                MsgBox(48, "MailSlot demo error", "Message is send but there is an open handle left." & @CRLF & "That could lead to possible errors in future")
            Case 4
                MsgBox(48, "MailSlot demo error", "All is fucked up!" & @CRLF & "Try debugging MailSlot.au3 functions. Thanks.")
            Case Else
    ;           MsgBox(64, "MailSlot demo", "Sucessfully sent!")
        EndSwitch

WEnd

_GDIPlus_Shutdown()


Func _GetScreenshot($iX,$iY, $iWidth, $iHeight)

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

    $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,$pParams)
    _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


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

    Local $Ret = DllCall($__g_hGDIPDll, '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


 Func _FileSend($sBuff)

    While BinaryLen($sBuff)
        $iSendReturn = TCPSend($Socket, $sBuff)
        If @error Then Return SetError(4, 0, -1)

        $sBuff = BinaryMid ($sBuff, $iSendReturn + 1, BinaryLen ($sBuff) - $iSendReturn)
     WEnd

    Return 1
EndFunc

 

Posted

MailSlot MTU is limited to 65,507 bytes on localhost, and 412 bytes (datagram - 12 bytes header) on LAN. See my Pool environment (link in sig) for more info and some examples how to transfer larger data chunks on LANs.

  • 2 weeks later...
Posted

oh i figured that one out by making use of a buffer but the sending of data is much slower compared to Mailslots :(

i tried comparing the FPS and the mailslots gave much more smoother results.

Posted

You could test UDP; should be faster than TCP because there's no triple handshake, but there's no resend upon packet-loss, so you'd have to check the file integrity at the other end yourself.

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
×
×
  • Create New...