我正在尝试使用 SetWindowLong 覆盖 winmobile 任务栏的窗口过程(以便捕获和阻止按下的按钮)。我创建了一个类,其中包含一种用于重写的方法和一种用于恢复窗口过程的方法。 MessageReceived 方法是我用来替换任务栏窗口过程的方法。我的课程如下所示:
class ButtonBlocker
{
public delegate IntPtr WindowProc(IntPtr hwnd, uint uMsg, IntPtr wParam, IntPtr lParam);
public static WindowProc newWindowDeleg;
private static IntPtr oldWindowProc;
[DllImport("coredll.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("coredll.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("coredll.dll")]
static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("coredll.dll", EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
private static IntPtr MessageReceived(IntPtr hwnd, uint uMsg, IntPtr wParam, IntPtr lParam)
{
Debug.WriteLine("Message received");
return CallWindowProc(oldWindowProc, hwnd, uMsg, wParam, lParam);
}
public static void OverrideWindowProc()
{
newWindowDeleg = MessageReceived;
IntPtr taskBarHandle = FindWindow("HHTaskBar", null);
int newWndProc = Marshal.GetFunctionPointerForDelegate(newWindowDeleg).ToInt32();
int result = SetWindowLong(taskBarHandle, -4, newWndProc);
oldWindowProc = (IntPtr)result;
if (result == 0)
{
MessageBox.Show("Failed to SetWindowLong");
}
}
public static void RestoreWindowProc()
{
IntPtr taskBarHandle = FindWindow("HHTaskBar", null);
int result = SetWindowLong(taskBarHandle, -4, oldWindowProc.ToInt32());
}
}
移动模拟器中的行为如下 - 在按下按钮后,“已收到消息”显示在调试输出中,但程序崩溃并主动向 Microsoft 发送崩溃报告。 Visual Studio 调试器挂起并且不对停止命令做出反应。仅在模拟器重置后它才会解冻。
问题似乎出在 MessageReceived 方法末尾的 CallWindowProc 上。最有可能的是,旧的 windowproc 地址存在一些问题。
如果我尝试在 OverrideWindowProc 代码之后立即执行 RestoreWindowProc 代码(我的函数没有拦截任何消息),应用程序会正常退出并且调试器不会冻结。
任何有关如何使其发挥作用的想法将不胜感激。
我使用的是 Visual Studio 2008 SP1。该项目面向.NET Framework v3.5、Windows Mobile 6 Professional。