views:

406

answers:

5

I am currently exploring the option of porting some older VB6 application to WPF with C#. The plan, in phase one, is to port several key forms and not all the application. The theoretical goal is to open the VB6 form in a container of some sort within WPF via an ActiveX dll.

Is this even possible? I've tried looking at the Interop and can't seem to find a solid example of how get it to work with anything but Win32 controls, not a full form. I have full access to the old VB6 code and can modify it in anyway needed.

The following screenshot of the main WPF app would serve as the wrapper/container:

http://www.evocommand.com/junk_delete_me/main_menu_mockup.png

The current VB6 maintenance screen that would be loaded in the “white space” section on the right side of the previous screen.

+1  A: 

Can you even load that VB6 form in another VB6 form? I suggest you get that working first.

John Saunders
I want to load the VB6 form in a WPF form.
jasonk
@jasonk: I know what you want to do. I suggest you first get the VB6 form loaded in a VB6 form. Once that's done, you'll know that the form can be loaded in _some_ kind of form. _Then_ work on getting it to load in a WPF form. You may have to change the form to allow it to be loaded in another form. You'd just as well do that work in VB6, which you're familiar with.
John Saunders
A: 

There is no reliable way to set parent of a VB6 form. You can always hack it or use plain ActiveX control (UserControl in VB6) as UI container instead of VB6 forms.

wqw
I'm not very familiar with building OCX controls. Does that mean each screen in VB6 would have to be it's own control or is there a way to host multiple screens within the single control?
jasonk
+2  A: 

I think what you will have to do is extract the VB6 form contents into an ActiveX control. You can then expose this in your ActiveX dll and place that in your WPF form. I doubt it's possible to host a VB6 form within any other type of form.

Jeremy Wiebe
+1, although the control would need to be exposed in an ActiveX OCX rather than a DLL.
MarkJ
I'm not very familiar with building OCX controls. Does that mean each screen in VB6 would have to be it's own control?
jasonk
Yes, essentially you take everything off of the screen and place it in an ActiveX control. Then you can place this control onto your VB6 form (or host it in your .NET application). I just ran across this MSDN article which might help you. http://msdn.microsoft.com/en-us/library/ms742735.aspx
Jeremy Wiebe
A: 

I found a method to do what was needed within WinForms rather than WPF at this point. http://www.codeproject.com/KB/vb-interop/VB6formsinNET.aspx I figure if I can get it working 100% there I can port it over to WPF or worse case host the WinForm element in the WPF form if I absolutely have too (U-G-L-Y).

Anyway, I've gotten a bit closer, but am having a very odd issue with certain controls painting too the screen. Radio/Option buttons are rendering as solid black:

http://www.evocommand.com/junk_delete_me/optionbuttons.png

I've tried explicitly changing the controls' background color from buttonface to a fixed color and it still does it. I'm assuming it's a layering issue with the option buttons being within the frame control. I'm at a bit of a loss on how to proceed without massive rework of the VB6 content to change the options buttons to checkboxes. It's a hefty app and there are 600+ option button controls across the application that I don't exactly want to deal with.

EDIT: I was able to confirm it has something to do with the layering of the option within a Frame control. If pulled out to the base form the issue does not occur: http://www.evocommand.com/junk_delete_me/optionbuttons2.png

jasonk
Found an odd workaround that if you put the OptionButtons within a PictureBox rather than a Frame it will display without the black background.
jasonk
+4  A: 

I was able to accomplish the task with the following steps:

  1. Created a new VB6 Active X Control Project. Copied and pasted the entire contents of the VB6 form controls and code behind into the new control. There are several elements that have to be handled in switching to a control:

    1. you lose the ability to display the caption of the form in the previous manner. You can work around it with alternate controls (label/borderlesstextbox, etc) that accomplish the same functionality if needed. This wasn’t a priority since each screen was being hosted in a browser like tab system in our new .Net project.

    2. All mousepointer references have to be changed from Me.Mousepointer to Screen.mousepointer

    3. You cannot use Me.Hide and have to alternate events to hide the .Net container.

    4. Any and all references to Me.[anything] have to be removed or replaced with UserControl.[anything] if they are applicable.

    5. If you use any functions that reference a [yourcontrol].Contianer.Property on a form they will need to be altered to loop through the UserControl.Controls collection instead and “Container” is invalid for vb6 ActiveX controls

    6. All non-modal forms/dialog boxes must be removed from the project as there is now no Hwnd to handle in WPF. You get an error of 'Non-modal forms cannot be displayed in this host application from an ActiveX DLL, ActiveX Control, or Property page'. In our case we had a simple splash screen that would display when certain long processes/reports displayed to let the user know what was running.

  2. I was unable to directly add the VB6 control via the interop to a WPF project . As such a new .Net “Windows Form Control Library” project was created. A reference to the VB6 OCX was added to the project. The VB6 Control s were then added to the .Net toolbox by “right click” –> “Add Item” and pointing a com reference to the VB6 control ocx. The .Net control was then used to host/serve the VB6 Control.

  3. To display host a form in the VB6 and get it to fire the necessary initialization functionality the VB6 OCX controls were defaulted in a Visible.False manner so they were initially added to the .Net OCX as invisible controls. When needed the VB6 control is set to visible = True which fires the UserControl_Show() event. All code formerly in Form_Load() was moved to this event. The show event was the easiest method of accessing the Form_Load as needed. MSDN: “The control does not receive Show events if the form is hidden and then shown again, or if the form is minimized and then restored. The control’s window remains on the form during these operations, and its Visible property doesn’t change.”

  4. Wrapping the vb6 controls within a .Net Winform control resolved the issue with Radio/Option buttons being rendered as black as outlined elsewhere in one of my responses to this question without having to convert the frames to Picture boxes as suggested.

  5. In the WPF app as a menu choice is selected xaml code is dynamically created and displayed via a wrapper with a WindowsFormsHost tag. A dynamically created control object from the .Net winform app is then pushed into the WindowsFormsHost tag on the xaml and the control is made visible on the .net project which fires vb6 UserControl_Show and then load and display of the vb6 form.

jasonk
Wow, that is amazingly through.
Jonathan Allen
Just trying to save some poor soul some of the cranial bruising, from banging their head, that I've gone through for the last couple weeks working it out.
jasonk