-
Oct 20th, 2017, 03:50 PM
#1
Thread Starter
Fanatic Member
[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.
-
Oct 20th, 2017, 04:06 PM
#2
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.
-
Oct 20th, 2017, 04:49 PM
#3
Thread Starter
Fanatic Member
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).
-
Oct 20th, 2017, 04:56 PM
#4
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.
-
Oct 20th, 2017, 05:54 PM
#5
Thread Starter
Fanatic Member
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
-
Oct 21st, 2017, 04:57 AM
#6
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
-
Oct 21st, 2017, 06:33 AM
#7
Thread Starter
Fanatic Member
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.
-
Oct 21st, 2017, 07:35 AM
#8
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.
-
Oct 21st, 2017, 09:45 AM
#9
Thread Starter
Fanatic Member
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.
-
Oct 21st, 2017, 09:50 AM
#10
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
-
Nov 2nd, 2017, 09:36 PM
#11
Thread Starter
Fanatic Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|