Today someone asked what is a way to send messages between two .NET exes.
mmm Well. Interesting question. There are several approaches.
1. .NET Remoting
.NET remoting is not a new technology but is a core part of the
.NET framework and it's always available:
For an example see this code from: http://www.codeproject.com/Articles/62813/NET-Remoting-Events-Explained
2. Named Pipes
This is vb.net example: http://support.microsoft.com/kb/871044
3. WCF
WCF is a great option even if you have legacy VB6 code you can use the SOAP Client to communicate
with the service:
This link http://www.aspfree.com/c/a/VB.NET/Calling-a-Web-Service-using-VB6-with-SOAP-30/
shows an example calling a Coldfusion Service but use it as a base for calling
a WCF service
You can also integrate WCF with COM+ http://msdn.microsoft.com/en-us/library/bb735856.aspx
4. Windows Messages
There is a nice project that wrap it all up for you so you can use this solution:
http://www.codeproject.com/Articles/17606/NET-Interprocess-Communication
In VB6 ActiveX-EXEs or ActiveX OLE Server where used for several
reasons. Sometimes it was performance (because it allowed you to run
your code in another process) and sometimes as way to share resources
between several applications, like connection information, database
connections, mainframe info, etc.
During migration some of this ActiveX-Exes can be migrated as simple
Assembly DLLs, but other require more attention. Specially if they have
global variables that hold state shared by several programs.
In that is your case what are your options then?
1. Convert those ActiveX-Exes to Windows Services.
This option is simple. You modify your migrated assembly to work as a Windows Service. The easier way to do that is:
a) Start Microsoft Visual Studio 2005\2008
b) Go to File\New…\Project… and Select Windows Service
That will generated code like:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
namespace WindowsService1
{
public partial class Service1 : ServiceBase
{
public Service1() { InitializeComponent(); }
protected override void OnStart(string[] args) { }
protected override void OnStop() { }
}
}
c) Add a reference to the Remoting Assemblies: System.Runtime.Remoting;
d) Modify the previous code:
Add two using statements like:
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting;
Add a simple event log for tracing:
private static EventLog evt = new EventLog(“Application”);
private static string SVC_NAME = “ActiveX Server Example Svc”;
And modify the OnStart and OnStop methods to look like:
protected override void OnStart(string[] args)
{
HttpChannel chnl = new HttpChannel(1234);
ChannelServices.RegisterChannel(chnl,true );
RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyClass), “MyClass.soap”, WellKnownObjectMode.Singleton);
evt.WriteEntry(SVC_NAME + ” Started”);
}
protected override void OnStop() { evt.WriteEntry(SVC_NAME +” Stoppped”); }
Also make sure that MyClass extends MarshalByRefClass
2. Convert those ActiveX-Exes using the Artinsoft ActiveX migration helpers.
Sometimes, you need your migrated application to replicate some of
the original ActiveX EXE \OLE DLL VB6 characteristics. For example you
need your ActiveX-EXE to start just when the first instance is created
and to resemble the VB6 logic for Process creation\destruction.
For that purpose Artinsoft has created some helpers that our
migration tool is able to automatically use in the generated code if it
detects that this functionality is needed.
The code will then be changed from:
Dim myInstance As New MyProject.MyClass
To the following Helper method:
myInstance = MyProjectFactory.Create< MyProject.MyClass>(myInstance);
And destroy calls can be changed to the following Helper method:
myInstance= MyProjectFactory.Dispose<MyProject.MyClass >( myInstance);
The migration tool will modify your ActiveX-EXEs or OLE Servers to
be Windows EXE and the helper will then locate the assembly that
contains the desired Class, create an instance and initilize a Remoting
channel to the desired classes. Settings as SingleUse and MultiUse are
also taken care by the helpers.
3. Other possible alternatives are using WFC and COM+ that I will comment in another post.
How can I migrate property pages? Well that is a common question when migrating VB6 Activex controls.
Property Pages where commonly used in VB6 to provide a mechanism for your user controls to edit values.
.NET provides even more mechanisms for editing your control properties. You can provide an editor for each one of your component properties or you can provide a ComponentEditor for all the component, this is very similar to the VB6 concept.
In .NET the ComponentEditor can be actived in the designer selecting Properties from the context menu when you right click over the control.
This is from the MSDN documentation:
“A component editor is used to edit a component as a whole and can be used to implement a
user interface similar to that of the property pages. You associate a component editor with a
component by using the EditorAttribute attribute.” From: ComponentEditor Class
The VBUC does not process out of the box, your PropertyPages, but I developed a tool that can be
used so the VBUC can help you migrate those property pages. This tool will modify your VB6 project,
and VB6 PropertyPages source code to make those VB6 PropertyPages look like VB6 UserControls.
This will allow the VBUC migration tool to recover some of the VB6 PropertyPages code and appearance
and with some manual changes you can get your property pages to work again.
Use the following link to downlaod the tool: DOWNLOAD TOOL
So these are the steps to migrate a VB6 Project that has Property Pages with the VB6.
1) Make a backup copy of your source code.
2) Run the TOOL with your project file. For example if your project file is Project1.vbp then run the tool like this:
FixPropertyPages Project1.vbp
This will generate a new VB6 Project file called ModifiedProject1.vbp
3) Open the VBUC, and migrate the new project file ModifiedProject1.vbp
4) Open the migrated solution in Visual Studio.
5) All your property pages will be migrated to .NET UserControls. You might need to go thru some changes to make them completely functional. Remeber to add the [ToolboxItem(false)] to these property pages because they do not need to be visible in your toolbox.
6) Now, to associate those property pages with your UserControl do this:
6.1) Add a new code file to your migrated solution. We are going to create a ComponentEditor, that will hold all the pages and associate that to the migrated control. Lets say the control is named Control1 and the property pages are PropertyPage1 and PropertyPage2.
We will call the ComponentEditor ComponentEditorToAssociatePagesForMyControl.
In this ComponentEditor we will add an internal class for each PropertyPage. This class will inherit from ComponentEditorPage. We will call this internal classes Page1, and Page2. And we will associate those classes with the ComponentEditorToAssociatePagesForMyControl in the GetComponentEditorPages().
The resulting code will be like:
C#using System.Windows.Forms.Design;
using WindowsFormsApplication1;
using System.Drawing;
using System.ComponentModel;
[ToolboxItem(false)]
public class ComponentEditorToAssociatePagesForMyControl : WindowsFormsComponentEditor
{
// Methods
public override bool EditComponent(ITypeDescriptorContext context, object component)
{
return false;
}
class Page1 : ComponentEditorPage
{
// Methods
public Page1()
{
PropertyPage1ForControl1 page1 = new PropertyPage1ForControl1();
Size mysize = new Size(400, 250);
this.Size = mysize;
this.Text = "Page 1 for Control1";
this.Controls.Add(page1);
}
protected override void LoadComponent() { }
protected override void SaveComponent() { }
}
class Page2 : ComponentEditorPage
{
// Methods
public Page2()
{
PropertyPage2ForControl1 page2 = new PropertyPage2ForControl1();
Size mysize = new Size(400, 250);
this.Size = mysize;
this.Text = "Page 2 for Control1";
this.Controls.Add(page2);
}
protected override void LoadComponent() { }
protected override void SaveComponent() { }
}
protected override System.Type[] GetComponentEditorPages()
{
return new System.Type[] { typeof(Page1),typeof(Page2) };
}
protected override int GetInitialComponentEditorPageIndex()
{
return 0;
}
}
VB.NET
<ToolboxItem(False)> _
Public Class ComponentEditorToAssociatePagesForMyControl
Inherits WindowsFormsComponentEditor
' Methods
Public Overrides Function EditComponent(ByVal context As ITypeDescriptorContext, ByVal component As Object) As Boolean
Return False
End Function
Protected Overrides Function GetComponentEditorPages() As Type()
Return New Type() { GetType(Page1), GetType(Page2) }
End Function
Protected Overrides Function GetInitialComponentEditorPageIndex() As Integer
Return 0
End Function
' Nested Types
Private Class Page1
Inherits ComponentEditorPage
' Methods
Public Sub New()
Dim page1 As New PropertyPage1ForControl1
Dim mysize As New Size(400, 250)
MyBase.Size = mysize
Me.Text = "Page 1 for Control1"
MyBase.Controls.Add(page1)
End Sub
Protected Overrides Sub LoadComponent()
End Sub
Protected Overrides Sub SaveComponent()
End Sub
End Class
Private Class Page2
Inherits ComponentEditorPage
' Methods
Public Sub New()
Dim page2 As New PropertyPage2ForControl1
Dim mysize As New Size(400, 250)
MyBase.Size = mysize
Me.Text = "Page 2 for Control1"
MyBase.Controls.Add(page2)
End Sub
Protected Overrides Sub LoadComponent()
End Sub
Protected Overrides Sub SaveComponent()
End Sub
End Class
End Class
7) After creating the ComponentEditor you must associate the component Editor to your new component editors. This can be done with something like:
C#
[Editor(typeof(ComponentEditorToAssociatePagesForMyControl), typeof(ComponentEditor))]
public class Control1 : UserControl
|
VB.NET
<Editor(GetType(ComponentEditorToAssociatePagesForMyControl), GetType(ComponentEditor))> _
Public Class Control1
|
8) Now to use this property pages, go to the designer screen and open the context menu and select properties. And editor with your properties pages will appear :)
9) You still need to write some code for saving the property values that is something you have to add to the LoadComponent and SaveComponent methods of the internal classes in your ComponentEditor (ComponentEditorToAssociatePagesForMyControl in our previous example).
I hope this helps to get your code faster in .NET. I'm attaching a C# sample if you want to try it out.
This post describes an an interesting workaround that you can use to support the migration of ActiveX Documents with the Artinsoft Visual Basic Upgrade Companion which is one of the Artinsoft \ Mobilize.NET tools you can use to modernize your Visual Basic, Windows Forms and PowerBuilder applications.
Currently the Visual Basic Upgrade Companion does not allow you to process ActiveX Document directly, but there is a workaround: in general ActiveX Document are something really close to an User Control which is a element that is migrated automatically by the Visual Basic Upgrade Companion.
This post provides a link to a tool (DOWNLOAD TOOL) that can fix your VB6 projects, so the Visual Basic Upgrade Companion processes them. To run the tool:
1) Open the command prompt
2) Go to the Folder where the .vbp file is located
3) Execute a command line command like:
FixUserDocuments Project1.vbp
This will generate a new project called Project1_modified.vbp. Migrate this new project and now UserDocuments will be supported.
First Some History
VB6 allows you to create UserDocuments, which can be embedded inside an ActiveX container. The most common one is Internet Explorer. After compilation, the document is contained in a Visual Basic Document file (.VBD) and the server is contained in either an .EXE or .DLL file. During development, the project is in a .DOB file, which is a plain text file containing the definitions of the project’s controls, source code, and so on.
If an ActiveX document project contains graphical elements that cannot be stored in text format, they will be kept in a .DOX file. The .DOB and .DOX files in an ActiveX document project are parallel to the .FRM and .FRX files of a regular Visual Basic executable project.
The trick to support ActiveX documents is that in general they are very similar to UserControls, and .NET UserControls can also be hosted in a WebBrowser. The following command line tool can be used to update your VB6 projects. It will generate a new solution where UserDocuments will be defined as UserControls.
If you have an ActiveX document like the following:
Then after running the tool you will have an Project like the following:
So after you have upgraded the projet with the Fixing tool, open the Visual Basic Upgrade Companion and migrate your project.
After migration you will get something like this:
To use your migrated code embedded in a Web Browser copy the generated assemblies and .pdb to the directory you will publish:
Next create an .HTM page. For example UserDocument1.htm
The contents of that page should be something like the following:
<html>
<body>
<p>ActiveX Demo<br> <br></body>
<object id="UserDocument1"
classid="http:<AssemblyFileName>#<QualifiedName of Object>"
height="500" width="500" VIEWASTEXT>
</object>
<br><br>
</html>
For example:
<html>
<body>
<p>ActiveX Demo<br> <br></body>
<object id="UserDocument1"
classid="http:Project1.dll#Project1.UserDocument1"
height="500" width="500" VIEWASTEXT>
</object>
<br><br>
</html>
|
Now all that is left is to publish the output directory.
To publish your WinForms user control follow these steps.
- Create a Virtual Directory:
- A Wizard to create a Virtual Directory will appear.
Click Next
Name the directory as you want. For example Project1. Click Next
Select the location of your files. Click the Browse button to open a dialog box where you can select your files location. Click Next
Check the read and run scripts checks and click next
Now Click Finish
- Properties for the Virtual Directory will look like this:
NOTE: to see this dialog right click over the virtual directory
- Now just browse to the address lets say http:\\localhost\Project1\UserDocument1.htm
And that should be all! :)
The colors are different because of the Host configuration however a simple CSS like:
<style>
body {background-color: gray;}
</style>
Can make the desired change:
Notice that there will be security limitations, for example for thinks like MessageBoxes.
You can allow restricted operations by setting your site as a restricted site:
For example:
Restrictions
The constraints for this solution include:
* This solutions requires Windows operating system on the client side
* Internet Explorer 6.0 is the only browser that provides support for this type of hosting
* It requires .NET runtime to be installed on the client machine.
* It also requires Windows 2000 and IIS 5.0 or above on the server side
Due to all of the above constraints, it might be beneficial to detect the capabilities of the client machine and then deliver content that is appropriate to them. For example, since forms controls hosted in IE require the presence of the .NET runtime on the client machine, we can write code to check if the client machine has the .NET runtime installed. You can do this by checking the value of the Request.Browser.ClrVersion property. If the client machine has .NET installed, this property will return the version number; otherwise it will return 0.0.
Adding a script like:
<script>
if ((navigator.userAgent.indexOf(".NET CLR")>-1))
{
//alert ("CLR available " +navigator.userAgent);
}
else
alert(".NET SDK/Runtime is not available for us from within " + "your web browser or your web browser is not supported." + " Please check with http://msdn.microsoft.com/net/ for " + "appropriate .NET runtime for your machine.");
</script>
Will help with that.
References:
ActiveX Documents Definitions:
http://www.aivosto.com/visdev/vdmbvis58.html
Hosting .NET Controls in IE
http://www.15seconds.com/issue/030610.htm
As part of the VB Companion Development group, my day to day includes
migrating several project from different clients, to develop custom mappings
and custom functionality for their migration needs or to add new features
for the next VB Companion version.
A long part of the initialization in the migration process consists of the load and
analysis of the COM references indicated in the .VBP project file.
Sometimes I have notice that there are several references that are never used.
Removing these references will provide a great save in time because the migration will
not have to incur in any time for TypeLib and TypeInfo extraction.
I look for a tool that let me get rid of the VB6 unused referencences but I found none.
So I decided to create one myself. And I created the VB6 Project References Cleaner Addin
The concept of the tool is simple, someone from a group posted the idea I just implemented.
The addin goes thru all the references and one by one tries to remove it.
And then compiles the project. It the project compiles,then the reference was not neccesary.
If you mark the remove option the tool will remove the references for you.
This tool will NOT SAVE the project file. You decide if you what to save it.
I'm attaching the source code and the dll. To used it just take the VB6References.dll and run:
regsvr32 VB6References.dll
After that the tool will appear in the Addins menu in VB6
SOURCE CODE and BINARIES