0

我们有一个适用于 Windows Mobile 5 的 kiosk 模式应用程序,至少在生产中运行了一年。它通过SetWindowLongwindows API 函数使用窗口子类化来覆盖任务栏的行为,以防止用户离开我们的应用程序或其他明确允许的应用程序。

我的回调覆盖了一些窗口消息的处理,并调用了其他消息的默认处理程序。这是通过存储由 返回的前一个函数指针SetWindowLong,并通过调用CallWindowProc它在新函数内部使用它来完成的。

然后我们不得不更新应用程序以兼容 Windows Mobile 6.5.3,并开始遇到一堆问题。我按照这篇文章禁用了 6.5 中新增的底部菜单按钮。在单个应用程序上,它工作正常,菜单尊重我的回调。一旦用户通过我们的应用程序打开另一个应用程序,该窗口似乎被重新创建,我不得不设计一种机制来检测前台窗口的变化,然后再次“重新分类”窗口。

在我的代码中,我无法控制重新创建此窗口的确切时间,因此我的第一次尝试是使用该GetWindowLong函数获取当前回调地址并针对我自己的函数地址进行测试。我学到了不能只比较这样的值的艰难方法,因为它并不总是返回函数指针

因为我无法以这种方式测试我的方法是否是当前处理程序,所以有时我最终将我的方法设置为处理程序,而前一个处理程序也是我自己的方法(在这种情况下,没有重新创建窗口,因此已经设置了我的方法)。这会导致无限循环,因为我的回调最终会无限期地调用自己。

如何知道我的自定义函数是否是某个窗口正在使用的函数,以便避免这种无限递归?

4

2 回答 2

2

不要SetWindowLong(GWL_WNDPROC)用于子类化窗口。改为使用SetWindowSubClass()(如 Raymond Chen 所说):

子类化控件

更安全的子类化

除了提供更安全的子类语义(例如一次允许多个子类)之外,它还允许您将用户定义的数据与每个子类相关联。所以你可以GetWindowSubclass()用来检查你是否已经对窗口进行了子类化。

或者,您可以简单地跟踪您是否已经对窗口进行了子类化。一个简单的布尔变量就足够了。一旦您的子类就位,您必须在窗口完全销毁之前删除子类。因此,例如,当子类收到WM_NCDESTROY消息时,您可以删除子类并同时清除布尔值,然后下次再次看到窗口时,布尔值会告诉您需要对窗口进行子类化。

于 2014-07-17T01:51:01.957 回答
1

将自定义消息发送到窗口。在您的自定义函数中处理此消息以返回一些值,该值将表明它是您的自定义处理程序..等等。

if(SendMessage(hwnd, mymsg, 0, 0) != myvalue)
    ;// It's not your handler
于 2014-07-16T22:16:26.027 回答