Olav Aukan Getting information off the Internet is like taking a drink from a fire hydrant…

31Aug/10

Creating an ActiveX control in .Net using C#

A while back I had a client request that I write an ActiveX control for use on their corporate intranet. I had never done this before, and most of the examples I could find online were either really old, incomplete or based on using C++ and MFC. It's safe to say that my C++ skills are not quite up to the job, so for me it was really a requirement to be able to do this with C#. It took me about an hour or two to write the code for the control, but it took almost three days to successfully package and deploy it as a .cab file... So to save others from wasting their time like I did, I'll document my findings in this post.

Steps

  1. - Create a new Class Library project in Visual Studio
  2. - Create a new class that inherits from UserControl
  3. - Create a new interface that exposes the controls methods and properties to COM interop
  4. - Make the control class implement the new interface
  5. - Mark the control as safe for scripting and initialization
  6. - Create a .msi installer for the control
  7. - Package the control in a .cab file for web deployment
  8. - Initialize and test the control with JavaScript

1. Create a new Class Library project in Visual Studio

I'm using Visual Studio 2008, but other versions should work as well.

  1. After starting Visual Studio click File -> New -> Project and select Class Library under C#.
  2. Call the project 'AxControls' and click OK.

2. Create a new class that inherits from UserControl

  1. Rename 'Class1.cs' to 'HelloWorld.cs', making sure to rename the class name as well.
  2. Add a project reference to System.Windows.Forms.
  3. Make the HelloWorld class inherit UserControl.

3. Create a new interface that exposes the controls methods and properties to COM interop

  1. Right click the project in Visual Studio and click Add -> New Item.
  2. Select 'Interface' from the list of components, name it 'IHelloWorld.cs' and click Add.
  3. Edit the 'IHelloWorld.cs' file so it looks like this:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    
    namespace AxControls
    {
        [ComVisible(true)]
        [InterfaceType(ComInterfaceType.InterfaceIsDual)]
        [Guid("41E85D5D-C57A-4386-B722-4031D0B1E1B7")]
        public interface IHelloWorld
        {
            string GetText();
        }
    }
    

We now have a COM visible interface with a single method 'GetText()'.

[ComVisible(true)] makes the interface visible to COM.
[InterfaceType(ComInterfaceType.InterfaceIsDual)] sets the COM interface type to Dual, see InterfaceTypeAttribute Class on MSDN.
[Guid("41E85D5D-C57A-4386-B722-4031D0B1E1B7")] let's us manually assign a GUID to the interface. Use guidgen.exe to generate your own.

4. Make the control class implement the new interface

Make the HelloWorld class implement the IHelloWorld interface and have the GetText() method return a string of your choice. This is what the file might look like:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace AxControls
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [Guid("1FC0D50A-4803-4f97-94FB-2F41717F558D")]
    [ProgId("AxControls.HelloWorld")]
    [ComDefaultInterface(typeof(IHelloWorld))]
    public class HelloWorld : UserControl, IHelloWorld
    {
        #region IHelloWorld Members

        public string GetText()
        {
            return "Hello ActiveX World!";
        }

        #endregion
    }
}

We now have a COM visible control that implements the IHelloWorld interface.

[ComVisible(true)] makes the control visible to COM, see ComVisibleAttribute Class on MSDN.
[ClassInterface(ClassInterfaceType.None)] indicates that no class interface is generated for this class, see ClassInterfaceType Enumeration on MSDN.
[Guid("1FC0D50A-4803-4f97-94FB-2F41717F558D")] let's us manually assign a GUID to the control, see GuidAttribute Class on MSDN. Use guidgen.exe to generate your own.
[ProgId("AxControls.HelloWorld")] is a "user friendly" ID that we'll use later from JavaScript when initiating the control, see ProgIdAttribute Class on MSDN.
[ComDefaultInterface(typeof(IHelloWorld))] sets IHelloWorld as the default interface that will be exposed to COM, see ComDefaultInterfaceAttribute Class on MSDN.

5. Mark the control as safe for scripting and initialization

By default IE will not allow initializing and scripting an ActiveX control unless it is marked as safe. This means that we won't be able to create instances of our ActiveX class with JavaScript by default. We can get around this by modifying the browser security settings, but a more elegant way would be to mark the control as safe. Before you do this to a "real" control, be sure to understand the consequences. I found an ancient (1996) MSDN article that explains this here. We will mark the control as safe by implementing the IObjectSafety interface.

  1. Right click the project in Visual Studio and click Add -> New Item.
  2. Select 'Interface' from the list of components, name it 'IObjectSafety.cs' and click Add.
  3. Edit the 'IObjectSafety.cs' file so it looks like this:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    
    namespace AxControls
    {
        [ComImport()]
        [Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        interface IObjectSafety
        {
            [PreserveSig()]
            int GetInterfaceSafetyOptions(ref Guid riid, out int pdwSupportedOptions, out int pdwEnabledOptions);
    
            [PreserveSig()]
            int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions);
        }
    }
    
  4. Make the HelloWorld class implement the IObjectSafety interface. The end result should look something like this:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    namespace AxControls
    {
        [ComVisible(true)]
        [ClassInterface(ClassInterfaceType.None)]
        [Guid("1FC0D50A-4803-4f97-94FB-2F41717F558D")]
        [ProgId("AxControls.HelloWorld")]
        [ComDefaultInterface(typeof(IHelloWorld))]
        public class HelloWorld : UserControl, IHelloWorld, IObjectSafety
        {
            #region IHelloWorld Members
    
            public string GetText()
            {
                return "Hello ActiveX World!";
            }
    
            #endregion
    
            #region IObjectSafety Members
    
            public enum ObjectSafetyOptions
            {
                INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001,
                INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002,
                INTERFACE_USES_DISPEX = 0x00000004,
                INTERFACE_USES_SECURITY_MANAGER = 0x00000008
            };
    
            public int GetInterfaceSafetyOptions(ref Guid riid, out int pdwSupportedOptions, out int pdwEnabledOptions)
            {
                ObjectSafetyOptions m_options = ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_CALLER | ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_DATA;
                pdwSupportedOptions = (int) m_options;
                pdwEnabledOptions = (int) m_options;
                return 0;
            }
    
            public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
            {
                return 0;
            }
    
            #endregion
        }
    }
    

[ComImport()] IObjectSafety is a native interface so we have to redefine it for managed .Net use. This is done with the ComImport() attribute, see ComImportAttribute Class on MSDN.
[Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")] This is the GUID of the original IObjectSafety interface. Do not change it.
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] sets the COM interface type to Unknown, see InterfaceTypeAttribute Class on MSDN.

This is just a simple implemetation of the IObjectSafety interface that will mark the control as safe. In "real life" there would probably be some sort of logic to determine if the control is safe or not.

6. Create a .msi installer for the control

Before an ActiveX control can be used it must be installed and registered on the client. This can be done in a number of ways, from manually editing the registry to using regasm.exe, but we're going to create a Vistual Studio setup project to handle the installation for us.

  1. Right click the Visual Studio solution, select Add -> New Project and select Setup Project under Other Project Types.
  2. Call the project 'AxControlsInstaller' and click OK.
  3. Right click the 'AxControlsInstaller' project, select Add -> Project Output, select 'Primary output' from the 'AxControls' project and click OK.
  4. Right click 'Primary output from AxControls (Active)' and select Properties.
  5. Change the Register property from 'vsdrpDoNotRegister' to 'vsdrpCOM'.
  6. Right click the 'AxControlsInstaller' project and select Build.

The installer should now be located in the AxControlsInstaller's output folder (bin\Debug or bin\Release). In the corporate domain this .msi file can de run manually on the client, or automatically with a Group Policy.

7. Package the installer in a .cab file for web deployment

For public web sites we obviously can't deploy our ActiveX control to the client with a Group Policy. In this case we're gonna have to use Internet Explores built-in ability to download and install controls that are packaged in .cab files.

  1. Download the Microsoft Cabinet Software Development Kit.
  2. Unpack the kit to a local folder and copy Cabarc.exe to the 'AxControlsInstaller' folder.
  3. Create a new file named 'AxControls.inf' in the 'AxControlsInstaller' folder and add the following content:
    [version]
    signature="$CHICAGO$"
    AdvancedINF=2.0
    
    [Add.Code]
    AxControlsInstaller.msi=AxControlsInstaller.msi
    
    [AxControlsInstaller.msi]
    file-win32-x86=thiscab
    clsid={1FC0D50A-4803-4f97-94FB-2F41717F558D}
    FileVersion=1,0,0,0
    
    [Setup Hooks]
    RunSetup=RunSetup
    
    [RunSetup]
    run="""msiexec.exe""" /i """%EXTRACT_DIR%\AxControlsInstaller.msi""" /qn
    
  4. Click the AxControlsInstaller project and then click the Properties window (View -> Properties Window if it's not visible).
  5. Click the '...' button next to the PostBuildEvent property and add the following content:
    "$(ProjectDir)\CABARC.EXE" N "$(ProjectDir)AxControls.cab" "$(ProjectDir)AxControls.inf" "$(ProjectDir)$(Configuration)\AxControlsInstaller.msi"
    
  6. Right click the 'AxControlsInstaller' project and select Build.
  7. There should now be a 'AxControls.cab' file in the 'AxControlsInstaller' folder.

NB! Make sure you use ANSI encoding for the 'AxControls.inf' file or you will be unable to install the control.

8. Initialize and test the control with JavaScript

  1. Right click the AxControls solution, select Add -> New Project and select 'ASP.Net Web Application' under 'Web'.
  2. Call the project 'WebAppTest' and click OK.
  3. Right click the 'WebAppTest' project, select Add -> New Item and select 'HTML Page'.
  4. Call it 'index.html' and click OK.
  5. Add the following content to index.html:
    <html>
        <head>
    
            <object name="axHello" style='display:none' id='axHello' classid='CLSID:1FC0D50A-4803-4f97-94FB-2F41717F558D' codebase='AxControls.cab#version=1,0,0,0'></object>
    
          <script language="javascript">
    
            <!-- Load the ActiveX object  -->
            var x = new ActiveXObject("AxControls.HelloWorld");
    
            <!-- Display the String in a messagebox -->
            alert(x.GetText());
    
          </script>
        </head>
        <body>
        </body>
    </html>
    

    Note that 'classid' matches the GUID of the HelloWorld control.

  6. Right click 'index.html' and select 'Set as start page'.
  7. Right click the 'WebAppTest' project and select 'Set as startup project'.
  8. Copy 'AxControls.cab' from the 'AxControlsInstaller' folder to the same folder as index.html.
  9. Uninstall the control from the client by going to Control Panel -> Programs and Features, selecting 'AxControlsInstaller' on the list and clicking Uninstall. This forces Internet Explorer to download and install the .cab file and is an important step in case you've already installed the control.
  10. Run the application (F5). This will open 'index.html' in Internet Explorer.
  11. Internet Explorer will display a security warning, asking if you want to install 'AxControls.cab'. Click Install.
  12. When the page loads it should display a message box with the string you defined in HelloWorld's GetText() method.

If the message box displayed without any more warnings or errors we've implemented everyting correctly.

UPDATE

I forgot to write that you have to register the assembly containing the ActiveX control for COM interop. Right-click the project, select Properties, go to Build and check the "Register for COM interop" checkbox. This should solve the error some of you are seeing about "Automation Server can’t create this object" and similar error messages. You might need to add the [ComVisible(true)] attribute to the methods and properties you are exposing as well, but I haven't had time to test this.

Comments (1943) Trackbacks (8)
  1. Há um método que nos aquiesce avaliar nosso progresso
    na Fé e nosso aprimoramento místico.

  2. If you’ve ever typed an enquiry term into the Google search box, probable that you’ve noticed that Google automatically offers popular search suggestions as you type. For instance, if you begin typing the phrase “how to cut carrots,” after typing utilized “how” the suggestion “how to tie a tie” will appear, and so on. I do a involving searching with Google, there is nothing have often noticed humorous search methods.

    After that, how long you ought to keep trying to be able to seek help from a fertility specialist depends in large part on your real age. Fertility declines whenever you get older, so in case you are over 40, get the help an expert right besides. If you’re 35 to 40, speak with a specialist after you’ve tried for six months with no luck. And when you’re under 35, subjects as possible . fine keep trying for virtually any year before seeking company.

    The position during s e x is another contributing factor when referring to getting little one. The missionary position has proved to be unique position for girls who are looking for a way of getting pregnant need to know how to get pregnant faster!. It helps although it helps give the sperm closest to the cervix.

    You should likewise consider tracking your monthly period should you want to get pregnant prompt. You should track the era of your luteal phase. Keep record of your vaginal hot temperature. You should also take note of the cervical mucous. There is and a technique called “Ovulation Calculator” – this calculator could be very accurate.

    As time passed, my optimism begin to fade. Months turned with a year. We scheduled an appointment with our doctor. He examined both us extensively, and determined that. he simply didn’t know what was wrong! What’s worse than receiving a harmful diagnosis, you ask? How about being told from your doctor, those who is meant to have the answers, that your infertility does not have a explanation?

    And what’s more, there have been studies done that give us guidelines getting pregnant with a girl, a boy also twins. For you to the following links read more details.

    Do not use artificial lubricants during love making. These lubricants have chemicals that may damage sperm and stop pregnancy. If you do need a lubricant ask skilled to prescribe one.
    http://www.need.net.pk/pregnancy-tips-should-you-have-an-epidural/

  3. 『巻くだけで腹筋300回の効果』という部分痩せマシン「スレンダートーン」

    テレビCMでとっても魅力的なこの商品を、購入しようかな~?と悩んでいる人も多いのではないでしょうか。

    ベルトを巻いてスイッチを入れるだけで、本当に腹筋が引き締まるの?期待と効果がないかもと疑うのと半々です。

    試してみて、返品すればいいやと、39日間返品保証も気になるのですが、条件が厳しいのではと悩んでいませんか?

    実は条件は全然厳しくなくすんなり返品できるので、一度試してみても損はしませんよ。

  4. Доменное имя toramp.com было поставлено регистратором в состояние «clienthold», что делает его неработоспособным для пользователей.
    Наш НОВЫЙ домен: http://serialum.ru/

    власти России заблокировали ряд публичных анонсеров, во все торренты добавлены новые рабочие анонсеры, если ваши торренты перестали работать, перекачайте сами торрент файлы и ваш торрент клеинт должен автоматически добавить новые анонсеры

  5. Проститутки в Киеве https://hit.ua/site_view/108316 старые

  6. … киев cheat engine 6.2 скачать бесплатно kinopoisk сколько калорий в яблоке &quot … в хорошем качестве "бесплатно скачать фильмы сумерки 4" … мобильные сайты реальные пацаны "афто симулятор" gip ru ….. онлайн порно игра трахни звезду inurl:/gaestebuch.php cleaning караван убийство knigafund кинотеатр в …

  7. I besides think thence, perfectly indited post!

  8. Бренд Маленькая Леди – лидер российского производство в сфере одежды для девочек премиум класса.
    Школьные юбки, блузки, брюки, жакеты на девочку со скидкой до 70%! Распродажа школьной формы в самом разгаре!
    Шелковые блузки великопено сидят по фигуре девочки, стильные сарафаны формируют правильный силуэт.
    Самооценка ребенка – важная часть в формировании личности и успехов в дальнейшем! Качественная дизайнерская одежда
    Маленькая Леди – Ваш вклад в счастливое будущее своих детей.
    http://s011.radikal.ru/i316/1703/11/4fd2684e146f.jpg

  9. И натурального, зато длина в рулоне вдвое больше (30 м) . Более надежный, влаго и термостойкий обличие ротангового полотна получают из пластика. Имея чаще всего седой окраска, пластиковые http://www.liveinternet.ru/users/5719925/post409999913/ полотна выглядят не столь эффектно, сиречь натуральные и к тому же уступают им в плане.

  10. Community Communication Back this output admission to medical school

  11. I see your site needs some unique articles. Writing manually
    is time consuming, but there is solution for this hard task.
    Just search for; Miftolo’s tools rewriter

  12. coumadin valtrex interaction ecgeakgedgfb

  13. Здравствуйте, посетители сайта!
    Рекомендую необычный вебресурс,
    Профиль ресурса коды мобильных операторов.
    Вернее всего приемлимо.
    Всем удачи, друзья.
    Борис

  14. Здравствуйте, народ сетевой!
    Бросьте взгляд на увлекательный вебсайт: http://www.liveinternet.ru/users/5908616/post375738733 – как копировать с ютуба
    Хорошего времени суток в сети.
    Юрий

  15. Обратите внимание на увлекательный вебсайт: http://www.liveinternet.ru/users/5908616/post374495985 – правила поведения в интернете.
    Удачного дня.
    Коля

  16. Thanks for your personal marvelous posting! I truly enjoyed reading it, you will be
    a great author.I will ensure that I bookmark your blog and will eventually come back in the foreseeable future.
    I want to encourage yourself to continue your great work,
    have a nice evening!

  17. trust buy-cialis-online.review metformin expiration cialis generic pills women who take cialis pharmacy death

  18. Hey, sometimes I get a 404 message when I visit this page. I figured you would like to know.

  19. sawnacally saiuutlxfnt rkny fsgcbdeb

  20. In diesem Fall sind die Versorger der Versicherung nicht
    verpflichtet, mit dem Antragssteller den Vertrag abzuschließen.

  21. Looking for a car can take too much time. There are several cars you can try, and also a handful of considerations. Thus, you want solid data to ensure the process to get smooth. Keep this advice in your mind when you make an investment.

    Don’t forget to look into the fee for parts for any vehicle prior to buying it. Some cars, especially imports, cost considerably more to preserve as opposed to others. Investigate the cost of parts that break down frequently, such as tires, brakes, and windshield wiper blades. Research the expense of alternators, spark plugs, and also other engine components, too.

    Have a clear comprehension of what those upgrades costs. Buying the fancy stereo, leather seats and DVD player could possibly be appealing, but those options could add a substantial amount to the price tag on your car or truck. Take some time to think about exactly how much you actually need the upgrades, and simply get the ones you may make use of the most.

    Do not create the mistake of believing that you must pay for the full asking price to get a second hand car. There should invariably be room for negotiation. in case a car has become in the marketplace for a time with no buyers auto komis ruda śląska, that will make the owner more likely to accept a deal of lower than they are seeking.

    Have got a budget in mind before you go car shopping. This requires assessing your monthly income and bills, and achieving a precise idea of what you can really afford to increase those. Doing this will help you to stay in budget once you help make your new car purchase.

    Look for your brand-new car online prior to deciding to ever go to the dealership. Doing a search online lets you look at inventory from multiple dealerships, and it also causes you to privy to information about online only pricing. This really is a terrific way to comparison shop and extremely ensure you are getting the hottest deal.

    Don’t get a car online from someone without going and checking it out first. If you are not mechanically inclined, bring somebody that is. Be also wary of deals that seem too good to be real. People will make the most of you if you’re not good with cars, so attempt to take along somebody who is aware of them.

    Test drive more than one car before you purchase it. Any new car will almost certainly feel fantastic if you’re employed to driving a classic one. Think seriously about how exactly the ride feels, where buttons can be found, and how much of the highway you can actually see. Test-driving several car can help you realize where you wish to be.

    Don’t enable the salesperson know you will have a trade in until you have a good sales price at your fingertips. Some dealers will inflate the price once they think you’re trading in the vehicle, to allow them to provide you with a lot for the trade in, which is, then balanced with the new price they provide on the car they’re selling.

    Have a look at how much repairs on the car would cost before buying it. You must be able to get yourself a fair idea of what types of costs you will have to buy repairs. And that’s not only for after it is under warranty. What happens if you want to pay full price for an ignition coil? Different cars cost different amounts, so learn.

    Read before you sign. You might be getting in some serious trouble if you’re out there blindly signing money away. Your signature binds you legally, meaning you’ll be forced to pay or suffer severe consequences. You can carry it home along to see it. Should your salesman will not want to enable you to consider the contract home, there is probably some hidden clause they do not need you to discover more regarding.

    Investigate the laws where you live in terms of getting a bad car. There are many states which may have lemon laws. They may protect you buying a car that isn’t in great condition and being unable to have a refund. Not all the state has these laws, which explains why it is necessary you should do the research.

    A licensed used vehicle will not guarantee that this vehicle is at great condition. This is just a whole new technique for car dealers to trick people into thinking that they are guaranteed a top quality used vehicle. Tend not to be enticed by it. Research certified vehicles in the same way you might any other to completely protect yourself.

    If you are going to purchase an auto, you need to know up to you are able to prior to deciding to actually do it. Use these guidelines to drive away in something you’re happy in. They must assist you in making the very best decision on your car purchase.

  22. Hi, nice blog, speaking of Word-press plugins is anyone recommend a easy to install Clickbank plugin? A free plugin would be awesome – Thanks


Leave a comment