Click to See Complete Forum and Search --> : BitBlt and 2 monitors


Kdev
June 14th, 2001, 03:21 PM
I'm not sure if this is related to BitBlt or not but I am using a library of functions that allows me to do screen capturing from my application.

My application captures the client area of its own main form. This works fine when I am running this on a system with just one video card and monitor, but this program normally runs on a system with 2 video cards and 2 monitors (on the secondary monitor). When I try to do the screen capture it comes out as just a blur of colors.

Here is the function that I use to capture the screen:
#If Win32 then
public Function CaptureWindow(byval hWndSrc as Long, _
byval Client as Boolean, byval LeftSrc as Long, _
byval TopSrc as Long, byval WidthSrc as Long, _
byval HeightSrc as Long, optional RasterOp) as Picture

Dim hDCMemory as Long
Dim hBmp as Long
Dim hBmpPrev as Long
Dim r as Long
Dim hDCSrc as Long
Dim hPal as Long
Dim hPalPrev as Long
Dim RasterCapsScrn as Long
Dim HasPaletteScrn as Long
Dim PaletteSizeScrn as Long
#ElseIf Win16 then
public Function CaptureWindow(byval hWndSrc as Integer, _
byval Client as Boolean, byval LeftSrc as Integer, _
byval TopSrc as Integer, byval WidthSrc as Long, _
byval HeightSrc as Long, optional RasterOp) as Picture

Dim hDCMemory as Integer
Dim hBmp as Integer
Dim hBmpPrev as Integer
Dim r as Integer
Dim hDCSrc as Integer
Dim hPal as Integer
Dim hPalPrev as Integer
Dim RasterCapsScrn as Integer
Dim HasPaletteScrn as Integer
Dim PaletteSizeScrn as Integer
#End If
Dim LogPal as LOGPALETTE
Dim lRasterOp as Long

If IsMissing(RasterOp) then
lRasterOp = vbSrcCopy
else
lRasterOp = RasterOp
End If

' Depending on the value of Client get the proper device context.
If Client then
hDCSrc = GetDC(hWndSrc) ' get device context for client area.
else
hDCSrc = GetWindowDC(hWndSrc) ' get device context for entire
' window.
End If

' Create a memory device context for the copy process.
hDCMemory = CreateCompatibleDC(hDCSrc)
' Create a bitmap and place it in the memory DC.
hBmp = CreateCompatibleBitmap(hDCSrc, WidthSrc, HeightSrc)
hBmpPrev = SelectObject(hDCMemory, hBmp)

' get screen properties.
RasterCapsScrn = GetDeviceCaps(hDCSrc, RASTERCAPS) ' Raster
' capabilities.
HasPaletteScrn = RasterCapsScrn And RC_PALETTE ' Palette
' support.
PaletteSizeScrn = GetDeviceCaps(hDCSrc, SIZEPALETTE) ' Size of
' palette.

' If the screen has a palette make a copy and realize it.
If HasPaletteScrn And (PaletteSizeScrn = 256) then
' Create a copy of the system palette.
LogPal.palVersion = &H300
LogPal.palNumEntries = 256
r = GetSystemPaletteEntries(hDCSrc, 0, 256, _
LogPal.palPalEntry(0))
hPal = CreatePalette(LogPal)
' Select the new palette into the memory DC and realize it.
hPalPrev = SelectPalette(hDCMemory, hPal, 0)
r = RealizePalette(hDCMemory)
End If

' Copy the on-screen image into the memory DC.
r = BitBlt(hDCMemory, 0, 0, WidthSrc, HeightSrc, hDCSrc, _
LeftSrc, TopSrc, lRasterOp)

' Remove the new copy of the on-screen image.
hBmp = SelectObject(hDCMemory, hBmpPrev)

' If the screen has a palette get back the palette that was
' selected in previously.
If HasPaletteScrn And (PaletteSizeScrn = 256) then
hPal = SelectPalette(hDCMemory, hPalPrev, 0)
End If

' Release the device context resources back to the system.
r = DeleteDC(hDCMemory)
r = ReleaseDC(hWndSrc, hDCSrc)

' Call CreateBitmapPicture to create a picture object from the
' bitmap and palette handles. then return the resulting picture
' object.
set CaptureWindow = CreateBitmapPicture(hBmp, hPal)
End Function


I call this function in this manner:
set frmMain.pictScreen.Picture = CaptureWindow(frmMain.hWnd, true, _
(frmMain.Left + 45) / Screen.TwipsPerPixelX, (frmMain.Top + 25) / Screen.TwipsPerPixelY, _
(frmMain.Width - 130) / Screen.TwipsPerPixelX, (frmMain.Height - 300) / Screen.TwipsPerPixelY)


I cannot figure out why this works with one video card but not 2. Please help.

-K

Cimperiali
June 15th, 2001, 05:45 AM
Do not know if this may help but:
#If Win32 then
should be resolved at compiling time. That means: value is decided when building exe (or compiling from ide). So, if you compile and then switch monitor, you should try to get the wrong one. If this is true, if you first switch monitor then compile, it should work for that monitor. If you build it on the Pc with 1 card only and then install it and run on the other, it should work only for a card compatible with your...
Let me know if theory matches practice.

Special thanks to Lothar "the Great" Haensler, Tom Archer, Chris Eastwood, Bruno Paris and all the other wonderful people who made and make Codeguru a great place. Come back soon, you Gurus.

Kdev
June 15th, 2001, 03:16 PM
I believe that you are right in what you say Cesare however I found out that in this case that was not the problem. I still am not sure how to force this function to read the write video memory (if that is indeed how it captures the video) but for a work around I set my screen capture function to move the form to the other monitor, capture the screen, then move back to where it was and this works fine. By the way I tested this on my own system under the VB IDE and this worked but the previous way still did not work.

-K

Cimperiali
June 18th, 2001, 02:03 AM
>>a work around I set my screen capture
function to move the form to the other monitor, capture the screen,
then move back to where it was and this works fine...

How did you manage to move your app to the other monitor and then to come back?

Special thanks to Lothar "the Great" Haensler, Tom Archer, Chris Eastwood, Bruno Paris and all the other wonderful people who made and make Codeguru a great place. Come back soon, you Gurus.

Kdev
June 18th, 2001, 10:29 AM
Grin, you want me to give you all my secrets? Well that is what I love to do--Open Source all the way!

'First move the form to the primary display
If lLeft <> 0 Or lTop <> 0 then
frmMain.WindowState = vbNormal 'Must not be minimized or maximized when moving
frmMain.Hide

frmMain.ScaleLeft = 0 'Primary display is
frmMain.ScaleTop = 0 'always 0,0

frmMain.Left = Screen.TwipsPerPixelX * frmMain.ScaleLeft
frmMain.Top = Screen.TwipsPerPixelY * frmMain.ScaleTop

frmMain.Show
frmMain.WindowState = vbMaximized
DoEvents
End If

'Here I capture the screen

'then move the form back to the 2nd display
If lLeft <> 0 Or lTop <> 0 then
frmMain.WindowState = vbNormal
frmMain.Hide

frmMain.ScaleLeft = lLeft
frmMain.ScaleTop = lTop

frmMain.Left = Screen.TwipsPerPixelX * frmMain.ScaleLeft
frmMain.Top = Screen.TwipsPerPixelY * frmMain.ScaleTop

frmMain.Show
frmMain.WindowState = vbMaximized
End If



Here lLeft and lTop are the left and top coordinates of the form at startup. These are global variables that I set using a class file that I found on M$ to bring back the top and left coordinates of all the displays set up. I only wrote this to use 2 monitors so the first display that does not have coordinates of 0,0 (primary display) it will use for the 2nd monitor.

-K