Results 1 to 11 of 11

Thread: [RESOLVED] BitBlt to DC at Other Than (0,0)

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    857

    Resolved [RESOLVED] BitBlt to DC at Other Than (0,0)

    What I'm hoping to do is just capture an area out of a picturebox and move it to another picturebox, BUT keep all graphics in the other picturebox except where the capture area is placed.

    (see code)
    -------------------------------------
    I have a drawing on the right of the Picturebox.

    I use CreateCompatibleDC and CreateCompatibleBitmap and then capture JUST that image Not the entire client area. That works fine.

    I now want to BitBlt that image to a different picturebox in the same area. However changing the BitBlt destination top and left locations does not seem to work. I always end up at (0,0)
    in the other picturebox
    .
    NOTE: The following code has BitBlt 0, 0 hardcoded for now.
    Code:
    Public Function GetScreenSnapshot(srcHwnd As Long, destDC As Long, rcWindow As RECT) As IPictureDisp
    '1)  Capture a Rectanglar  Screen Area
    '2)  Place it in a Memory Device Context
    '3)  Copy it From the Memory Device Context to the Destination Device Context
    
    'NOTES:
    'IPictureDisp is a COM/OLE Interface.
    'StdPicture object Is VB 's implementation of that interface.
    
        #If kDEBUGON Then
            Debug.Print "Begin GetScreenSnapshot"
        #End If
        
        On Error GoTo Error_GetScreenSnapshot
        
        '--------------
          
        Dim srcDC As Long
        Dim memDC As Long
        Dim tempPict As Long
        Dim oldPict As Long
        Dim wndWidth As Long
        Dim wndHeight As Long
    
        'Objects
        Dim Pic As PictDesc
        Dim rcWindow As RECT
        Dim Guid(3) As Long
        
    
        '************
        'STARTUP
        '************
         
        '***********
        'Main
        '***********
        'Get either the Desktop Window or Orther Window based on srcHwnd Parameter
         'If srcHwnd = 0 Then srcHwnd = GetDesktopWindow
        GetWindowRect srcHwnd, rcWindow
    
         ' get window's size
         wndWidth = rcWindow.right - rcWindow.left
         wndHeight = rcWindow.bottom - rcWindow.top
     
         ' get Source window's device context from hwnd
         srcDC = GetWindowDC(srcHwnd)
         
         ' create a memDC compatabile to srcDC
         memDC = CreateCompatibleDC(srcDC)
        
         ' create (assign) a Bitmap to the memDC
         ' the size of the srcDC  we're capturing
         tempPict = CreateCompatibleBitmap(srcDC, wndWidth, wndHeight)
         oldPict = SelectObject(memDC, tempPict)
        
         ' copy the screen image (bitmap) in the srcDC into the memDC Bitmap (element)
         BitBlt memDC, 0, 0, wndWidth, wndHeight, srcDC, 0, 0, vbSrcCopy
         
        'Copy the BitMap in the memDC to the other Picturebox (destDC)
    
    '==============
    '>>> PROBLEM HERE as always end up at top/left
    '==============
    
        BitBlt destDC, 0, 0, wndWidth, wndHeight, memDC, 0, 0, vbSrcCopy
     
         ' set the old DC image and release the DC
         tempPict = SelectObject(memDC, oldPict)
         DeleteDC memDC
         ReleaseDC GetDesktopWindow, srcDC
    
         ' fill the ScreenPic structure
         With Pic
             .cbSize = Len(Pic)      'Length this structure
             .pictType = vbPicTypeBitmap   'was = 1              ' Type of picture (bitmap)
             .hIcon = tempPict       ' handle to bitmpa
             .hPal = 0                   ' handle to pallette (may be null)  - you can omit this of course
         End With
    
         ' convert the image to a IpictureDisp object
         ' this is the IPicture GUID {7BF80980-BF32-101A-8BBB-00AA00300CAB}
         ' we use an array of Long to initialize it faster
         Guid(0) = &H7BF80980
         Guid(1) = &H101ABF32
         Guid(2) = &HAA00BB8B
         Guid(3) = &HAB0C3000
    
         ' create the picture,
         ' return an object reference right into the function result
         OleCreatePictureIndirect Pic, Guid(0), True, GetScreenSnapshot
         
        '***********
        'WRAPUP
        '***********
        #If kDEBUGON Then
            Debug.Print "End GetScreenSnapshot"
        #End If
        
        Exit Function
        
    Error_GetScreenSnapshot:
        
    End Function
    Last edited by vb6forever; Oct 20th, 2017 at 03:55 PM.

  2. #2
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: BitBlt to DC at Other Than (0,0)

    The 2d & 3d parameters of BitBlt are the destination X,Y coordinates. You have them as 0,0. Change them to where you want to draw to.

    P.S. You don't need all that code. This will do it nicely, since you are talking about 2 pictureboxes. Air-code follows:
    Code:
    PicDest.PaintPicture PicSrc.Image, destX, destY, destWidth, destHeight, srcX, srcY, destWidth, destHeight
    The above replaces nearly all your code. The coordinates are in the PicDest scalemode. If PicDest.AutoRedraw=True, then PicDest.Refresh

    Edited: If using the source .Image property, source .AutoRedraw should be True

    Quick sample. Place 2 pictureboxes on a form and paste this code. The 2d PaintPicture statement is similar to your entire routine above.
    Code:
    Private Sub Form_Load()
        With Picture1
            .Move 0, 0
            .AutoRedraw = True
            .BackColor = vbWhite
            Picture1.Line (0, .ScaleHeight \ 4)-(.ScaleWidth, .ScaleHeight * 0.75), vbBlue, BF
            .PaintPicture Me.Icon, .ScaleWidth \ 4, .ScaleHeight \ 8
            Picture2.Move 0, .Top + .Height, .Width, .Height
        End With
        
        Me.Show
        DoEvents
        With Picture2
            .PaintPicture Picture1.Image, .ScaleWidth \ 3, 0, _
                                          .ScaleWidth \ 3, .ScaleHeight, _
                                          .ScaleWidth \ 3, 0, _
                                          .ScaleWidth \ 3, .ScaleHeight
        End With
    End Sub
    Last edited by LaVolpe; Oct 20th, 2017 at 04:48 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  3. #3

    Thread Starter
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    857

    Re: BitBlt to DC at Other Than (0,0)

    La Volpe:
    Thanks for responding.

    ------
    1
    ------
    The 2d & 3d parameters of BitBlt are the destination X,Y coordinates. You have them as 0,0. Change them to where you want to draw to.
    I indicated this in my initial post guess you missed it.

    ------
    2
    ------
    I guess my explanation was NOT as good as it should be.

    Lets say I have a line drawn in the "lower" right quadrant of picturebox1.
    I now want to capture just this line (which the posted routine will do).
    I then want to place this line in the "upper" right quadrant of picturebox2 --BUT--
    without overwriting the other graphics in picturebox2 except where the rectangle
    the encompasses (bounds) the line will be placed.
    I would prefer API or VB for this.

    As stated even changing the 2nd, 3rd parameters of BitBlt to other than 0,0 the
    rectangle always ends up being pegged to Picturebox2 top/left corner (0,0).

  4. #4
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: BitBlt to DC at Other Than (0,0)

    I indicated this in my initial post guess you missed it.
    Didn't miss it. It's not what your posted code reflects, shown here:
    Code:
    '==============
    '>>> PROBLEM HERE as always end up at top/left
    '==============
    
        BitBlt destDC, 0, 0, wndWidth, wndHeight, memDC, 0, 0, vbSrcCopy
    Edited: I may still be a bit confused.
    Last edited by LaVolpe; Oct 20th, 2017 at 06:48 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  5. #5

    Thread Starter
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    857

    Re: BitBlt to DC at Other Than (0,0)

    La Volpe:

    Let me try a different way to make sure I understand what's going on behind the scene.
    My understanding.

    1) A device context is just a structure that defines "at least" the picturebox client area, in this case.
    2) The device context structure has as one of its elements a place to hold a pointer (I assume) to a bitmap.
    3) WHen one uses CreateCompatibleDC, one is in effect making a copy of the original Picturebox structure (DC).
    4) WHen one uses CreateCompatibleBitmap, one is in effect setting aside another area of memory equal to the same size as that area pointed to by the bitmap element in the original DC. I also assume here a pointer
    is also created and placed in the CompatibleDC element that points to this memory area.
    5) When one BitBlts, the memory representing the defined rectangle area in the original DC is copied to the
    memory location pointed to by the bitmap element in the Compatible DC.

    So if the Compatible Bitmap Memory contains all "0s", does the rectangle values copied:
    1) Always get placed at (0,0) since it is a compatible (memory) bitmap?
    2) Get offset to some other location in memory which is defined by the 2nd, 3rd parameters
    of BitBlt
    3) something else

  6. #6
    Fanatic Member Spooman's Avatar
    Join Date
    Mar 2017
    Posts
    868

    Re: BitBlt to DC at Other Than (0,0)

    VB

    It might help if you could post a screenshot.

    Regarding
    Code:
    '==============
    '>>> PROBLEM HERE as always end up at top/left
    '==============
    
        BitBlt destDC, 0, 0, wndWidth, wndHeight, memDC, 0, 0, vbSrcCopy
    .. is destDC PB2 and memDC PB1?
    I didn't notive any PB references

    Spoo

  7. #7

    Thread Starter
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    857

    Re: BitBlt to DC at Other Than (0,0)

    Spooman: Tough to post a picture to show issue if can't get it to work.

    Tonight I thought of two other ways to describe it.

    ----
    Example 1
    ----

    Picturebox1 has two circles drawn in it. One somewhere in the left half, the other somewhere in the right half.
    Picturebox2 has a line drawn in it, somewhere in the right half.
    I now want to copy (bitblt) the line from Picturebox2 to Picturebox1 at the same or a different location into Picturebox1.

    -----------
    Example 2
    -----------
    When doing thumbnails one normally uses a picturebox control array to place them on a form.
    I want to copy (bitblt) a selected number of drawings (line, circle, etc) that reside in Picturebox2 into Picturebox1 but at a different location then they reside in Picturebox2.

    Hope that is a little bit clearer.
    Last edited by vb6forever; Oct 21st, 2017 at 06:38 AM.

  8. #8
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: BitBlt to DC at Other Than (0,0)

    Picturebox1 has two circles drawn in it. One somewhere in the left half, the other somewhere in the right half.
    Picturebox2 has a line drawn in it, somewhere in the right half.
    I now want to copy (bitblt) the line from Picturebox2 to Picturebox1 at the same or a different location into Picturebox1.
    Let's say the 1st DC (one with circles is 100x100) and contains a bitmap with 2 circles, each 50x50.
    Now the 2nd DC (one with horizontal line is also 100x100) an contains a line starting at position 20x20 and draws to 20x70
    We'll draw a 50x50 section of the 2nd DC to the 1st DC, right half of it:
    Code:
    BitBlt hDC1, 50, 0, 50, 50, hDC2, 20, 0, vbSrcCopy
    If wanting to draw it to the same position as source, we simply change the destination coordinates
    Code:
    BitBlt hDC1, 20, 0, 50, 50, hDC2, 20, 0, vbSrcCopy
    Now as I stated in previous reply.. Your code is drawing to destDC at 0,0. You need to change that if you want the drawing to occur at a different position. There is no way that changing 0,0 to some other value will result in the BitBlt occurring at 0,0. If you still believe that, then you are not looking at the result of that BitBlt call. In other words, you are not looking at destDC, rather you are looking at some other image, like maybe the picture object returned by your function?

    Question: What are you doing with the picture object returned from your function?

    The picture object contains the screen capture of the passed hWnd. DestDC contains the screen capture drawn to whatever coordinates you supply to BitBlt.

    Edited: You are not releasing a DC and should. Per MSDN, regarding GetWindowDC
    After painting is complete, the ReleaseDC function must be called to release the device context. Not releasing the window device context has serious effects on painting requested by applications.
    I think the code you are using may have attempted that with this line
    Code:
    ReleaseDC GetDesktopWindow, srcDC
    But your code called this: srcDC = GetWindowDC(srcHwnd)
    not this: srcDC = GetWindowDC(GetDesktopWindow)
    If srcHwnd was passed as a result of GetDesktopWindow API, then all is ok, but the routine is still written incorrectly because I doubt srcHwnd will always be the desktop
    Last edited by LaVolpe; Oct 21st, 2017 at 09:11 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  9. #9

    Thread Starter
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    857

    Re: BitBlt to DC at Other Than (0,0)

    LaVolpe:
    At least I know it is supposed to work as you describe.
    Will Nth check again my code including the release.


    RE the Release:
    The object is to return "either" the Desktop -- OR -- Window hWnd
    'This does that

    Code:
        'Get either the Desktop Window or Orther Window based on srcHwnd Parameter
        If srcHwnd = 0 Then srcHwnd = GetDesktopWindow
        GetWindowRect srcHwnd, rcWindow
     
         ' get Source window's device context from hwnd
         srcDC = GetWindowDC(srcHwnd)
    For Release I can create an "if condition", to again check the srcHwnd, but so far no problem releasing Window to Desktop.

  10. #10
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: BitBlt to DC at Other Than (0,0)

    srcHwnd is passed as a parameter and srcDC is relative to srcHwnd. To fix any potential problems...
    Replace: ReleaseDC GetDesktopWindow, srcDC
    With: ReleaseDC srcHwnd, srcDC

    If you are doing this....
    Code:
    ' sample
    Set Picture2.Picture = GetScreenSnapshot(GetDesktopWindow, Picture2.hDC, wRECT)
    Then that would explain what you are seeing.
    1. GetScreenSnapshot is doing what you expect, drawing to an offset on Picture2.hDC
    2. But you then cover-up what was drawn by setting the picture property which is the screenshot at 0,0
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  11. #11

    Thread Starter
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    857

    Re: BitBlt to DC at Other Than (0,0)

    Final on this was I decided to create a memory buffer and flip it (a small double buffer).
    Where a little confusion for me came initially, is that CreateCompatibleDC and CreateCompatibleBitMap are just duplicating the Original Structure element information.
    If a smaller / larger rectangle is selected its size dictates, not the Original element size.

    Code:
    Public Function ScreenToMemory(srcHwnd As Long, srcRect As RECT) As Long
    '1)  Capture a Rectanglar  Screen Area and
    '2)  Place it in a Memory Device Context
    
    'Return:   memDC
    
        #If kDEBUGON Then
            Debug.Print "Begin ScreenToMemory"
        #End If
        
        On Error GoTo Error_ScreenToMemory
        
        '--------------
          
        Dim srcDC As Long
        Dim memDC As Long
        Dim tempPict As Long
        Dim oldPict As Long
        Dim srcRectWidth As Long
        Dim srcRectHeight As Long
    
        '************
        'STARTUP
        '************
         
        '***********
        'Main
        '***********
          ' get srcRect size
         srcRectWidth = srcRect.right - srcRect.left
         srcRectHeight = srcRect.bottom - srcRect.top
     
         ' get Source window's device context from hwnd
         'seems to be CRITICAL as passing in the srcDC as a parameter
         'does NOT appear to work
         srcDC = GetWindowDC(srcHwnd)
         
         ' create a memDC compatabile to srcDC
         memDC = CreateCompatibleDC(srcDC)
     
         ' create a Bitmap the size of the srcDC  we're capturing
         tempPict = CreateCompatibleBitmap(srcDC, srcRectWidth, srcRectHeight)
         
         'Select the just created Bitmap Into the memDC
         oldPict = SelectObject(memDC, tempPict)
        
         ' copy the screen image (bitmap) in the srcDC into the memDC Bitmap (element)
         BitBlt memDC, 0, 0, srcRectWidth, srcRectHeight, srcDC, srcRect.left, srcRect.top, vbSrcCopy
     
        '***********
        'WRAPUP
        '***********
        ScreenToMemory = memDC
        
        #If kDEBUGON Then
            Debug.Print "End ScreenToMemory"
        #End If
        
        Exit Function
        
    Error_ScreenToMemory:
        
    End Function
    
    Public Function MemoryToScreen(memDC, destRect As RECT, destDC)
    'Place the Device Context in Memory Onto the Screen
    
        #If kDEBUGON Then
            Debug.Print "Begin MemoryToScreen"
        #End If
        
        On Error GoTo Error_MemoryToScreen
        
        '--------------
        
        Dim destRectWidth As Long
        Dim destRectHeight As Long
        
    
        '************
        'STARTUP
        '************
         
        '***********
        'MAIN
        '***********
         'Copy the BitMap in the memDC to the other Picturebox (destDC)
         destRectWidth = destRect.right - destRect.left
         destRectHeight = destRect.bottom - destRect.top
        
        BitBlt destDC, destRect.left, destRect.top, destRectWidth, destRectHeight, memDC, 0, 0, vbSrcCopy
       
         '************
        'WRAPUP
        '************
       
       #If kDEBUGON Then
            Debug.Print "End MemoryToScreen"
        #End If
        
        Exit Function
        
    Error_MemoryToScreen:
        
     
    End Function
    
    Public Sub CleanUp_DC(hdc As Long)
    'Delete Any DC when finished with it.
    
         ' set the old DC (bitmap) image and release the DC
         'Since destroying the DC also destroys the BitMap
         'no need to Select the oldPict
     '     tempPict = SelectObject(memDC, oldPict)
    
    
         Call DeleteDC(hdc)
    
    End Sub
    Last edited by vb6forever; Nov 2nd, 2017 at 09:42 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width