【发布时间】:2013-02-14 03:31:19
【问题描述】:
Shell 命名空间扩展相当复杂。在过去的 10 年里,我们一直在构建一个 shell 命名空间扩展;最新的版本是 MagicRAR (www.magicrar.com) 中的存档文件夹功能。
不幸的是,尽管编码非常仔细,确保线程正确访问共享内存等,我们的 shell 命名空间扩展仍然偶尔会崩溃。 Explorer 主机进程在使用我们的 shell 命名空间扩展期间或之外崩溃。
我们使用了多种工具(例如 AQTime Pro)来对我们的 shell 命名空间扩展代码进行故障排除。没有报告内存覆盖或其他类似的访问问题。这只剩下一个罪魁祸首:VCL 不是线程安全的!
确实,我们正在使用 VCL 作为 shell 命名空间扩展的一部分; Explorer 中的文件列表实际上是一个托管控件,在我们自己的 shell 命名空间扩展的情况下,它实际上是一个 VCL 窗口。我们现在甚至想知道(经过多代开发)这是否是一个允许的场景......
主应用程序对象甚至不存在于我们的外壳命名空间扩展 DLL 中。使用 TThread.Synchronize 死锁资源管理器,因为尚未在任何地方创建主 VCL 线程。我们是否需要手动创建一个主 VCL 线程(如何?) - 可能在另一个 DLL 中 - 并通过该 DLL 重新路由我们所有的 UI 创建/更新/销毁?
请记住,资源管理器可能会显示任意数量的包含我们的 VCL 窗口的窗口。根据目标系统的配置,Explorer 还可以作为多个独立进程或单个进程运行。
我们的 shell 命名空间扩展基于 John Lam 的起点(大多数 Delphi shell 命名空间开发人员都知道)。当然,正如您在最终产品中看到的那样,对这个起点进行了重大修改。 John Lam 甚至从未在他的幻灯片和示例项目中讨论过 VCL 线程不安全的问题。
在过去十年中,我们还尝试使用多个版本的 ShellPlus 组件。他们已经完成了一些出色的工作,但不幸的是,根据我们的经验,即使是基于他们的代码的非常初级的工作也提供了比我们自己的代码差得多的结果。
ShellPlus 实际上还提供了使用 Explorer 自己的预定义主机窗口的功能,而不是创建自定义 VCL 窗口;虽然这可能会回避任何 VCL 线程问题,但根据我们的经验,即使这也不是一个可行的解决方案 - 因为 ShellPlus shell 命名空间扩展始终不如我们自制的代码稳定,无论 VCL 是否窗口化。
所以首先;这个问题是一个理论上的问题 - VCL 可以在使用 Explorer 内的 VCL 窗口作为进程主机的 shell 命名空间扩展中使用吗?
如果是这样,在这种情况下如何处理VCL线程不安全的问题?
【问题讨论】:
-
您是否真正检查过您的涉及 GUI 的代码是否在每个进程中运行多个线程? Win32 有自己的线程规则。具体来说,窗口具有线程亲和性。我希望只要资源管理器希望您使用窗口句柄,您总是会在同一个线程中被调用。换句话说,我质疑线程亲和力是否真的是你的问题。
-
如果资源管理器注意线程亲和性,那就太好了,但是当多个资源管理器窗口显示多个我们的 VCL 窗口副本时会发生什么? VCL 不是线程安全的,因此仍然存在多个线程在同一进程中执行 GUI 工作的问题——而不是单个线程处理所有 GUI 工作。事实上,Explorer 创建了多个调用 shell 命名空间扩展的线程。
-
好的,到那时你就完蛋了。
-
那么这是否意味着 Delphi 不适合构建 shell 命名空间扩展,至少就 GUI 而言?
-
一点也不。如果你可以在 C++ 中完成,你可以在 Delphi 中完成。但 VCL 听起来不是一个选项。