URGENT, tricky question (BitBlt experts especially)

  • Thread starter Thread starter VB Programmer
  • Start date Start date
V

VB Programmer

I am using the BitBlt operation to capture various controls into jpegs.
It's almost like a screen capture, but of just the control. (This is a
VB.NET application.)

Because of BitBlt limitations I know that the application has to always be
on top.

The problem: I am running this application on a Windows Server 2003 PC. The
server is in another state (North Carolina). I am in Florida. I access the
server over Termincal Server /Remote Desktop. When I disconnect my Remote
Desktop (with the application still running) ALL THE GENERATED IMAGES ARE
BLACK! If I reconnect with Remote Desktop it works PERFECTLY. In other
words it's like using my remote display to draw the jpegs!

1. Any ideas how to overcome this tricky problem?
2. Any alternatives to BitBlt? (I have an ActiveX gauge control (like a
speedometer) and need to capture just the control to a jpeg image.)

Thanks.
 
Here's the portion dealing with that...

Public Declare Function BitBlt Lib "gdi32" ( _
ByVal hDestDC As IntPtr, _
ByVal x As Integer, _
ByVal y As Integer, _
ByVal nWidth As Integer, _
ByVal nHeight As Integer, _
ByVal hSrcDC As IntPtr, _
ByVal xSrc As Integer, _
ByVal ySrc As Integer, _
ByVal dwRop As Integer _
) As Integer

Private Sub CaptureGauge(ByVal strFileName As String, ByVal IsKnob As
Boolean)
Try
Dim MyBitmap As Bitmap
Dim MyForm As frmMain

If IsKnob Then
MyBitmap = CaptureControl(MyFrmMain.panKnob)
Else
MyBitmap = CaptureControl(MyFrmMain.panSlider)
End If
MyBitmap.Save(strFileName, Imaging.ImageFormat.Jpeg)

Catch ex As Exception
HandleError(ex, "CaptureGauge")
End Try
End Sub

Public Function CaptureControl(ByVal c As Control) As Bitmap
Dim bmp As Bitmap
Dim gDest, gSource As Graphics
Dim hdcSource, hdcDest As IntPtr
Const SRCCOPY As Integer = &HCC0020
bmp = New Bitmap(c.Width, c.Height)

gSource = c.CreateGraphics
Try
gDest = Graphics.FromImage(bmp)
Try
hdcSource = gSource.GetHdc
Try
hdcDest = gDest.GetHdc
Try
BitBlt( _
hdcDest, 0, 0, _
c.Width, c.Height, _
hdcSource, 0, 0, SRCCOPY _
)
Finally
gDest.ReleaseHdc(hdcDest)
End Try
Finally
gSource.ReleaseHdc(hdcSource)
End Try
Finally
gDest.Dispose()
End Try
Finally
gSource.Dispose()
End Try
Return bmp
End Function
 
Hi,

Are you getting an error ?

Declare Function GetLastError Lib "kernel32" Alias "GetLastError" () As
Integer

Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA"
_

(ByVal dwFlags As Integer, ByRef lpSource As Object, ByVal dwMessageId As
Integer, _

ByVal dwLanguageId As Integer, ByVal lpBuffer As String, ByVal nSize As
Integer, _

ByRef Arguments As Integer) As Integer

Private Const FORMAT_MESSAGE_FROM_SYSTEM As Short = &H1000S

Private Const LANG_NEUTRAL As Short = &H0S



Dim intReturn As Integer

intReturn = BitBlt( _

hdcDest, 0, 0, w, h, hdcSrc, 0, 0, SRCCOPY)

If intReturn = 0 Then

Dim Buffer As String = Space(255)

FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError, _

LANG_NEUTRAL, Buffer, 255, 0)

MessageBox.Show(Buffer)

End If



Ken
 
Hi,

Are you getting an error ?

Declare Function GetLastError Lib "kernel32" Alias "GetLastError" () As
Integer

Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA"
_

(ByVal dwFlags As Integer, ByRef lpSource As Object, ByVal dwMessageId As
Integer, _

ByVal dwLanguageId As Integer, ByVal lpBuffer As String, ByVal nSize As
Integer, _

ByRef Arguments As Integer) As Integer

Private Const FORMAT_MESSAGE_FROM_SYSTEM As Short = &H1000S

Private Const LANG_NEUTRAL As Short = &H0S



Dim intReturn As Integer

intReturn = BitBlt( _

hdcDest, 0, 0, w, h, hdcSrc, 0, 0, SRCCOPY)

If intReturn = 0 Then

Dim Buffer As String = Space(255)

FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError, _

LANG_NEUTRAL, Buffer, 255, 0)

MessageBox.Show(Buffer)

End If



Ken

Ken,

Using GetLastError in VB.NET is not a good idea - for the same reasons
as in VB.CLASSIC. The runtime makes API calls and the value you get
from GetLastError may not be correct...

To get API error returns you should use Marshal.GetLastWin32Error().
And the calls to format message are not needed either. Just create an
instance of System.ComponentModel.Win32Exception and then look at the
..Message property...

' BitBlt code...
If intRetun = 0 Then
Dim ex As New Win32Exception(Marshal.GetLastWin32Error())
MessageBox.Show(ex.Message)
End If

--
Tom Shelton [MVP]
Powered By Gentoo Linux 1.4
Of all men's miseries, the bitterest is this:
to know so much and have control over nothing.
-- Herodotus
 
Ken Tucker said:
Are you getting an error ?

Untested: I think we could reproduce the problem by pressing Win+L and
having the app make a snapshot meanwhile...
 
Hi,

Much better method.

Ken
------------------
Tom Shelton said:
Ken,

Using GetLastError in VB.NET is not a good idea - for the same reasons
as in VB.CLASSIC. The runtime makes API calls and the value you get
from GetLastError may not be correct...

To get API error returns you should use Marshal.GetLastWin32Error().
And the calls to format message are not needed either. Just create an
instance of System.ComponentModel.Win32Exception and then look at the
.Message property...

' BitBlt code...
If intRetun = 0 Then
Dim ex As New Win32Exception(Marshal.GetLastWin32Error())
MessageBox.Show(ex.Message)
End If

--
Tom Shelton [MVP]
Powered By Gentoo Linux 1.4
Of all men's miseries, the bitterest is this:
to know so much and have control over nothing.
-- Herodotus
 
Thanks everyone I will try it today.

Armin Zingler said:
Untested: I think we could reproduce the problem by pressing Win+L and
having the app make a snapshot meanwhile...
 
Back
Top