C# 应用程序中的多个 VB6 公寓

Posted

技术标签:

【中文标题】C# 应用程序中的多个 VB6 公寓【英文标题】:Multiple VB6 apartments in C# application 【发布时间】:2013-10-29 19:00:00 【问题描述】:

我们有非常古老的旧版 vb6 应用程序,它有一个用作应用程序核心的全局对象,它存储不同的应用程序设置、调用数据库操作等。具有不同 progid 的多个模块使用这个全局对象,并且由于单线程单元而没有问题。

不久前创建了新的 WPF 应用程序,它为我们提供了从 vb6 的过渡,但是由于一些架构错误,它仍然受到 vb6 旧版的限制。每个应用实例只能连接到一个数据库。它在包装类中保存 vb6 全局对象的静态实例,用作实现旧功能的桥梁。

现在,我们正在开发不受旧代码限制的新应用程序,特别是新应用程序应该能够同时连接到多个数据库,但是有一个问题:vb6 代码仅限于单个数据库,所以应该有多个 vb6 全局对象的实例,每个数据库一个。

所以问题是:有没有可能,如果有,怎么可能在同一个 C# 应用程序中使用多个独立的全局 vb6 对象实例?

我认为这样的对象的每个实例都应该存在于它自己的 STA-线程中,但我不知道如何创建这样的线程,这些线程在整个应用程序运行时保持活动状态并且具有关联的包装器,包含全局 vb6 对象的实例并支持从 GUI 线程调用某些函数(以及如何组织这种跨线程通信,没有 thread.invoke(...))。我考虑过使用 wpf 调度模型(包装类是 DispatcherObject,每个实例都有自己的调度程序和自己的 STA 线程),但我看不到如何实现这样的事情。另外我认为它可以通过在不同的 AppDomain 中加载包装类(静态)的每个实例来实现,但我不知道它是否解决了 COM 的 STA 问题。

【问题讨论】:

一个有趣的问题。您确定在 c# 中重新编码 vb6 全局对象不会减少麻烦(并且更可靠、更易于维护等)吗? 我们不能只重新编码 vb6 全局代码,因为我们必须重新编码每个使用它的 vb6 模块——而且工作量很大(甚至没有人想碰它,重写这些会容易得多从头开始使用 C# 中的模块。但这也需要很长时间,因此我们正在尝试在新应用程序中实现与旧模块的向后兼容) 这是 VB6 的内置功能。如果您正确配置了它,那么再次创建 Application 对象应该会启动进程外服务器的 另一个 实例。与第一个完全隔离,它可以与自己的数据库对话。 线程不是唯一的问题。线程不是相互独立的。如果代码被编写为假设只有一个线程,则在两个不同线程上运行的代码仍可能使用公共内存。 您可能会为每个 AppDomain 运行一个全局对象实例而侥幸。为了安全起见,您应该在各自的进程中运行它们,因为这是创建它们的假设。我向您保证,当您违反古代代码的假设时,可能会发生可怕的事情——尤其是当您将它们介绍给编写时根本不存在的事物时。 【参考方案1】:

这是可能的,使用所谓的非托管代码。看看这个: http://www.codeproject.com/Articles/154144/Using-Unmanaged-VB6-Code-in-NET

【讨论】:

【参考方案2】:

您可能会因每个AppDomain 运行一个全局对象实例而侥幸成功。

为了安全起见,您应该在各自的进程中运行它们,因为这是创建它们的假设。我向您保证,当您违反古代代码的假设时,可能会发生可怕的事情 - 特别是当您将它们引入到编写时根本不存在的事物时。

【讨论】:

VB6 将 TLS 用于全局状态。跨线程共享状态的唯一方法是通过 COM 编组函数调用。所以实际上每个线程使用一个单例对象是非常安全的——在这种情况下没有任何假设被破坏。唯一的麻烦是 STA 线程拆除,因为运行时正在泄漏,并且没有修复。然后 MS 放弃了整个语言。 这行不通。 VB6、COM 没有 .NET AppDomains 的概念。如果 VB6 状态对于加载的进程是全局的,那么无论您的 .NET 代码在多少个 AppDomain 中,它都会继续存在。

以上是关于C# 应用程序中的多个 VB6 公寓的主要内容,如果未能解决你的问题,请参考以下文章

向多个用户推送通知

Vista 中的 VB6 .NET 互操作问题

基础表单消失但仅在显示对话框时

VB6 与 C# 以不同顺序返回的 SQL 结果集

c# app与vb6 app通信

C++ 库在 vb6 中有效,但在 c# 中无效