How to sink managed Visual C++ .NET or Visual C++ 2005 events in Internet Explorer script (816165)



The information in this article applies to:

  • Microsoft Visual C++ .NET (2003)
  • Microsoft .NET Framework 1.1
  • Microsoft Visual C++ 2005 Express Edition

For a Microsoft Visual Basic .NET version of this article, see 316516.
For a Microsoft Visual C# .NET version of this article, see 313891.
This article refers to the following Microsoft .NET Framework Class Library namespaces:
  • System::Runtime::InteropServices
  • System::ComponentModel

SUMMARY

This article describes how to sink Managed Visual C++ .NET or Visual C++ 2005 events in Microsoft Internet Explorer scripts. To do this, create a Windows Control Library (.NET) project, and then sink the managed control event in an Internet Explorer script.

IN THIS TASK

INTRODUCTION

This step-by-step article describes how to sink managed events from Component Object Model (COM) clients that use unmanaged code when you write Microsoft Visual Studio .NET or Microsoft Visual Studio 2005 Windows controls. For example, you sink managed events from COM clients when you run a script in Microsoft Internet Explorer.

For information about how to write and how to use managed types from COM, visit the following Microsoft Developer Network (MSDN) Web site:Back to the top

Requirements

The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:
  • Microsoft Visual Studio .NET 2003 or Microsoft Visual Studio 2005
  • Microsoft Internet Explorer (Programming) version 5.5 or later
Back to the top

Sink a managed event in an Internet Explorer script

To create a .NET control library, and to sink a managed control event in Internet Explorer script, follow these steps:
  1. Start Visual Studio .NET 2003 or Microsoft Visual Studio 2005 .
  2. On the File menu, click New, and then click Project.
  3. Under Project Types, click Visual C++ Projects, and then click Windows Control Library (.NET) under Templates.

    Note In Visual Studio 2005, click Visual C++ under Project Types, and then click Windows Forms Control Library under Templates.
  4. In the Name text box, type ControlLib, and then click OK. This creates the ControlLibControl control and opens the control in Design mode.
  5. Right-click ControlLibControl, and then click ViewCode.
  6. Add the following code after the using directives in the ControlLibControl.h file:
    using namespace System::Runtime::InteropServices;
  7. Define a source interface for the events to be exposed. To do this, add the following code inside the ControlLib namespace definition before the ControlLibControl class definition in the ControlLibControl.h file:
    //Source interface for events to be exposed.
    public __gc __interface ControlEvents
    {
    	void ClickEvent(int x, int y);
    };
  8. Add a GuidAttribute attribute to the source interface. You must format the string that you pass to the attribute as an acceptable constructor argument for the Guid type. You can use the Guidgen.exe file to create an unused GUID. To do this, add the following code above the interface that you defined in step 7:
    [GuidAttribute("0422D916-C11A-474e-947D-45A107038D14") ]
  9. Add an InterfaceTypeAttribute attribute to the source interface to expose COM as an IDispatch interface. To do this, add the following code before the source interface definition that you added in step 8 and after the GuidAttribute attribute that you added in step 8:
    [InterfaceTypeAttribute(ComInterfaceType::InterfaceIsIDispatch)]
  10. Add a DispIdAttribute attribute to any members in the source interface to specify the COM dispatch identifier (DISPID) of a method or a field. To do this, add the following code before the ClickEvent member of the source interface definition that you added in step 8:
    //Add a DispIdAttribute to any members in the source 
    //interface to specify the COM DispId.
    [DispIdAttribute(0x60020000)]
    Your code should appear as follows:
    [GuidAttribute("0422D916-C11A-474e-947D-45A107038D14") ]
    [InterfaceTypeAttribute(ComInterfaceType::InterfaceIsIDispatch)]
    //Source interface for events to be exposed.
    public __gc __interface ControlEvents
    {
    	//Add a DisIdAttribute to any members in the source 
    	//interface to specify the COM DispId.
    	[DispIdAttribute(0x60020000)]
    	void ClickEvent(int x, int y);
    };
  11. Create a new event type to wrap the event that you want to expose. To do this, follow these steps:
    1. Use the __delegate keyword to define a reference type with the same signature to encapsulate the source interface method. To do this, add the following code after the source interface definition in the ControlLib namespace:
      //define a reference type to encapsulate the interface method
      public __delegate void ClickEventHandler(int x, int y);
    2. By using the __event keyword, declare a managed event data member of the delegate type in the ControlLibControl class. To do this, add the following code:
      // declare a delegate type data member as event
      __event ControlLib::ClickEventHandler *ClickEvent;
  12. Add a ComSourceInterfaces attribute to the control class to identify the list of interfaces that are exposed as COM event sources. To do this, add the following code before the ControlLibControl class definition:
    //Add a ComSourceInterfaces attribute to the control to 
    //identify the list of interfaces that are exposed as COM event sources. 
    [ClassInterface(ClassInterfaceType::None),ComSourceInterfaces(__typeof(ControlEvents))]
  13. Add a dummy interface, and then implement the dummy interface in the ControlLibControl class. Add the following code before the ControlLibControl class definition in the ControlLib namespace:
    public __gc __interface MyDummyInterface
    {
    };
  14. To implement the MyDummyInterface interface in the ControlLibControl class, change the definition of the ControlLibControl class as follows:
    public __gc class ControlLibControl : public System::Windows::Forms::UserControl, public MyDummyInterface
  15. Add the following code to declare a TextBox control member in the ControlLibControl class:
    System::Windows::Forms::TextBox *tx;
  16. Replace the code in the ControlLibControl class constructor with the following code:
    InitializeComponent();
    tx = new System::Windows::Forms::TextBox();
    initControlLibControl();
  17. Add the following code in the InitializeComponent method:
    components = new System::ComponentModel::Container();
    this->Name = S"ControlLibControl";
  18. Add the following code after the InitializeComponent method in the ControlLibControl class:
    private: void initControlLibControl() 
    {
    	System::Drawing::Size size(300, 50);
    	Size = size;
    	tx->Text = "Click the TextBox to invoke  'ClickEvent'";
    	tx->Size = this->Size;                  
    	tx->Click += new System::EventHandler(this, ClickHandler);
    	this->Controls->Add(tx);
    }
    private: void ClickHandler(System::Object * sender, System::EventArgs *e)
    {
    	if (ClickEvent != 0) 
    	{
    		ClickEvent(0, 0);
    	}
    }
  19. Press CTRL+SHIFT+B to build the control as a DLL.
  20. Create a script block in the HTML to hook the event, and then save the HTML file in the folder that contains the DLL as follows:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=iso-8859-1' />
    
    <HTML>
    	<HEAD>
    		<TITLE>Sink managed event in Internet Explorer</TITLE>
    	</HEAD>
    	<BODY>
    	<OBJECT id="ctrl" classid="ControlLib.dll#ControlLib.ControlLibControl">
    	</OBJECT>
    	<SCRIPT LANGUAGE="JScript">
    		function ctrl::ClickEvent(a,b)
            	{
    			alert("ControlLibControl_ClickEvent");
            	}
    	</SCRIPT>
    		
    	</BODY>
    </HTML>
  21. On any client system, use the Microsoft .NET Framework Configuration tool (Mscorcfg.msc) to grant the assembly the individual permissions that are required. To do this, follow these steps:
    1. Start the .NET Framework configuration tool, Mscorcfg.msc.
    2. Expand each element in the following path:

      My Computer/Runtime Security Policy/Machine/Code Groups/All_Code/LocalIntranet_Zone

    3. Right-click All_Code, and then click New.
    4. On the Identify the new Code Group page of the Create Code Group wizard, type Q816165 in the Name box, and then click Next.
    5. In the Choose the condition type for this code group list, click URL.
    6. Type the URL of the folder in the Web Server that contains the .dll file, and then click Next.
    7. Click Use existing permission set, and then click FullTrust.
    8. Click Next, and then click Finish.
  22. Browse the HTML file that you just created, and then click the Textbox control.

    Note You must create a virtual directory in Internet Information Services (IIS) that points to the folder that contains the HTML file and the .dll file, and then look through the HTML file.
Back to the top

Complete code listing

#pragma once

using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Runtime::InteropServices;


namespace ControlLib
{
    [GuidAttribute("0422D916-C11A-474e-947D-45A107038D14") ]
    [InterfaceTypeAttribute(ComInterfaceType::InterfaceIsIDispatch)]
    //Source interface for events to be exposed.
    public __gc __interface ControlEvents
    {
        //Add a DispIdAttribute to any members in the source 
        //interface to specify the COM DispId.
        [DispIdAttribute(0x60020000)]
        void ClickEvent(int x, int y);
    };

    //Define a reference type to encapsulate the interface method.
    public __delegate void ClickEventHandler(int x, int y);
    /// <summary> 
    /// Summary for ControlLibControl
    /// </summary>
    ///
    /// WARNING: If you change the name of this class, you must change the 
    ///          'Resource File Name' property for the managed resource compiler tool 
    ///          associated with all .resx files this class depends on.  Otherwise,
    ///          the designers will not be able to interact correctly with localized
    ///          resources associated with this form.
    public __gc __interface MyDummyInterface
    {
    };
    //Add a ComSourceInterfaces attribute to the control to 
    //identify the list of interfaces that are exposed as COM event sources.
    [ClassInterface(ClassInterfaceType::None),ComSourceInterfaces(__typeof(ControlEvents))]
    public __gc class ControlLibControl : public System::Windows::Forms::UserControl, public MyDummyInterface
    {
    public:
        ControlLibControl(void) 
        {
            InitializeComponent();
            tx = new System::Windows::Forms::TextBox();
            initControlLibControl();
        }
        
    protected:
        void Dispose(Boolean disposing) 
        {
            if (disposing && components)
            {
                components->Dispose();
            }
            __super::Dispose(disposing);
        }
        
    private:
        /// <summary>
        /// Required designer variable.
        /// </summary>
        System::ComponentModel::Container* components;
        System::Windows::Forms::TextBox *tx;
        // Declare a delegate type data member as event.
        __event ControlLib::ClickEventHandler *ClickEvent;
        
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        void InitializeComponent(void)
        {
            components = new System::ComponentModel::Container();
            this->Name = S"ControlLibControl";
        }
        private: void initControlLibControl() 
        {
            System::Drawing::Size size(300, 50);
            Size = size;
            tx->Text = "Click the TextBox to invoke  'ClickEvent'";
            tx->Size = this->Size;                  
            tx->Click += new System::EventHandler(this, ClickHandler);
            this->Controls->Add(tx);
        }
        private: void ClickHandler(System::Object * sender, System::EventArgs *e)
        {
            if (ClickEvent != 0) 
            {
                ClickEvent(0, 0);
            }
        }
    };
}
Note You must add the common language runtime support compiler option (/clr:oldSyntax) in Visual C++ 2005 to successfully compile this code sample. To do this, follow these steps:
  1. Click Project, and then click ProjectName Properties.

    Note ProjectName represents the name of the project.
  2. Expand Configuration Properties, and then click General.
  3. Click to select Common Language Runtime Support, Old Syntax (/clr:oldSyntax) in the Common Language Runtime support project setting on the right pane, click Apply, and then click OK.
For more information about the common language runtime support compiler options, visit the following Microsoft Web site:

/clr (Common language runtime compilation)
http://msdn2.microsoft.com/en-us/library/k8d11d4s.aspx

Back to the top

REFERENCES

For more information, visit the following Microsoft Developer Network (MSDN) Web sites:

Host secure, lightweight client-side controls in Microsoft Internet Explorer
http://msdn.microsoft.com/msdnmag/issues/02/01/UserCtrl/default.aspx

For additional information, click the following article numbers to view the articles in the Microsoft Knowledge Base:

316510 PRB: Security exception when you use event handlers in Internet Explorer

814664 PRB: ActiveX error when you sink managed events in Internet Explorer script

Back to the top

Modification Type:MajorLast Reviewed:1/5/2006
Keywords:kbhtml kbCOMInterop kbinterop kbEvent kbHOWTOmaster KB816165 kbAudDeveloper