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.
Getting False response from Windows System API after a while
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);
}
}
}
}
2 answers
Sort by: Most helpful
-
-
Castorix31 83,206 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);