C# 在.Net Office Interop中将系统光标设置为自定义的低级设置
我正在编写一个.NETWPF应用程序,允许其他程序对其进行写入。设计师想要实现的一个功能是在第三方程序中使用自定义光标来取代文本编辑器“I-Beam”中的光标 我一直在玩的第一个第三方程序是MS Word 2013,它使用.Net的Office互操作功能。我在程序的应用程序域中有一个全局C#DLL,它保存游标资源 Interop不允许您分配自定义游标(尽管它允许您切换游标)。所以在大量挖掘之后,我尝试了一些低级的胡闹 在Interop加载项中,我添加了以下类:C# 在.Net Office Interop中将系统光标设置为自定义的低级设置,c#,winapi,office-interop,low-level,C#,Winapi,Office Interop,Low Level,我正在编写一个.NETWPF应用程序,允许其他程序对其进行写入。设计师想要实现的一个功能是在第三方程序中使用自定义光标来取代文本编辑器“I-Beam”中的光标 我一直在玩的第一个第三方程序是MS Word 2013,它使用.Net的Office互操作功能。我在程序的应用程序域中有一个全局C#DLL,它保存游标资源 Interop不允许您分配自定义游标(尽管它允许您切换游标)。所以在大量挖掘之后,我尝试了一些低级的胡闹 在Interop加载项中,我添加了以下类: public static cla
public static class CursorHook
{
private static IntPtr programCursor = IntPtr.Zero;
private static IntPtr systemCursor = LoadCursor(IntPtr.Zero, OCR_IBEAM);
public static void Init()
{
programCursor = Marshal.AllocHGlobal(resourceCursor.marker_cursor2.Length);
Marshal.Copy(resourceCursor.marker_cursor2, 0, programCursor, resourceCursor.marker_cursor2.Length);
}
public static void Start()
{
SetSystemCursor(programCursor, OCR_IBEAM);
}
public static void Stop()
{
SetSystemCursor(systemCursor, OCR_IBEAM);
}
public static void Dispose()
{
Marshal.FreeHGlobal(programCursor);
}
private static IntPtr _hookID = IntPtr.Zero;
private const int OCR_IBEAM = 32513;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetSystemCursor(IntPtr hCursor, uint id);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadCursor(IntPtr hInstance, int id);
[DllImport("user32.dll")]
private static extern IntPtr SetCursor(IntPtr hCursor);
}
在我的外接程序类中,我执行以下操作:
public partial class ThisAddIn
{
//Stuff
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
CursorHook.Init();
CursorHook.Start();
this.Application.WindowDeactivate += new WordInterop.ApplicationEvents4_WindowDeactivateEventHandler(Deactivated);
this.Application.WindowActivate += new WordInterop.ApplicationEvents4_WindowActivateEventHandler(Activated);
//Stuff
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
CursorHook.Stop();
CursorHook.Dispose();
}
//stuff
private void Activated(WordInterop.Document Doc, WordInterop.Window Wn) { CursorHook.Start(); }
private void Deactivated(WordInterop.Document Doc, WordInterop.Window Wn) { CursorHook.Stop(); }
//stuff
}
然而,光标没有改变(即使调用了代码)。我错过了什么
顺便说一句,我知道静态类可能不是资源的最佳使用。但现在,我只是想让光标做我想做的事情,我会在完成后再做优雅的工作
提前谢谢
编辑
我已将代码修改为如下所示:
public static class CursorHook
{
private static IntPtr ptr_IBeam = IntPtr.Zero;
private static IntPtr programCursor = IntPtr.Zero;
private static IntPtr systemCursor = IntPtr.Zero;
private static Cursor ProgramCursor = null;
public static void Init()
{
using(MemoryStream ms = new MemoryStream(resourceCursor.marker_cursor2))
{
ProgramCursor = new Cursor(ms);
}
programCursor = ProgramCursor.Handle;
systemCursor = Cursors.IBeam.CopyHandle();
}
public static void Start()
{
SetSystemCursor(programCursor, UNS_OCR_IBEAM);
}
public static void Stop()
{
SetSystemCursor(systemCursor, UNS_OCR_IBEAM);
}
public static void Dispose()
{
}
private const int OCR_IBEAM = 32513;
private const uint UNS_OCR_IBEAM = OCR_IBEAM;
private static IntPtr PTR_OCR_IBEAM = new IntPtr(OCR_IBEAM);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool SetSystemCursor(IntPtr hCursor, uint id);
}
现在一切都简单多了,这主要归功于汉帕桑下面的评论。事实上,它现在也有点起作用了
然而,仍然有两个bug
1) 图标不是彩色的。我知道这是一个自定义图标的问题,有解决办法,所以我会自己研究
是什么让我陷入困境:
2) 打开Word时,图标将变为我的自定义图标,单击Word外部时,图标将变回默认图标。但之后它将拒绝更改回我的图标。每次我“激活”MS Word时,SetSystemCursor()将返回false。为什么?这是最后的代码。它可以工作,但光标不是彩色的。由于彩色光标在Windows中是一个众所周知的头痛问题,这是一个不同的问题。非常感谢汉斯·帕桑
public static class CursorHook
{
private static IntPtr programCursor = IntPtr.Zero;
private static IntPtr systemCursor = IntPtr.Zero;
private static Cursor ProgramCursor = null;
private static Cursor DefaultCursor = null;
public static void Init()
{
using(MemoryStream ms = new MemoryStream(resourceCursor.marker_cursor2))
{
ProgramCursor = new Cursor(ms);
}
DefaultCursor = new Cursor(Cursors.IBeam.CopyHandle());
}
public static void Start()
{
//as the GC has likely invalidated the IntPtr, each time you have to assign it anew
programCursor = ProgramCursor.CopyHandle();
SetSystemCursor(programCursor, UNS_OCR_IBEAM);
}
public static void Stop()
{
//as the GC has likely invalidated the IntPtr, each time you have to assign it anew
systemCursor = DefaultCursor.CopyHandle();
SetSystemCursor(systemCursor, UNS_OCR_IBEAM);
}
public static void Dispose()
{
}
private const int OCR_IBEAM = 32513;
private const uint UNS_OCR_IBEAM = OCR_IBEAM;
private static IntPtr PTR_OCR_IBEAM = new IntPtr(OCR_IBEAM);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool SetSystemCursor(IntPtr hCursor, uint id);
}
可以安全地假设目标窗口处理,根据自己认为合适的方式设置自己的光标,从而取消您更改光标形状的天真尝试。除了我正在尝试更改系统光标,以便与目标窗口的操作无关。这假设目标窗口正在使用系统光标。@IInspectable Fair point。不过,是Word女士。当我通过控制面板将系统光标更改为自定义光标时,MS Word会使用它。错误检查不是可选的。SetSystemCursor可能返回false,您永远不会知道它。LoadCursor的第二个参数是IntPtr,而不是int.Marshal.AllocHGlobal()+Copy()不正确,请改用Icon.Handle属性。