Click here to Skip to main content
Email Password   helpLost your password?

Screenshot - VB6formsinNET_screenshot.jpg

Introduction

Typically, the available tools that provide interoperation between .NET code and VB6 code are based on proxies, wrappers or other forms of middleware that allow VB6 applications to call .NET Winforms. So far, we haven't seen a solution that allows us to do the opposite. That is, to embed VB6 forms in a .NET application. For that reason, we decided to create that solution on our own. At MasterSoft, we have many applications developed in Visual Basic 6 in which we invested several thousands of development hours. Right now we face the necessity of migrating them to .NET in a gradual way and with the least amount of effort.

To reach that goal, we envisioned a kind of interoperation between VB6 and .NET that would allow us to open VB6 forms in a .NET application. This would give us the opportunity to migrate the applications gradually, incorporating new functionality with "native" .NET code and maintaining intact � or as intact as possible � everything that's written in VB6. The main advantage of this strategy is in leveraging a .NET framework developed by ourselves, which gives us powerful tools for menu designing and security management, among many other things. All these benefits would be lost if we maintained the core of our applications in VB6.

The solution we applied is based on a .NET MDI environment from which we can open VB6 forms contained in a DLL, just as if they were MDI children of the .NET form. Instead of using toolkits or power packs for .NET-VB6 interop, we used instances of a .NET container form in which we embed the VB6 forms. By using API functions, the normal behavior of the embedded forms is simulated.

Implementation details

To use VB6 forms from within a .NET application, we opted to develop a "shell" (container) form in VB.NET with MDI child functionality. This creates an instance of the VB6 form through a specific class in the DLL ActiveX, which is ClsForms. Using API functions and communication with the DLL, the VB6 form is instanced and embedded in the container.

Within the VB6 DLL, there is a public class that does the job of instancing the forms and communicating with the .NET application. This class acts as a controller of the instantiated forms in the DLL. It provides access to them through several methods that help the container to behave as the VB6 form would in a VB6 MDI container. Due to the fact that the VB6 forms reside in a DLL ActiveX, we needed to make sure that their MDIChild property is set to False because we couldn't figure out how to change that property at runtime. In order to manage the events of the VB6 form, the .NET container uses a Timer control that constantly queries the VB6 class for messages to handle.

A big issue we needed to solve was the communication between VB6 forms. In many cases, our application forms call each other, passing parameters and results -- of searches, for instance -- between them through properties. In order to keep this behavior in the .NET application with the VB6 forms, it was necessary to give the VB6 forms the chance to create new instances of the container and embed in them other VB6 forms. This was done as explained below.

Showing the sequence

To make things a bit more encapsulated, we develop a FormController class in the .NET project which maintains the instance of the DLL and creates multiple instances of the .NET container. Thus, we can open multiple forms using the same instance of ClsForms.

'We instantiate FormController by passing 

'the MDI form and the Dll ActiveX name

Dim objFormController As New FormController(objMDIForm, "FormsVB6")

'then we just call the OpenForm function passing the VB6 form name

objFormController.OpenForm("frmChildForm")

The best way to show the interaction between objects is with this UML sequence diagram:

Screenshot - VB6formsinNET_sequence.gif

The OpenForm function in the FormController creates an instance of the ClsForms class in the ActiveX DLL -- the one that contains all the VB6 forms -- and then instantiates the frmContainer form. Finally, it calls its OpenForm method. The OpenForm method in the container in turn calls the OpenForm method in ClsForms. It does this in order to create a new instance of the form's name, passed by argument using the hidden VB6 Forms.Add("formname") instruction.

When the form instance is created, the OpenForm method returns the handle of the instance to the container. With that handle and through API functions, as well as through other methods of the ClsForms class, the VB6 form is "drawn" inside the .NET container. The OpenForm container obtains the property values of the VB6 form such as Title, Width, Height, etc. in order to replicate them in the container, i.e. the GetWindowTitle in the diagram above. The container form is also responsible for checking the state of its embedded form. In this way, it can know if the VB6 form has been closed by an Unload Me instruction and thus can close the container.

Form behavior

In order to mimic the event firing from the VB6 form, the container uses a Timer control to constantly check if there are events in the VB6 form that need to be handled. We could have chosen to pass the events directly from the VB6 form to the .NET application, but that would have implied a much deeper modification of those forms' code, which was exactly what we wanted to avoid.

To give the VB6 form the ability to open "child" non-modal forms and keep its condition of MDIChild, it is necessary to use the ShowForm function in VB6 instead of the usual .Show method. The ShowForm function does all the process needed to keep the called child form in the .NET environment within its container. That is basically all the work that needs to be done with the VB6 forms in order to embed them in a .NET container.

'Opens a new child form

ShowForm(frmChildForm, True)

'Opens a new modal form

ShowForm(frmModalForm, False)

So we need only to replace the Show calls in the code to ShowForm(), passing the form we want to show and a second boolean argument indicating if you want it to be an MDI child or not. If so, it calls the OpenForm in the container by passing a message "OpenForm" to it. If not, it just opens the form as a regular modal form.

To preserve the normal behavior of the VB6 forms and their respective containers as MDI child forms � for instance, the normal use of Ctrl-Tab, the focus change between forms or the fact that the .NET MDI Form keeps active to open other .NET or VB6 forms � we needed to use various API functions like SendMessage, SetForegroundWindow and LockWindow.

To enhance this technique, we are planning to add code to the intermediate class that sits between the .NET MDI form and the container. This would allow event firing from VB6 that affects the .NET environment. Examples would be modifying the Caption property of the MDI Form, opening .NET "native" forms, etc.

References

We use a function from Stephen Kent to change the form border style at runtime.

Using the code

The code is pretty simple and is commented where I think it's needed. We didn't use advanced programming techniques, only a few API calls to do the "magic."

Conclusion

This way of interoperating between .NET and VB6 allows us to start a gradual migration path to .NET for our applications that won't force us to make immediate modifications to them. It also instantly adds many of the benefits of the .NET framework we developed to the applications. As an additional feature, this gradual migration path allows the end users to learn gradually how to use the new features that the .NET version of the application offers, without being forced to learn all the changes at once.

Special thanks go to Gustavo Du Mortier and Mariano Aranda from MasterSoft; they really help and colaborate with this.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralSet frmContrainer.vb top of all but as modeless
abdh
4:12 27 Oct '09  
help, after testing the sample code it work fine but i discoverd after adding a panel on the MDI form that the frmContrainer is drown under it and this is upnormal from normal .net forms in my application that can easly drown above all the panel and controls when it first initialised and opend, any help might solve this issue ,im trying to go arround the APi func but seems useless Confused
Generalactive x error
tenro
6:52 14 Aug '08  
when i even try to run your sample open vb form i get this error
See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.

************** Exception Text **************
System.Exception: Cannot create ActiveX component.
at Microsoft.VisualBasic.Interaction.CreateObject(String ProgId, String ServerName)
at NetForms.FormController.GetInstance() in C:\Documents and Settings\******\Desktop\wow\NETProject\NetForms\Classes\FormController.vb:line 20
at NetForms.FormController.OpenForm(String strFormName) in C:\Documents and Settings\*******\Desktop\wow\NETProject\NetForms\Classes\FormController.vb:line 30
at NetForms.frmMain.mnuVB6Form_Click(Object sender, EventArgs e) in C:\Documents and Settings\******\Desktop\wow\NETProject\NetForms\Forms\frmMain.vb:line 17
at System.Windows.Forms.ToolStripItem.RaiseEvent(Object key, EventArgs e)
at System.Windows.Forms.ToolStripMenuItem.OnClick(EventArgs e)
at System.Windows.Forms.ToolStripItem.HandleClick(EventArgs e)
at System.Windows.Forms.ToolStripItem.HandleMouseUp(MouseEventArgs e)
at System.Windows.Forms.ToolStripItem.FireEventInteractive(EventArgs e, ToolStripItemEventType met)
at System.Windows.Forms.ToolStripItem.FireEvent(EventArgs e, ToolStripItemEventType met)
at System.Windows.Forms.ToolStrip.OnMouseUp(MouseEventArgs mea)
at System.Windows.Forms.ToolStripDropDown.OnMouseUp(MouseEventArgs mea)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ToolStrip.WndProc(Message& m)
at System.Windows.Forms.ToolStripDropDown.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

its coming from this line
mobjActiveXInstance = CreateObject(mstrActiveXLib & ".ClsForms")
mstractive at the time is "FormsVB6"
GeneralRe: active x error
sisdevar
10:15 14 Aug '08  
You have to run the VB6 project first so the .NET project can instantiate the VB6 project's ClsForms class.

Hope this helps.
General[Message Removed]
immetoz
16:08 4 Oct '08  
Spam message removed
GeneralRe: active x error
Tamires
7:42 3 Dec '08  
I got the same error and running the VB6 project didn't work out.
Any idea?
GeneralRe: active x error
sisdevar
7:57 3 Dec '08  
If you run the VB6 project you should be able to create an instance of the ClsForms class from the .NET project. Place a breakpoint in the line
mobjActiveXInstance = CreateObject(mstrActiveXLib & ".ClsForms")
and check if values are correct. If you still have prblems to instantiate the VB6 ClsForms class you should check the VB6 project properties and ClsForms properties to make them available for the CreateObject function.
GeneralAccessViolations and Application-Hangs
Geert Teugels
22:52 12 Jun '08  
We are developing a similar application : ~5000 ActiveX-VB6-dll's of which 20% has been converted to VB.Net 2.0.
We used a different technique to keep the window-forms modal : WindowHooks, WndProc and SetActiveWindow.

We experience however AccessViolations causing the application to hang or close unexpectedly.

Our question to you is whether you are experiencing the same (or similar) problems with your solution. If not, we might try to implement your solution.
GeneralVB6 interop in CAB and SCSF screens
RathiV
20:28 15 May '08  
Hi, Can you please let me know if i can invoke a VB6 form from my CAB screen (Composite UI Application block).
My requirement is not to use Winforms but use forms developed using CAB. Any help is most welcome.

Thanks a lot,
Rathi
GeneralRe: VB6 interop in CAB and SCSF screens
Eduardo Campano
4:00 18 May '08  
Sorry but I didn't try the CAB yet. I think it's possible but you'll need to change al least some of the .net code.
GeneralRe: VB6 interop in CAB and SCSF screens
RathiV
19:37 18 May '08  
Hi, Thanks for the input. Can you please let me know, if i can embed the VB form in my windows forms control like Web Browser control and navigate to multiple VB6 forms?

Thanks,
Rathi
QuestionWhy I can't create a child form which is not midchild in the FormVB?
dick.mei
20:41 19 Sep '07  
I tried to create a child form in frmChildForm as you suggested, but It doesn't work.
Private Sub Command3_Click()
ShowForm frmChildForm2, False
End Sub

When I press button Command3, nothing is happened. And I can't figure out the cause even in debug mode.

Do you know why?

AnswerRe: Why I can't create a child form which is not midchild in the FormVB?
Eduardo Campano
3:58 20 Sep '07  
Ok you found two bugs, please correct the ShowForm function to

Public Sub ShowForm(ByRef objForm As Form, ByVal blnMDIChild As Boolean)

If blnMDIChild Then
SendMessage "OpenForm", objForm.Name
Else
objForm.Show vbModal
End If

End Sub

the Not in the condition was wrong and then the

strMessage = mobjClsFormsInstance.GetMessage(strParameters)

line in frmContainer form in the .NET project to

strMessage = mobjClsFormsInstance.GetMessage(mintFormHandle, strParameters)

Now you can open a form as a modal form using ShowForm(Form1, False) or as another MDI child using ShowForm(Form1, True)
The first bug is a wrong condition and the second is breaking the communication between .NET and VB6

Thank you for the message
AnswerRe: Why I can't create a child form which is not midchild in the FormVB?
Dick Mei
16:25 20 Sep '07  
Thank you for your reply! It's very helpful!

I have studied your sample for about 4 hours, and find a little problem. When I open the FromVB again, an exception occurrs. Well I can fix it myself.

My concern is that is this solution strong enough to handle all the problems. You know in a product there may be many vb forms and maybe one show another, modal or non-modal. If I invoke the vb forms in .net forms, do they act the same with what they acted in vb environment. Is there any big problems that can't be fixed by this solution?
GeneralRe: Why I can't create a child form which is not midchild in the FormVB?
Eduardo Campano
3:55 18 May '08  
I don't really it's a fully stable solution yet. As it uses Win32 APIs, I don't think all the behaviours, like focus or key shortcuts, are beeing well handled. I started with it cause we need to migrate a big project from VB6, but the migration stopped for now so I couldn't continue this work.
QuestionWhen you press the TAB key, the focus does not change from one control to another control.
victorleo
7:52 1 Sep '07  
Hello.

Apply east example and you have the following problems

When you press the TAB key, the focus does not change from one control to to another control.

When you press ENTER on to command button that there are the focus, the Click event of the command button does not occur.

Looking for in Internet on this encontre this I articulate http://support.microsoft.com/kb/925369/en-us in Microsoft.

According to I articulate To supported hotfix is now available from Microsoft, but it is only intended to correct the problem that this article you describe. Apply it only to systems that plows experiencing this specific problem.

If somebody has the bookstores they podrian to give them to me.

Victor
AnswerRe: When you press the TAB key, the focus does not change from one control to another control.
victorleo
10:22 25 Sep '07  
Have obtained the HotFix but I follow such with problems
GeneralRe: When you press the TAB key, the focus does not change from one control to another control.
Elfman_NE
4:53 22 Jan '08  
Is there a work around for this?

Also, is there anyway to communicate between forms of VB 6 and .Net?
GeneralRe: When you press the TAB key, the focus does not change from one control to another control.
Member 2445078
12:43 12 Feb '08  
Hi,

We are having this problem, but with VB6 Forms under .NET; I'm not sure
I understand you were saying... Did the hotfix worked ?
AnswerRe: When you press the TAB key, the focus does not change from one control to another control.
skokeh
4:29 16 Dec '08  
Good day guys
actually i didn't try the hotfix yet because i couldn't download it.
but i have an idea may it will be useful to you
1. add two textboxs to VB.net Container which contains the vb6 form.
2. change BorderStyle property to None, BackColour to Control, and ReadOnly to True.
now you have two TextBoxs invisible in the form.
you will see that when you press tab index it will not go to the next form
but the problem now is you can't go to the next control in vb6
3. if you print this code in vb6

Private Sub Form_KeyPress(KeyAscii As Integer)
If KeyAscii = 13 Then
SendKeys "{Tab}"
end if
End Sub
it will not work lol
because Tab key not sensitive in Vb6 also in VB.net
so if anyone know how it will be sensitive we will solve this problem.

question is hotfix work verywell or what?

Mhd Sam Kouka

GeneralRe: When you press the TAB key, the focus does not change from one control to another control.
ryanlenagh
5:59 9 Sep '09  
What hotfix are you all refering too. I am having the same problem and am wondering if this will even work for my app. Are you referring to http://support.microsoft.com/kb/925369[^] if so, that doesnt apply to windows 7.
GeneralSuggetions
VeNoM00
23:25 27 Jun '07  
Try

Catch ex As Exception

MsgBox(ex.Message)

End Try

What's that? Sniff
Anyway, you can't interact with the VB6 form (or at least you didn't explained how), you can just insert it as an MDI child. What can do a form alone? This would be useful just in the case that form is a stand-alone application itself.
Moreover this technique seems too complex to me. Wouldn't it be simpler transfer the code from the vb6 form into an activex control and then embed it in .net winform? In this way you shouldn't make all that api calls and manage the form better. Don't you think?
GeneralRe: Suggetions
Eduardo Campano
6:09 28 Jun '07  
Ok, sorry about the try...chatch, it's horrible.
As I explain in the article, the main goal of this solution was to use MDI child forms written in VB6 touching as less as we can of the VB6 code. The applications we build use a layered architecture, so VB6 forms are nearly stand-alone as you say, they communicate with a business layer to process the loaded data.
This way we simply moved the forms from the Exe to an ActiveX Dll, switch their MDIChild properties to False and we can open them from a NET MDI. (Don't forget to replace the Show method to ShowForm, so you can open another MDI child from the VB6 code). Imagine that our VB6 applications got about 100 forms (and we reuse them, there's not repeated code), so moving the content of the forms to an activex control and create a fixed shell of each one in the NET side would take a lot.
This technique allow us to add new functionality (new forms) in the NET side and gradually migrate the VB6 forms to NET with much less effort (consider the product realeases).

It's the first version, I have a large list for performance and comunication improvements to make.
I'd like to receive suggestions too.


Last Updated 12 Jul 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010