Getting False response from Windows System API after a while

Hasib 0 Reputation points
2023-05-02T05:04:09.5266667+00:00

I am trying to get the current cursor data using C#. And I need to run the program infinitely and pass broadcast the data through a socket server. But after running the program for some time, the Windows system APIs (GetCursorInfo, GetIconInfo, CopyIcon) start to return a false/null response. And it can not recover from that state. This is not happening because of the socket server i.e. no dependency on the socket server. Once I restart the program it starts giving the correct response again. Here's my code for getting cursor data.

Edit: For a better perspective adding more code.

Cursor.cs


using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using System.Text.Json;

namespace Cursor_Windows
{
    class CursorData
    {
        public string mouse_cursor { get; set; }
        public string position { get; set; }
    }
    class Cursor
    {
    [DllImport("user32.dll", EntryPoint = "CopyIcon")]
    private static extern IntPtr CopyIcon(IntPtr hIcon);

    [DllImport("user32.dll", EntryPoint = "DestroyIcon")]
    private static extern IntPtr DestroyIcon(IntPtr hIcon);

    [DllImport("gdi32.dll", EntryPoint = "DeleteObject"))]
    private static extern IntPtr DeleteObject(IntPtr hDc);

    [DllImport("user32.dll", EntryPoint = "GetCursorInfo")]
    private static extern bool GetCursorInfo(out CURSORINFO pci);

    [DllImport("user32.dll", EntryPoint = "GetIconInfo")]
    private static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo);

    public static string getCurrentCursor()
    {
        string ret = "A";
        try
        {
            CURSORINFO pci = new CURSORINFO();
            pci.cbSize = Marshal.SizeOf(pci);
            if (GetCursorInfo(out pci))
            {
                DeleteObject(pci.hCursor);
                IntPtr hIcon = CopyIcon(pci.hCursor);
                pci.hCursor = IntPtr.Zero;
                if (hIcon != IntPtr.Zero)
                {
                    ICONINFO iconInfo;
                    /*if (!GetIconInfo(hIcon, out iconInfo))
                    {
                        *//*ret = "EMPTY4";*//*
                        goto fin;
                    }*/
                    GetIconInfo(hIcon, out iconInfo);
                    System.Drawing.Icon ic = System.Drawing.Icon.FromHandle(hIcon);
                    DeleteObject(iconInfo.hbmColor);
                    DeleteObject(iconInfo.hbmMask);
                    iconInfo.hbmColor = iconInfo.hbmMask = hIcon = IntPtr.Zero;
                    System.Drawing.Bitmap bmp = ic.ToBitmap();
                    ic.Dispose();
                    ic = null;
                    if (bmp == null)
                    {
                        ret = "B";
                        goto fin;
                    }

                    System.IO.MemoryStream ms = new MemoryStream();
                    bmp.Save(ms, ImageFormat.Png);
                    bmp.Dispose();
                    bmp = null;
                    byte[] byteImage = ms.ToArray();
                    ms.Dispose();
                    var SigBase64 = Convert.ToBase64String(byteImage) /*+ ":" + iconInfo.xHotspot + "," + iconInfo.yHotspot*/;
                    /*Console.WriteLine(SigBase64);*/
                    var cd = new CursorData
                    {
                        mouse_cursor = SigBase64,
                        position = "{" + iconInfo.xHotspot.ToString() + "," + iconInfo.yHotspot.ToString() + "}",
                    };
                    JsonSerializerOptions jso = new JsonSerializerOptions
                    {
                        Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
                    };
                    string jsonString = JsonSerializer.Serialize<CursorData>(cd, jso);
                    ret = jsonString;
                    goto fin;
                }
                else
                {
                    pci.hCursor = hIcon = IntPtr.Zero;
                    ret = "EMPTY";
                }
            }
            /*else
                Console.WriteLine("Error3: " + GetLastError());
            pci.hCursor = hIcon = IntPtr.Zero;
            ret = "EMPTY5";*/
            // return "EMPTY3";
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
        fin:  return ret;
    }
    [StructLayout(LayoutKind.Sequential)]
    private struct CURSORINFO
    {
        public Int32 cbSize; // Specifies the size, in bytes, of the structure.
        public Int32 flags; // Specifies the cursor state. This parameter can be one of the following values:
        public IntPtr hCursor; // Handle to the cursor.
        public POINT ptScreenPos; // A POINT structure that receives the screen coordinates of the cursor.
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct ICONINFO
    {
        public bool fIcon; // Specifies whether this structure defines an icon or a cursor. A value of TRUE specifies
        public Int32 xHotspot; // Specifies the x-coordinate of a cursor's hot spot. If this structure defines an icon, the hot
        public Int32 yHotspot; // Specifies the y-coordinate of the cursor's hot spot. If this structure defines an icon, the hot
        public IntPtr hbmMask; // (HBITMAP) Specifies the icon bitmask bitmap. If this structure defines a black and white icon,
        public IntPtr hbmColor; // (HBITMAP) Handle to the icon color bitmap. This member can be optional if this
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct POINT
    {
        public Int32 x;
        public Int32 y;
    }
}

SocketServer.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Cursor_Windows
{
    class SocketServer
    {
        public Socket listener;
        List<Socket> connectedSockets = new List<Socket>();
        public string currentCursor = "";
        public void initServer()
        {
            Console.WriteLine("Init Server...");
            IPHostEntry host = Dns.GetHostEntry("127.0.0.1");
            IPAddress ipAddress = host.AddressList[0];
            IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 9008);
        try
        {
            // Create a Socket that will use Tcp protocol
            Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            // A Socket must be associated with an endpoint using the Bind method
            listener.Bind(localEndPoint);
            // Specify how many requests a Socket can listen before it gives Server busy response.
            // We will listen 10 requests at a time
            listener.Listen(10);
            /*listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);*/
            this.listener = listener;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    public bool sendCurrentCursorToAllConnectedSockets()
    {
        /*listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);*/
        string newCursor = "";
        try
        {
            newCursor = Cursor.getCurrentCursor() /*"HHHHHHHHHHHHHHHHHHHHHASFASf"*/;
            if (newCursor.Contains("EMPTY")) return false;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            return false;
        }
        if (!currentCursor.Equals(newCursor))
        {
            currentCursor = newCursor;
            try
            {
                Socket handler = listener.Accept();
                /*foreach (Socket handler in connectedSockets) {*/
                handler.Send(Encoding.ASCII.GetBytes(currentCursor));
                /*}*/
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                return false;
            }
        }
        return true;
    }
}

Program.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using System.Timers;

namespace Cursor_Windows
{
    class Program
    {
        /*private static System.Timers.Timer _timer;*/
        /*private static SocketServer ss;*/
        static void Main(string[] args)
        {
            /*Console.WriteLine("MAIN-----------");*/
        /*st:*/ SocketServer ss = new SocketServer();
            ss.initServer();
            for (; ; )
            {
                ss.sendCurrentCursorToAllConnectedSockets();
                /*if (!ss.sendCurrentCursorToAllConnectedSockets())
                {
                    ss.listener.Shutdown(SocketShutdown.Receive);
                    ss.listener.Close();
                    Console.WriteLine("E");
                    Console.WriteLine("M");
                    Console.WriteLine("P");
                    Console.WriteLine("T");
                    Console.WriteLine("Y");
                    goto st;
                }*/
                Thread.Sleep(20);
            }
        }
    }
}
.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,548 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,528 questions
{count} votes

2 answers

Sort by: Most helpful
  1. KingKong-4442 166 Reputation points
    2023-05-02T08:24:38.7066667+00:00

    DeleteObject is used for deleting GDI Objects, not cursor handles. Use DestroyCursor instead. And don´t destroy the cursor before copying it, as you´re trying to do right now. Then, don´t forget to DestroyIcon when you´re done with hIcon.


  2. Castorix31 82,576 Reputation points
    2023-05-02T08:45:03.8533333+00:00

    There are a few bugs.

    Don't call DeleteObject (and in MS samples, pci.hCursor is ignored, it is just a handle of the current cursor, not a copy)

    Don't set hIcon = IntPtr.Zero but call DestroyIcon(hIcon); at end

    Some API declarations are not correct, like :

                [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
                private static extern bool DestroyIcon(IntPtr hIcon);
    
                [DllImport("Gdi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
                private static extern bool DeleteObject(IntPtr hObject);
    
                [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
                [return: MarshalAs(UnmanagedType.Bool)]
                private static extern bool GetCursorInfo(ref CURSORINFO pci);