我在表单上使用了许多第三方ActiveX控件。我的应用程序有多种形式,并说这些ActiveX控件在myAxHostingForm
上。将鼠标移动到某些控件上可以获得myAxHostingForm
焦点。我想阻止它。
我尝试过一个空的事件处理程序
For Each c In Me.ChildControls(Of AxHost)() ' custom extension method returning controls of type provided
AddHandler c.MouseMove,
Sub(s As Object, m As MouseEventArgs)
End Sub
Next
我得到以下异常:
System.NotSupportedException was caught
HResult=-2146233067
Message=Event MouseMove is not valid on this ActiveX control.
Source=System.Windows.Forms
StackTrace:
at System.Windows.Forms.AxHost.add_MouseMove(MouseEventHandler value)
at <my source code file>
我希望有人知道.NET中的ActiveX托管,可以帮助理解这个错误,并可能解决这个恼人的问题。
编辑: 尝试@Hans方法,
<ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000114-0000-0000-C000-000000000046")>
Interface IOleWindow
<PreserveSig>
Function GetWindow(ByRef hwnd As IntPtr) As Int32
Sub ContextSensitiveHelp(ByVal fEnterMode As Int32)
End Interface
Class ActiveXWindow
Inherits NativeWindow
Protected Overrides Sub WndProc(ByRef m As Message)
System.Diagnostics.Debug.WriteLine(m)
If (m.Msg = &H200) Then Return
MyBase.WndProc(m)
End Sub
End Class
这是我的表单加载:
Dim itf = CType(CCDimage1.GetOcx, IOleWindow)
Dim hWnd As IntPtr
Dim hr As Integer = itf.GetWindow(hWnd)
If hr <> 0 Or hWnd = IntPtr.Zero Then Throw New Exception("Could not find handle for DataRay window")
Dim wrapper = New ActiveXWindow()
wrapper.AssignHandle(hWnd)
我在第一行得到了例外:
System.InvalidCastException was caught
HResult=-2147467262
Message=Unable to cast COM object of type 'System.__ComObject' to interface type 'Instruments.IOleWindow'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{00000114-0000-0000-C000-000000000046}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
Source=Instruments
答案 0 :(得分:3)
这是您可以尝试使用IMessageFilter的另一种方法:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += Form1_Load;
}
void Form1_Load(object sender, EventArgs e)
{
// list out your 3rd party ActiveX controls here:
Control[] controls = new Control[] {
this.axWindowsMediaPlayer1,
this.axWindowsMediaPlayer2
};
Application.AddMessageFilter(new MouseMoveFilter(controls));
}
}
public class MouseMoveFilter : IMessageFilter
{
private const int WM_MOUSEMOVE = 0x200;
private List<IntPtr> ControlHandles = new List<IntPtr>();
public MouseMoveFilter(Control[] controls)
{
foreach(Control ctl in controls)
{
this.ControlHandles.Add(ctl.Handle);
}
}
public bool PreFilterMessage(ref Message m)
{
switch (m.Msg)
{
case WM_MOUSEMOVE:
if (this.ControlHandles.Contains(m.HWnd))
{
return true;
}
break;
}
return false;
}
}
答案 1 :(得分:1)
是的,那不起作用。 ActiveX控件创建自己的窗口,并可以在他们认为合适的时候聚会。与你自己的应用程序混淆,它是一个非常好的恶意软件注入矢量。他们应该玩得很好并与主人一起工作,但角落经常被削减。
你唯一能做的就是对他们的窗口进行子类化,这样你就可以先得到他们的消息。首先需要获取它们的窗口句柄,这需要使用IOleWindow :: GetWindow()方法。你需要这个声明:
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000114-0000-0000-C000-000000000046")]
interface IOleWindow {
[PreserveSig]
int GetWindow(out IntPtr hwnd);
void ContextSensitiveHelp(int fEnterMode);
}
然后你需要从NativeWindow派生自己的类,这样你就可以覆盖WndProc()方法并检测消息。一个简单的过滤WM_MOUSEMOVE:
class ActiveXWindow : NativeWindow {
protected override void WndProc(ref Message m) {
System.Diagnostics.Debug.WriteLine(m);
if (m.Msg == 0x200) return;
base.WndProc(ref m);
}
}
然后你需要把它放到位。您必须等到创建本机窗口,表单的Load事件通常是正确的时间。我使用Windows Media Player来测试代码:
private void Form1_Load(object sender, EventArgs e) {
var itf = (IOleWindow)axWindowsMediaPlayer1.GetOcx();
IntPtr hWnd;
int hr = itf.GetWindow(out hWnd);
if (hr != 0 || hWnd == IntPtr.Zero) throw new Exception("Oh, no");
var wrapper = new ActiveXWindow();
wrapper.AssignHandle(hWnd);
}
答案 2 :(得分:1)
本机窗口上的ActiveX控件具有与Form_Load中看到的句柄不同的句柄。所以我无法明确地忽略它们上的鼠标移动。但是,它们是我想在我的应用程序中忽略鼠标移动的唯一控件,它们都具有Control.FromHandle(m.HWnd) Is Nothing = true
的特征。感谢@Idle_Mind引导我采用这种方法。
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Application.AddMessageFilter(New MouseMoveFilter())
End Sub
...
Public Class MouseMoveFilter
Implements IMessageFilter
Private Const WM_MOUSEMOVE As Int32 = &H200
Public Function PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage
Select Case m.Msg
Case WM_MOUSEMOVE
Return Control.FromHandle(m.HWnd) Is Nothing
End Select
Return False
End Function
End Class