代码之家  ›  专栏  ›  技术社区  ›  Yakimych

在托管代码(Compact框架)中调用setwindowlong和callwindowproc

  •  1
  • Yakimych  · 技术社区  · 15 年前

    我正在尝试使用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调试器挂起,不响应stop命令。它只有在模拟器重置后才会解冻。 问题似乎出在messageReceived方法末尾的callWindowProc。很可能,旧的windowproc地址有问题。 如果我尝试在overrideWindowProc代码之后立即执行restoreWindowProc代码(我的函数没有截获任何消息),则应用程序会正常退出,调试器不会冻结。 任何关于如何使这项工作的想法都将受到赞赏。

    我正在使用Visual Studio 2008 SP1。该项目的目标是.NET Framework v3.5、Windows Mobile 6 Professional。

    1 回复  |  直到 15 年前
        1
  •  3
  •   Hans Passant    15 年前

    不能替换由其他进程拥有的窗口的窗口过程。替换函数的地址仅在您的进程中有效。在另一个过程中,它会导致立即爆炸。为了解决这个问题,您必须向目标进程中注入一个DLL。不能插入用托管语言编写的dll,clr未初始化。