1

I'm using the ScreenCapture sample of SharpDX library to be able take a screenshot of a game that is in fullscreen (because common GDI+ capture techniques here doesn't work, even the Windos default "Print" key cannot take a proper screenshot of the game).

The code that I'm using in my application is practically the same of the official sample linked above (translated to VB.NET), so I think is not necessary to publish the same code block here.

The problem I have is that I would like to include the mouse cursor in the captured image.

Maybe SharpDX has some method or property/parameter to include the mouse cursor in a friendly way?, if not then how could acchieve this taking into account that the mouse cursor of the game is personalized (not the default white Windows arrow)?.

22
  • Have you tried getting the graphics from the resulting image and calling Cursor.Draw()? Commented Jul 2, 2016 at 22:03
  • @Visual Vincent I do exactlly that when doing a common capture with a Bitmap and Graphics.CopyFromScreen(), however this seems more complicated because its a game which its native resolution is smaller than the screen resolution and it is running in fullscreen mode (so it reescales the resolution, and no way with .NET neither windows/Print-key can't capture an image of the game with the real screen size in that circunstances, only with DirectX techniques as I discovered), so its complicated for me to locate the exact mouse hotspot in that circunstances. Commented Jul 2, 2016 at 23:11
  • If SharpDX can capture an image of the screen, I suppose that it could do something itself to also capture and draw the cursor in the resulting image, avoiding calling the WinForms related namespace members to help on this. Anyways the Cursor.Draw() (or Cursors.Arrow.Draw()) will draw a default Windows cursor, but I would like to capture the cursor that I see in-game when I do the screenshot. Commented Jul 2, 2016 at 23:19
  • 1
    I understand what you mean; I prefer pure solutions too for the method/API I'm using. If you want to wait it out that's fine by me. It's just 15-25 rep we're talking about (which is about 0,65% of my total). :) Commented Jul 3, 2016 at 22:39
  • 1
    Well sadly it does not seem to be common for DirectX nor GDI to actually capture the mouse with the screenshot. So shall I write an answer including the method of P/Invoking GetCursorInfo() then? -- It's late here though, so you'll have to wait for it 'til the morning. :) Commented Jul 3, 2016 at 23:39

1 Answer 1

1

You could utilize the WinAPI's GetCursorInfo() function to get a handle to the current cursor. By then calling Icon.FromHandle() and passing the cursor handle as a parameter you'll get the cursor as a drawable icon.

As different cursors may have different hotspots you'll have to take that into account too. For this you can use the WinAPI's GetIconInfo() function to get the X and Y-coordinates for the hotspot, then you'll just have to substract the cursor's position with the hotspot's position.

The method for drawing the cursor:

Public Shared Sub DrawCursor(ByVal Graphics As Graphics)
    Dim CursorInfo As New NativeMethods.CURSORINFO With {.cbSize = Marshal.SizeOf(GetType(NativeMethods.CURSORINFO))}

    'Get the cursor info.
    If NativeMethods.GetCursorInfo(CursorInfo) = True Then
        Using CursorIcon As System.Drawing.Icon = System.Drawing.Icon.FromHandle(CursorInfo.hCursor) 'Get the cursor icon.
            Dim IconInfo As New NativeMethods.ICONINFO

            Try
                Dim ModifierPoint As New Point(0, 0) 'Declare the modifier point (the cursor's hotspot).

                'Get the info for the cursor icon.
                If NativeMethods.GetIconInfo(CursorInfo.hCursor, IconInfo) = True Then
                    If IconInfo.fIcon = False Then 'If the cursor is an icon the hotspot will always be (0, 0).
                        ModifierPoint = New Point(IconInfo.xHotspot, IconInfo.yHotspot) 'Set the hotspot modifier.
                    End If

                End If


                'Normalize the coordinates according to the hotspot.
                Dim FinalPoint As New Point(CursorInfo.ptScreenPos.x - ModifierPoint.X, CursorInfo.ptScreenPos.y - ModifierPoint.Y)

                'Draw the cursor.
                Graphics.DrawIcon(CursorIcon, New Rectangle(FinalPoint, CursorIcon.Size))

            Finally
                'Some cleaning up...
                If IconInfo.hbmMask <> IntPtr.Zero Then
                    NativeMethods.DeleteObject(IconInfo.hbmMask)
                    IconInfo.hbmMask = IntPtr.Zero
                End If

                If IconInfo.hbmColor <> IntPtr.Zero Then
                    NativeMethods.DeleteObject(IconInfo.hbmColor)
                    IconInfo.hbmColor = IntPtr.Zero
                End If

            End Try
        End Using
    End If
End Sub

NativeMethods.vb:

Imports System.Runtime.InteropServices

Public NotInheritable Class NativeMethods
    <StructLayout(LayoutKind.Sequential)> _
    Public Structure POINT
        Public x As Integer
        Public y As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure CURSORINFO
        Public cbSize As Integer
        Public flags As Integer
        Public hCursor As IntPtr
        Public ptScreenPos As POINT
    End Structure

    <DllImport("user32.dll")> _
    Public Shared Function GetCursorInfo(ByRef pci As CURSORINFO) As Boolean
    End Function

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure ICONINFO
        Public fIcon As Boolean
        Public xHotspot As Integer
        Public yHotspot As Integer
        Public hbmMask As IntPtr
        Public hbmColor As IntPtr
    End Structure

    <DllImport("user32.dll")> _
    Public Shared Function GetIconInfo(ByVal hIcon As IntPtr, ByRef piconinfo As ICONINFO) As Boolean
    End Function

    <DllImport("gdi32.dll")> _
    Public Shared Function DeleteObject(ByVal hObject As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function
End Class

If you take the resulting screenshot you'd draw the cursor onto it like this:

Using g As Graphics = Graphics.FromImage(yourImage)
    DrawCursor(g)
End Using
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.