The legend of Forever Alone guy who wrote himself a wrapper for C# to use as ActiveX.

Woa, me and my classmates are planning to go to the cinema to enjoy "Madagascar 3" next week. It's fantastic because the girl I like love this movie so much. I invited her to join us but she couldn't, that's so sad. It's not the worst thing when I realized that all my guys would go with their girlfriends and I would go alone. In my band of 6 or 7, I am the only one who is single. Ridiculous.
Really I am a bad mood, and I can't work for final exam until I make something crazy. I decide to call some C# code in a VBScript @@ Thanks stackoverflow stuff for helping.

Target

Wrap a .NET user control in an ActiveX class

Solution

1/ Create the Class Library in VS 2010:

Open your Visual Studio in Administrator mode please (some system access will be made). Create a new, empty Class Library project and add into it a Windows Form.
Drag to the from 1 button named btnDo and 1 label named lblResult. Then bind the button clicking event with these code:

private void radButton1_Click(object sender, EventArgs e)
        {
            this.lblResult.Text = "I am a .NET user control happily living \ninside an ActiveX container. Cheers.";
        }

I'm sure you all know the meaning of that code. If you don't, go to the book store and pick any book about C# programming. I suggest the thin one because it should be cheaper.
Ok, let's move to the next part.

 

2/ Setting for project

Open the library's Property Settings window and select the Application tab. You should see an “Assembly Information…” button - click on it and it will open a dialog form with various assembly settings. You will see a checkbox named “Make assembly COM-visible”. The checkbox must be checked.
You would also see  a GUID field. Let's do something with it.
Click menu Tools -> Create GUID. In the showing dialog, click Copy. Now close this dialog and paste to GUID field in Property Settings. It is used to set the ID of the typelib if this project is exposed to COM.
Figure 1 -  Settings
Now, choose tab Build
If you want automatic registration of the freshly created ActiveX wrapper you should check the “Register for COM interop” checkbox. It runs Regasm.exe after every build to register the types with COM (which you probably shouldn't do until you're stable because your COM GUIDs will change whenever you change the methods unless you specify GUIDs explicitly, so your registry could end up with a lot of registration junk for versions that will never be used).
Last thing to do here is to provide your ActiveX a strong name key. Let do it with Microsoft style.
Steps below is copied from http://msdn.microsoft.com/en-us/library/aa559684%28v=bts.20%29.aspx with a small modification.
To create a strong name key file
  1. Click Start, point to Programs, point to Microsoft Visual Studio 2010, point to Visual Studio Tools, and then click Visual Studio 2010 Command Prompt.
  2. At the command prompt, change directory to you project folder.
  3. At the command prompt, type sn -k ActivX.snk, and then press ENTER
Now, in the Property Settings, choose Signing tab and Browse ActivX.snk as Strong name key file.
Done, now back to the code for a few additions.

3/ Thank God We have Interop Services

At the beginning of your Window Form class, insert below code:
    [ProgId("ActiveXTestLibrary.UserControl")]
    [ClassInterface(ClassInterfaceType.AutoDispatch)]
    [ComVisible(true)] 
The ProgId attribute which provides a unique name for the created ActiveX interface. You can change ActiveXTestLibrary.UserControl by other string that describes your ActiveX function.
The second ClassInterface attribute states whether and how a COM interface will be generated for the managed assembly.
The last ComVisible attibute controls accesibility of member true to COM.


Also you can provide static methods that are invoked when the ActiveX is registered or unregistered through the Regasm.exe:
        [ComRegisterFunction()]
        public static void RegisterClass(string key)
        {
            StringBuilder sb = new StringBuilder(key);
            sb.Replace(@"HKEY_CLASSES_ROOT\", "");

            RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);

            RegistryKey ctrl = k.CreateSubKey("Control");
            ctrl.Close();

            RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);
            inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase);
            inprocServer32.Close();

            k.Close();
        }

        [ComUnregisterFunction()]
        public static void UnregisterClass(string key)
        {
            StringBuilder sb = new StringBuilder(key);
            sb.Replace(@"HKEY_CLASSES_ROOT\", "");

            RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);

            if (k == null)
            {
                return;
            }
            k.DeleteSubKey("Control", false);

            RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);

            inprocServer32.DeleteSubKey("CodeBase", false);

            inprocServer32.Close();
        }

The methods have predefined names (RegisterClass and UnregisterClass) and should be marked respectively with the ComRegisterFunction/ComUnregisterFunction attributes. Here we register the category of the ActiveX as a UI control.

4/ Write some thing to show the form

To show a form you need to start a message loop by calling Application.Run:
        [ComVisible(true)]
        public void Hello()
        {
            Application.Run(this);
            MessageBox.Show("Hello text", "Test");
        }

The Show() function will show the form and immediately exit. Application.Run() will not exit until the form is closed.

Now build the project. You will have dll and your dll has already been registered to System.

5/ Test

Open a text editor for writing about 4,5 lines of VBS code. I like notepad++  for Window and gedit for Ubuntu, but what you use is up to you.

Paste that code, save it as Test.vbs, run the file and see what happen.

Sub main
    set objTest = CreateObject("ActiveXTestLibrary.UserControl")
    objTest.Hello
    Do While (10 > 9)
    Loop
end Sub

call main

Figure 2 - C# form is called by vbs
Then click the button :)
Figure 3 - C# event is listened

Thanks for reading a very boring post. Here is your gift: my source code


See more : C# wrapper for Java class

Comments

Popular posts from this blog

New Admob for Android: Switching from Admob SDK to Google Play Services API

How to wrap a C# library for using in Java, a folk tale about an idiot coding at midnight.