Функция BitBlt создает пустое растровое изображение при компиляции для x86 в приложении .NET 2.0 VB.

У меня есть функция оболочки BitBlt в моем проекте VB. Он отлично работает, когда скомпилирован как Any CPU, но когда я нацеливаю его на x86, он создает пустое растровое изображение. Я должен использовать x86, поскольку этого требуют другие части приложения. Есть идеи, что может быть не так? Вот код:

Imports System.Drawing.Imaging

''' <summary>
''' Provides the static method ControlCapture used to
''' take screenshots of the specified control.
''' </summary>
''' <remarks>This fails unless compiled targeting Any CPU!!!</remarks>
Public Class ControlCapture

    ''' <summary>
    ''' Pointer to gdi.exe win32 function.
    ''' </summary>
    ''' <param name="hDestDC">destination device context</param>
    ''' <param name="x">x coord. of output rectangle</param>
    ''' <param name="y">y coord. of output rectangle</param>
    ''' <param name="nWidth">width of source and dest. rectangle</param>
    ''' <param name="nHeight">height of source and dest. rectangle</param>
    ''' <param name="hSrcDC">source device context</param>
    ''' <param name="xSrc">x coord. of rectangle to capture</param>
    ''' <param name="ySrc">y coord. of rectangle to capture</param>
    ''' <param name="dwRop">mode (raster op)</param>
    ''' <returns>0 on failure, non-zero on success</returns>
    ''' <remarks>from http://support.microsoft.com/kb/147810 </remarks>
    Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, _
         ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, _
         ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, _
         ByVal ySrc As Long, ByVal dwRop As Long) As Long

    ''' <summary>
    ''' Grab a screen capture of the given control.
    ''' </summary>
    ''' <param name="control">control to grab</param>
    ''' <returns>Bitmap image</returns>
    ''' <remarks>used by mappoint map viewer and bing map viewer</remarks>
    Public Shared Function ControlCapture(ByVal control As Control) As Bitmap

        'capture params
        Dim width As Integer = control.Width
        Dim height As Integer = control.Height

        'output object
        Dim bitmap As Bitmap = New Bitmap(width, height, PixelFormat.Format32bppArgb)

        'get handles to source and destination objects as graphics
        Dim sourceGraphics As Graphics = control.CreateGraphics()
        Dim destGrahpics As Graphics = Drawing.Graphics.FromImage(bitmap)

        'actual handles
        Dim sourceGraphicsPointer As System.IntPtr = sourceGraphics.GetHdc()
        Dim destGraphicsPointer As System.IntPtr = destGrahpics.GetHdc()

        'get references as ints
        Dim destAddress As Integer = destGraphicsPointer
        Dim sourceAddress As Integer = sourceGraphicsPointer

        'call win32 api
        BitBlt(destAddress, 0, 0, width, height, sourceAddress, 0, 0, Codes.SourceCopy)

        'clean up
        sourceGraphics.ReleaseHdc(sourceGraphicsPointer)
        destGrahpics.ReleaseHdc(destGraphicsPointer)

        Return bitmap
    End Function

    ''' <summary>
    ''' SRCCOPY(CC0020)      Copies the source bitmap to destination bitmap.
    ''' </summary>
    ''' <remarks>From http://support.microsoft.com/kb/147810 </remarks>
    Private Enum Codes
        SourceCopy = &HCC0020
    End Enum

End Class

Спасибо, Брайан


person Brian Sweeney    schedule 04.10.2010    source источник


Ответы (1)


Это довольно классическая проблема с VB.NET, объявление pinvoke неверно. Тот, который вы используете, работает только для VB6, языка, который по историческим причинам использует Integer для 16-битного числа, Long для 32-битного числа. Это восходит к ранним версиям VB, которые работали в 16-разрядных операционных системах. VB.NET был переработан, чтобы хорошо работать в 32-битных операционных системах, его Integer — 32 бита, Long — 64 бита. Вы должны объявить аргументы как Integer. Случайно работает в 64-битном режиме.

Используйте pinvoke.net, чтобы получить правильное объявление.

И обратите внимание на Graphics.CopyFromScreen и Control.DrawToBitmap, так как они очень похожи по функциональности, но без необходимости использования pinvoke.

person Hans Passant    schedule 04.10.2010
comment
С этого момента моя стандартная рабочая процедура будет такой: 1) перейти к переполнению стека и спросить кого-нибудь, кто знает, что он делает, и 2) попытаться понять это самостоятельно. Огромное спасибо! - person Brian Sweeney; 05.10.2010
comment
Также я не могу использовать DrawToBitmap, потому что это элемент управления ActiveX, который я пытаюсь захватить. Спасибо за предложение. - person Brian Sweeney; 05.10.2010
comment
Graphics.CopyFromScreen использует BitBlt(). - person Hans Passant; 05.10.2010