Page 1 of 1

ActiveX with C#

#1 skaoth  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 91
  • View blog
  • Posts: 601
  • Joined: 07-November 07

Posted 06 December 2007 - 03:17 AM

Creating activex objects with c#
--------------------------------------

The purpose of this guide is to provide simple steps for
creating a simple ActiveX Control that can be loaded and used within an IE
hosted web page.

Background
--------------

ActiveX is a Microsoft technology used for creating
re-usable components. This technology, also called Object Linking and Embedding
(OLE), along with COM is heavily used within the Microsoft environment and
application development. For the duration of this article, I will use the term
COM to encompass all similar Microsoft related technologies: ActiveX, OLE,
Automation, etc… as it is the framework by which components are created. Anyone
interested in creating reusable components should have some familiarity with
COM. A very good resource is “Essential COM” by Don Box.

The idea behind COM is to allow the creation of components
that can be consumed by a variety of clients. This means that I can create a
component using C++ which can then be used by an application written in VB, or
even a web page which we will be performing shortly. Traditionally, ActiveX
objects were usually written in C++ and VB but can actually be written in any
language as long as they are COM-aware.

This means that we can create COM objects with the .NET
platform. A survey of resources/tutorials on COM and .NET on the internet by and
large only tell you how to consume unmanaged COM objects via Interop. So my aim
with this guide is to show how to use this powerful feature. Also, FYI, there is
a .NET technology very similar to what will be describe below which allows
hosting Windows Forms Controls inside of IE (don’t know the official term/name
for this).

That’s enough babbling lets get going with the example.

Requirements

* Familiarity with C#.
* Development Environment. I will be using Visual Studio
2005. (2003 should also work. Don’t know about the express editions though.)

* HTML, Javascript
* IE. ActiveX objects cannot be hosted in any other
browser.

Creating the ActiveX Control
-----------------------------------

The first step is to create a C# DLL Project. This can be
done with the following steps:

1. Launch Visual Studio
2. Select File -> NewProject
1. Select “Other Language” -> “Visual C#” for the project type
2. Select “Class Library” template

When the project is created, go ahead and rename Class1.cs
to whatever you want. I renamed it to HelloControl.cs

The ActiveX control we will be creating is the ubiquitous
hello world! The code and explanation follow.

HelloControl.cs

using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;

namespace csharp.activex.sample
{
	/// <summary>
	/// A very simple interface to test ActiveX with.
	/// </summary>
	[
		Guid( "E86A9038-368D-4e8f-B389-FDEF38935B2F"),
		InterfaceType( ComInterfaceType.InterfaceIsDual),
		ComVisible( true)
	]
	public interface IHello
	{
		[DispId(1)]
		string Hello();
		
		[DispId(2)]
		int ShowDialog(string msg);
	};

	[
		Guid("873355E1-2D0D-476f-9BEF-C7E645024C32"),

		// This is basically the programmer friendly name
		// for the guid above. We define this because it will
		// be used to instantiate this class. I think this can be
		// whatever you want. Generally it is
		// [assemblyname].[classname]
		ProgId("csharpAx.CHello"),

		// No class interface is generated for this class and
		// no interface is marked as the default.
		// Users are expected to expose functionality through
		// interfaces that will be explicitly exposed by the object
		// This means the object can only expose interfaces we define
		ClassInterface(ClassInterfaceType.None),

		// Set the default COM interface that will be used for
		// Automation. Languages like: C#, C++ and VB
		// allow to query for interface's we're interested in
		// but Automation only aware languages like javascript do
		// not allow to query interface(s) and create only the
		// default one
		ComDefaultInterface(typeof(IHello)),
		ComVisible(true)
	]
	public class CHello : IHello
	{

		#region [IHello implementation]
		public string Hello()
		{
			return "Hello from CHello object";
		}


		public int ShowDialog(string msg)
		{
			System.Windows.Forms.MessageBox.Show(msg, "");
			return 0;
		}
		#endregion
	};
}



The HelloControl.cs file consists of one class and one interface.
So let’s start with the interface definition and follow up with the CHello class.

**IHello Interface**

An interface is generally described as a contract. Once an interface is designed
and published for use it should NEVER change. Let me repeat this, it
should NEVER change.

Several attributes have been defined for this interface.

1) Guid – This is a unique identifier. Use guidgen.exe to generate your own
2) InterfaceType – This determines which base class to expose to COM.

The InterfaceType attribute demands a little further explaination. Here is how it is defined.

public enum ComInterfaceType
{
	InterfaceIsDual = 0,
	InterfaceIsIUnknown = 1,
	InterfaceIsIDispatch = 2,
}



All COM interfaces and objects must at a minimum inherit the IUnknown
interface (see Appendix A.). This interface allows clients to create the COM
objects via CoCreateInstance() and search for other interfaces along with
handling object lifetime management.

The IDispatch interface allows objects to be used in Automation-aware only
languages like javascript (see Appendix B.). This interface, allows for client
applications to query for properties and methods that the object supports at run-
time and execute them. This is very much like Reflection in .Net.

Dual simply means a combination of the two above. The main reason for this is to
allow the interface to be created without all of the overhead that IDispatch has
in situations where it’s not needed.

Lastly, you will notice the DispId(#) attribute for each method in the IHello
interface. This is needed when calling Invoke from the IDispatch interface.

**CHello class**

The last thing to discuss is the CHello class. This class simple implements
the IHello interface and nothing more. The ShowDialog() simply shows that we can
execute objects that require some sort of UI, in this case a messagebox.
The attributes are described in the comments.

Compiling & Registering
----------------------------

Once the code is written up go ahead an compile the ActiveX assembly.
The assembly will be called [projectname].dll inside the bin folder of the project.

The next step is to register. Do this opening up a command prompt and go to the
location of the dll. To register the assembly type:


C:\Regasm [projectname].dll /codebase /tlb


Make sure replace “[projectname]” with the correct name of your dll.
You should get some output that says the assembly was exported correctly.
Something like the following.


Microsoft ® .NET Framework Assembly Registration Utility 2.0.50727.42
Copyright © Microsoft Corporation 1998-2004. All rights reserved.
Types registered successfully
Assembly exported to '[TLB location]
', and the type library was registered successfully


To unregister the assembly pass the “/unregister” flag to Regasm. You will need to
unregister and close IE when changes need to be made to the assembly. If you don’t
unregister your assembly prior to making code changes you may end up with bogus
registry entries and a pain to clean up. The reason for closing IE is to make sure
that all reference to your assembly have been released.

Creating HTML Test Page
-----------------------------

We are just about done. All we need to do now is create a test page.
This should be really simple, but here it is nonetheless. The Javascript
to create the ActiveX object is also provided.

Test.html

<html xmlns="http://www.w3.org/1999/xhtml">
<head> <title>C# ActiveX Test</title> </head>

<body onload="myload();">
<h1>This is Our ActiveX Test Page h1>

The message from the ActiveX Control is [
<div id="axmsg"></div>
]

<script type ="text/javascript">
function myload()
{
	var myAx = new ActiveXObject("csharpAx.CHello");
	if(myAx != null)
	{
		myAx.ShowDialog("hello from asp.net"); 
		var d = document.getElementById("axmsg");
		
		var s = myAx.Hello();
		d.outerText = s;
	}
	else
		lert("NOOOO... we failed");
}
</script>
</body></html>



To create our ActiveX object in Javascript we use the ActiveXObject(). The parameter
for this is generally the PROGID that we specified in its definition. If a
PROGID was not specified in its definition then I think you can pass in
“AssemblyName.ClassName”. The rest of the javascript simply calls our ActiveX
objects methods.

That’s it!!! We should have a fully functional example. This ability to execute ActiveX
objects from javascript is very powerful. Debates and arguments about security
and safety of ActiveX objects are well known and I will not throw more fodder
to the fire. However, imagine creating a Win32 or even a Winform application
where the UI is written in HTML via IWebBrowser2 and all the UI interaction handled
with your ActiveX object, just food for thought. Though, now that I think of it,
WPF is already doing this. Oh Well.

Hopefully you found this guide on how to create an ActiveX object with C# helpful.

-skaoth-


Further Modifications
-------------------------

The example above, though complete (hopefully error free), has one slight problem. When the html page is
loaded we get a nasty message box saying

“An ActiveX control on this page might be unsafe…blah blah blah”

So how do we fix this? Well it is quit simple really. We need to Implement an interface
called IObjectSafety. To do this, add a new .cs file to the project.

IObjectSafety.cs

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Text;

namespace csharp.activex.sample
{
	[
		Serializable,
		ComVisible(true)
	]
	public enum ObjectSafetyOptions
	{
		INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001,
		INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002,
		INTERFACE_USES_DISPEX = 0x00000004,
		INTERFACE_USES_SECURITY_MANAGER = 0x00000008
	};

	//
	// MS IObjectSafety Interface definition
	//
	[
		ComImport(),
		Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"),
		InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
	]
	public interface IObjectSafety
	{
		[PreserveSig]
		long GetInterfaceSafetyOptions( ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions);

		[PreserveSig]
		long SetInterfaceSafetyOptions( ref Guid iid, int dwOptionSetMask, int dwEnabledOptions);
	};

	//
	// Provides a default Implementation for
	// safe scripting.
	// This basically means IE won't complain about the
	// ActiveX object not being safe
	//
	public class IObjectSafetyImpl : IObjectSafety
	{
		private ObjectSafetyOptions m_options =
			ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_CALLER | 
			ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_DATA;

		#region [IObjectSafety implementation]
		public long GetInterfaceSafetyOptions( ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions)
		{
			pdwSupportedOptions = (int)m_options;
			pdwEnabledOptions = (int)m_options;
			return 0;
		}

		public long SetInterfaceSafetyOptions(ref Guid iid, int dwOptionSetMask, int dwEnabledOptions)
		{
			return 0;
		}
		#endregion
	};
}



Then modify the CHello object so that it inherits from the IObjectSafetyImpl
class so that it looks like

public class CHello : IObjectSafetyImpl, IHello
{
…
};


With that, the dialog about the ActiveX object not being safe should disappear.

References
--------------

ATL Internals – Brent E. Rector, Chris Sells.
Essential COM – Don Box.


http://msdn2.microso...yw6(VS.80).aspx
http://msdn2.microso...y/aa768224.aspx
http://www.c-sharpco...tiveXInNet.aspx

Appendix A: IUnknown
----------------------------

interface IUnknown
{
virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) = 0;
virtual ULONG AddRef(void) = 0;
virtual ULONG Release(void) = 0;

};

Appendix B: IDispatch
---------------------------

interface IDispatch : public IUnknown
{
virtual ULONG GetTypeInfoCount(unsigned int FAR* pctinfo) = 0;
virtual HRESULT GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo ) = 0;
virtual ULONG GetIDsOfNames(
REFIID riid,
OLECHAR FAR* FAR* rgszNames,
unsigned int cNames,
LCID lcid,
DISPID FAR* rgDispId) = 0;
virtual ULONG Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS FAR* pDispParams,
VARIANT FAR* pVarResult,
EXCEPINFO FAR* pExcepInfo,
unsigned int FAR* puArgErr) = 0;
};

Is This A Good Question/Topic? 1
  • +

Replies To: ActiveX with C#

#2 gummi_  Icon User is offline

  • New D.I.C Head

Reputation: -1
  • View blog
  • Posts: 1
  • Joined: 29-July 08

Posted 29 July 2008 - 06:57 AM

This one is actually working :^:
Allthough I had to put my page to Trusted Sites and lower the safetylevel to the lowest using ie7.

Request: It would be super if you could write about making the above not nescessary. And how to make a .cab for this ActiveX (I can't get it to work).

Instead of using regasm I:
1. Added a setup project to my sollution.
2. Added project primary output from the ActiveX-project in my setup project.
3. Changed a property on the primary output in my setup project to Register: vsdrpCOM.
4. Built the setup project
5. Installed it with the setup created in bin-directory.

This post has been edited by gummi_: 29 July 2008 - 06:57 AM

Was This Post Helpful? -1
  • +
  • -

#3 yiannisezn  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 03-September 08

Posted 03 September 2008 - 01:51 AM

Did you have any luck finding a solution about putting your page to Trusted Sites and lower the safetylevel to the lowest using ie7?

If you have any clues about it, please share them.
Was This Post Helpful? 0
  • +
  • -

#4 grhind  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 07-October 08

Posted 07 October 2008 - 09:05 AM

This works wonderfully but what about having ActiveX object cause an event that javascript understands? I've been searching for an example in VB.NET and either javascript or VBScript
Was This Post Helpful? 0
  • +
  • -

#5 Guest_wwwboy*


Reputation:

Posted 14 April 2009 - 07:10 AM

I need to have some validations on a page document from my ActiveX control
Is there a way to get browser object from SetSite method?

Thanks
Was This Post Helpful? 0

#6 palpriye  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 08-May 09

Posted 11 May 2009 - 10:41 PM

Hello sir ,
This is Priya Ranjan.I am in the team who is developing Activex based project.During our course of projrct,we succeed with a warninig(An activex control on this page might be unsafe.....)which u have suggested in your coloumn.I have taken a simple application to implement that .But stilll I am getting the same warning.Could you please help me that where I am lagging.I have followed those steps given by you.

thanks and regard.

my code snippet is as follows.

HelloClass.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;


namespace Activex
{
    public interface IHello
    {
        string fname();
        string lname();
        int age();

    }
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public class HelloClass : IObjectSafetyImpl,IHello
    {
        public string fname()
        {
            return "Priye";
        }
        public string lname()
        {
            return "Ranjan";
        }
        public int age()
        {
           return 25;
        }
    }
}



then register it by regasm


now html file
-----------------

hellotest.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>activex sample</title>
  <script type="text/javascript">
   
    var x = new ActiveXObject("Activex.HelloClass");

    <!-- Access the Method -->
    alert(x.fname());
    alert(x.lname());

    <!-- Access the Property -->
    alert(x.Age);
  </script>
</head>
<body>
<h1>this is an active x</h1>
</body>
</html>



then i have added .cs file for IObjectSafety implementation


IObjectSafety.cs
--------------------
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Text;

namespace Activex
{
    [
        Serializable,
        ComVisible(true)
    ]
    public enum ObjectSafetyOptions
    {
        INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001,
        INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002,
        INTERFACE_USES_DISPEX = 0x00000004,
        INTERFACE_USES_SECURITY_MANAGER = 0x00000008
    };

    //
    // MS IObjectSafety Interface definition
    //
    [
        ComImport(),
        Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"),
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
    ]
    public interface IObjectSafety
    {
        [PreserveSig]
        long GetInterfaceSafetyOptions(ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions);

        [PreserveSig]
        long SetInterfaceSafetyOptions(ref Guid iid, int dwOptionSetMask, int dwEnabledOptions);
    };

    //
    // Provides a default Implementation for
    // safe scripting.
    // This basically means IE won't complain about the
    // ActiveX object not being safe
    //
    public class IObjectSafetyImpl : IObjectSafety
    {
        private ObjectSafetyOptions m_options =
            ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_CALLER |
            ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_DATA;

        #region [IObjectSafety implementation]
        public long GetInterfaceSafetyOptions(ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions)
        {
            pdwSupportedOptions = (int)m_options;
            pdwEnabledOptions = (int)m_options;
            return 0;
       }
        public long SetInterfaceSafetyOptions(ref Guid iid, int dwOptionSetMask, int dwEnabledOptions)
        {
            return 0;
        }
        #endregion
    };
}



and finally added the implementation part in HelloClass.cs file
Was This Post Helpful? 0
  • +
  • -

#7 phoeniX_  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 25
  • Joined: 04-August 09

Posted 10 August 2009 - 02:47 AM

Nice tutorial. Thanks!
Was This Post Helpful? 0
  • +
  • -

#8 ArneHB  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 26-October 09

Posted 26 October 2009 - 05:58 AM

Very nice tutorial!

However I'm getting the error message "Microsoft JScript runtime error: Automation server can't create object" when I'm trying to run the var myAx = new ActiveXObject("csharpAx.CHello");. I've added localhost to my trusted site and lovered the security.
Was This Post Helpful? 0
  • +
  • -

#9 maxpanella  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 31-October 09

Posted 31 October 2009 - 02:09 AM

Debug this Activex ??
Hello I try to attach debug to Iexporer Process but the debug do not start.

How I can do this ?
Was This Post Helpful? 0
  • +
  • -

#10 ummarbhutta  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 23-November 09

Posted 23 November 2009 - 10:04 AM

Thanks for this great article.. using your code as my baseline I have developed an ActiveX control and have signed it with a test certificate every this is working fine but problem is that My internet explorer shows an ugly message The website wants to run following add-on: 'Not Available' from 'Control name is not available', If you trust the website and the add-on and want to allow it to run, click here.... Why the control name is not available? I have added the attribute ComVisible to my assemblyInfo.cs, here is the code of Assembly
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Permissions;
using System.Runtime.InteropServices;
//// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: System.Runtime.InteropServices.ComVisible(true)]
[assembly: AssemblyTitle("My ActiveX Control")]
[assembly: AssemblyDescription("My ActiveX Control Description")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("CompanyXYZ")]
[assembly: AssemblyProduct("My ActiveX Control")]
[assembly: AssemblyCopyright("2009")]
[assembly: AssemblyTrademark("CompanyXYZ")]
[assembly: AssemblyCulture("")]
		 //// Version information for an assembly consists of the following four values:
////	  Major Version
//	  Minor Version 
//	  Build Number
//	  Revision
//// You can specify all the values or you can default the Revision and Build Numbers 
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.1")]

Pleasse help me out
Was This Post Helpful? 0
  • +
  • -

#11 Guest_Michael*


Reputation:

Posted 18 February 2010 - 01:51 PM

Great article!
Is possible call a js function from activex?
Was This Post Helpful? 0

#12 Guest_ummarbhutta*


Reputation:

Posted 19 February 2010 - 12:05 AM

View PostMichael, on 18 February 2010 - 12:51 PM, said:

Great article!
Is possible call a js function from activex?

It is preferable that you call the activex function from java script, and its quiet simple.. but the reverse I have tried lot with no success.. I was able to call a JS function from ActiveX in only one case that the JS call an activex function and in the same call the activex calls the JS function...
Was This Post Helpful? 0

#13 Guest_Maxpanella*


Reputation:

Posted 19 February 2010 - 11:50 AM

View PostMichael, on 18 February 2010 - 12:51 PM, said:

Great article!
Is possible call a js function from activex?

Yes you can ;)
see onclose of activex function

http://www.codeproje...iveXDotNet.aspx

please help me for activex debug !!
Was This Post Helpful? 0

#14 Guest_Robert*


Reputation:

Posted 19 July 2010 - 12:46 AM

Nice, this was very helpfull for me. I was searching for this like 2 hours. thanks a lot
Was This Post Helpful? 0

Page 1 of 1