从.NET COM DLL调用VB6表单?

3
我们有一个非常庞大的VB6应用程序,其中有数百个表单/用户控件/类等。我们已经开始迁移到.Net(目前在框架v2上,不过即将更改为v4),通过按照“按需”转换单个表单来使用公开的COM DLL。到目前为止,这一切都运作得很好。
一些更复杂的VB6表单调用多个其他表单,这些表单又调用其他表单等等,因此转换是一个自下而上的过程。有几种情况,如果我们能从.Net DLL中调用VB6表单,或许通过将某种对象引用传递到.Net中会使短期内生活更加容易。虽然我相当确定这是不可能的,但我想确认一下。
那么,这是可能的吗?

1
嗯,你可以在.NET应用程序中嵌入VB6表单,但我从未见过你想要的,尽管似乎可能是可行的,看看这个 - Pikoh
这个大型应用程序是包含在单个的VB6项目文件中还是多个项目(VBP)文件中? - John B
这是一个单一的大型VBP文件。它足够大,以至于在打开时VB会出现错误。 - Slugsie
2个回答

2
我们可以通过从.NET EXE引用VB6 DLL来调用VB6表单,这是可行的。我认为同样的方法也适用于.NET DLL。如果你想让VB6表单成为非模态的,你必须使用VB6 ActiveX EXE。将应用程序分解成可管理的块,并逐个迁移每个块是一种不错的迁移方法。

2

我不知道你的代码有多干净,所以这只是一个大概的思路(伪代码),但以下是我会采取的方法:

在一个共享库中,向.NET和COM公开每个表单的接口:

public interface ILoginForm
   property UserName as String 
   property Password as String
   function DisplayModal as Boolean 'True for login, false for cancel...or expose an enum
end interface

public interface IContactEditor
   property FirstName as String
   property LastName as String
   property EmailAddress as String
   function DisplayModal as Boolean 'True for save, false for cancel...or expose an enum
end interface

等等,对于应用程序中的每个表单都要做类似的事情。

接下来,定义一个FormFactory接口:

public interface IFormFactory
   function CreateLoginForm as ILoginForm
   function CreateContactEditorForm as IContactEditor
end interface

如果您想要缓存表单,那么您可以稍微改变界面以适应该用例。
接下来,在您的VB6 EXE中,您应该实现IFormFactory接口:
Class FormFactory Implements IFormFactory 

   public function IFormFactory_CreateLoginForm as ILoginForm
      'let's say this form is still in VB6
      Dim frm As frmLoginPage
      Set frm = new frmLoginPage
      Set IFormFactory_CreateLoginForm = frm
   end function

   public function IFormFactory_CreateContactEditorForm  as IContactEditor
      'let's say this form is in .NET
      Dim frm As DotNetLib.ContactEditorDialog
      Set frm = new DotNetLib.ContactEditorDialog
      Set IFormFactory_CreateContactEditorForm  = frm
   end function

在您的VB6应用程序中,所有表单创建都必须通过此单例进行:
Dim contactEditor as IContactEditor
Set contactEditor = modSingletons.FormFactory.CreateContactEditorForm()
contactEditor.FirstName = "Joe" 'seed with initial values
contactEditor.LastName = "Blow"
contactEditor.EmailAddress = "bubblegum@something.net"
Dim saved As Boolean
saved = contactEditor.DisplayModal()
if saved then
   'read the new values back out and write to DB or whatever
end if

如果您正确地执行此操作,您的主EXE甚至不会意识到表单是.NET还是VB6,您只需在工厂中切换它们即可。
最后,在.NET库中设置相同的内容。创建一个COM公开的单例,VB6 exe可以将IFormFactory实例传递到.NET库中。然后,您的.NET代码可以使用工厂实例来调用应用程序中的任何表单。
或者,您可以在每次调用表单时传递工厂实例(以允许该表单访问任何其他表单),但我不会这样做。原因是因为除了表单创建之外,很可能还有更多的服务需要开始迁移。为您的各种应用程序服务设置一堆接口,并以类似的方式将它们注入到.NET库中,这样您将获得更好的服务。最终所有内容都将在.NET中,但您的代码不需要更改,因为它正在使用接口。

代码非常混乱。20多年的开发,涉及各种技能水平的开发人员,使其变成了一团乱麻。它主要是一个单体的VB6 EXE,还有一个用于迁移/新代码的.Net DLL。如果我理解正确,你似乎在建议将一些或所有旧代码移动到一个可以从两侧调用的VB6 DLL中。不幸的是,我几乎不可能说服老板同意这样做。 - Slugsie
不,我建议一种迁移策略,可以使您的VB6和.NET表单在围栏的任一侧都可调用。附加的dll将位于.NET而不是VB6中,并且仅包含表单的接口。然后,两个项目都引用该UI接口库。 - tcarvin
啊,好的,我想我开始明白你的意思了。我得搭建一个测试系统来试一下。但是我怀疑这可能超出了我的老板的预期(他对转向 .Net 的态度已经很不情愿了)。 - Slugsie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接