Walkthrough: Creating a Proxy Assembly

This walkthrough demonstrates how to create a proxy assembly from an existing managed object model by using the Proxy Generation tool (ProxyGen.exe). The steps in this walkthrough use the object model of the managed ShapeApp sample application.

Visual Studio Tools for Applications enables add-ins to communicate with the host application through the use of proxies that represent the types in the object model of the host application. Creating the proxy assembly is usually the first step in integrating Visual Studio Tools for Applications into your host application.

For more information about the process, see Overview of Integrating Visual Studio Tools for Applications. For more information about proxies, see Creating Proxies. For more information about the ShapeApp sample applications, see ShapeApp Samples (Visual Studio Tools for Applications).

You can use this walkthrough as a stand-alone walkthrough, or you can use it as part of the series of walkthroughs described in Walkthrough: Integrating Visual Studio Tools for Applications with ShapeApp.

This walkthrough illustrates the following tasks:

  • Creating a proxy descriptor file.

  • Specifying an entry point.

  • Creating a proxy code file.

  • Creating a project for the proxy assembly.

  • Completing the definitions of proxies for exceptions.

  • Creating proxies for structs.

  • Signing and building the proxy assembly.

Prerequisites

You need the following components to complete this walkthrough:

  • Visual Studio 2008.

  • Microsoft Visual Studio Tools for Applications 2.0.

  • The built ShapeAppCSharp sample (that is, the version of the ShapeAppCSharp sample that has no Visual Studio Tools for Applications modifications). This walkthrough assumes that you have extracted the ShapeAppCSharp sample to drive:\ShapeAppSamples\ShapeAppCSharp. For more information, see How to: Build and Run the ShapeAppCSharp Sample.

    Note

    When you build the ShapeAppCSharp sample, an executable file named ShapeAppCSharp.exe is created in the drive:\ShapeAppSamples\ShapeAppCSharp\core\bin\Debug directory. You will use this executable file in this walkthrough.

Creating a Proxy Descriptor File

Use ProxyGen.exe to generate a proxy descriptor file for the object model of ShapeAppCSharp. The proxy descriptor file is an XML representation of the host object model. You need to modify this file before you can use it to generate the final code file, which is described later in this walkthrough. For more information about the format of the XML, see ProxyGen Descriptor Schema Reference.

To generate a proxy descriptor file

  1. Create a subfolder in the drive:\ShapeAppSamples\ShapeAppCSharp\ directory and name it proxy.

  2. Open a Command Prompt window and run the following command to change the path to the installation folder of the Visual Studio Tools for Applications SDK.

    cd "%ProgramFiles%\Visual Studio Tools for Applications 2.0 SDK\build number\Visual Studio Tools For Applications\Tools\ProxyGen"
    

    This path assumes you installed the Visual Studio Tools for Applications SDK to the default directory. Make sure that you replace build number with the current build of the Visual Studio Tools for Applications SDK you have installed.

  3. Type the following command at the command prompt and then press ENTER.

    proxygen.exe /l:"%SYSTEMDRIVE%\ShapeAppSamples\ShapeAppCSharp\core\bin\Debug\ShapeAppCSharp.exe" /o:"%SYSTEMDRIVE%\ShapeAppSamples\ShapeAppCSharp\proxy\ShapeAppCSharpOM.xml" /f
    

    A proxy descriptor file named ShapeAppCSharpOM.xml is created in the %SYSTEMDRIVE%\ShapeAppSamples\ShapeAppCSharp\proxy folder. For more information about the command arguments that are available for ProxyGen.exe, see Proxy Generation Tool (ProxyGen.exe).

Specifying an Entry Point and Excluding Structs

You must specify at least one type in the proxy descriptor file as an entry point (also called a host item). An entry point is a type that is instantiated when the host application loads the add-in. For more information, see Defining Entry Points and Other Proxy Changes.

Also mark the Color, Point, and Size structs as excluded in the proxy descriptor file. Marking these as excluded prevents ProxyGen.exe from generating proxies for them. Later in this walkthrough, you will manually define proxies for these structs to enable them to be serialized correctly between ShapeApp and add-ins. For more information, see Creating Proxies for Managed Structs.

To specify an entry point and exclude the structs

  1. Open ShapeAppCSharpOM.xml in a text editor and search for the following Class element.

    <Class originalFullyQualifiedName="Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp.Application" isExcluded="false" isAddInEntryPoint="false">
    
  2. Set the isAddInEntryPoint attribute to true.

    isAddInEntryPoint="true"
    
  3. Search for the following Color element.

    <Struct originalFullyQualifiedName="Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp.Color" isExcluded="false">
    
  4. Set the isExcluded attribute to true.

    isExcluded="true"
    
  5. Search for the following Point element.

    <Struct originalFullyQualifiedName="Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp.Point" isExcluded="false">
    
  6. Set the isExcluded attribute to true.

    isExcluded="true"
    
  7. Search for the following Size element.

    <Struct originalFullyQualifiedName="Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp.Size" isExcluded="false">
    
  8. Set the isExcluded attribute to true.

    isExcluded="true"
    
  9. Save and close ShapeAppCSharpOM.xml.

Creating a Proxy Code File

Now you can use ProxyGen.exe to generate a proxy code file for the object model of ShapeAppCSharp. The proxy code file defines proxy types that correspond to each of the types that are defined in the proxy descriptor file.

To generate a proxy code file

  • Type the following command at the command prompt and then press ENTER.

    proxygen.exe /c:"%SYSTEMDRIVE%\ShapeAppSamples\ShapeAppCSharp\proxy\Proxy.cs" /i:"%SYSTEMDRIVE%\ShapeAppSamples\ShapeAppCSharp\proxy\ShapeAppCSharpOM.xml" /f
    

    A proxy code file named Proxy.cs is created in the %SYSTEMDRIVE%\ShapeAppSamples\ShapeAppCSharp\proxy folder. ProxyGen.exe also displays warnings about being unable to load several types, such as System.Drawing.Color and System.Windows.Forms.IWin32Window. These warnings are expected, because these are types that are defined outside of the assembly that you passed to ProxyGen.exe. In the following procedure, you will add references to the assemblies that define these types when you create the project to compile the proxy code.

    Note

    ProxyGen.exe also generates a code file named Proxy.HostTypeMapProvider.cs. You will not use this code file in this walkthrough. This file contains a type map provider class that can be used with code that discovers and loads add-ins for the host application. For more information, see Mapping Host Types to Proxy Types and Walkthrough: Modifying an Application to Load Add-Ins.

Creating a Project for the Proxy Assembly

Project templates require a proxy assembly that is compiled from the proxy code file (Proxy.cs). Create a project in Visual Studio to use to compile the assembly. For more information about project templates, see Creating Project Templates (Visual Studio Tools for Applications).

To create a project for the proxy assembly

  1. Open the ShapeAppCSharp solution in Visual Studio.

  2. Right-click the ShapeAppCSharp solution node in Solution Explorer, point to Add, and then click New Project.

    The Add New Project dialog box appears.

  3. In the Project types pane, expand Visual C#, and then click Windows.

  4. In the Templates pane, select Class Library.

  5. In the Name box, type ShapeAppCSharpProxy, and then click OK.

  6. In Solution Explorer, right-click the Class1.cs file under ShapeAppCSharpProxy and click Delete.

  7. In Solution Explorer, right-click ShapeAppCSharpProxy, point to Add, and then click Existing Item.

  8. Navigate to the drive:\ShapeAppSamples\ShapeAppCSharp\proxy directory, select the Proxy.cs file that you created by using ProxyGen.exe, and then click Add.

  9. In Solution Explorer, right-click ShapeAppCSharpProxy, and then click Add Reference.

    The Add Reference dialog box opens.

  10. On the .NET tab, select the following assemblies:

    • Microsoft.VisualStudio.Tools.Applications.Runtime.v9.0

    • System.AddIn (version 3.5)

    • System.Drawing

    • System.Windows.Forms

  11. Click OK to close the Add Reference dialog box.

Completing the Definitions of Proxies for Exceptions

ShapeAppCSharp defines two custom exceptions named LocationInvalidException and SizeInvalidException. Because ProxyGen.exe generates only portions of exception types in the proxy code file, you must define the missing members for these two exceptions. Define these members in a separate code file.

For more information, see Creating Proxies for Custom Exceptions.

To complete the definitions of proxy exceptions

  1. In Solution Explorer, right-click ShapeAppCSharpProxy, point to Add, and then click Class.

  2. In the Name box, type Proxy.ExceptionSerialization.cs, and then click Add.

  3. Replace the contents of the Proxy.ExceptionSerialization.cs file with the following code. This code defines the missing serialization members of LocationInvalidException and SizeInvalidException.

    namespace Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp
    {
        using System;
        using System.Runtime.Serialization;
        using System.Security.Permissions;
    
        [Serializable]
        public partial class LocationInvalidException
        {
            public LocationInvalidException(string message, Exception innerException)
                : base(message, innerException)
            { }
    
            public LocationInvalidException(string message, Point invalidLocation)
                : base(message)
            {
                this.invalidLocation = invalidLocation;
            }
    
            protected LocationInvalidException(SerializationInfo info, StreamingContext context)
                : base(info, context)
            {
                this.invalidLocation = (Point)info.GetValue("invalidLocation", typeof(Point));
            }
    
            public Point InvalidLocation
            {
                get { return invalidLocation; }
            }
    
            [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
            public override void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                base.GetObjectData(info, context);
                info.AddValue("invalidLocation", invalidLocation);
            }
        }
    
        [Serializable]
        public partial class SizeInvalidException
        {
            public SizeInvalidException(string message, Exception innerException)
                : base(message, innerException)
            { }
    
            public SizeInvalidException(string message, Size invalidSize)
                : base(message)
            {
                this.invalidSize = invalidSize;
            }
    
            protected SizeInvalidException(SerializationInfo info, StreamingContext context)
                : base(info, context)
            {
                this.invalidSize = (Size)info.GetValue("invalidSize", typeof(Size));
            }
    
            public Size InvalidSize
            {
                get { return invalidSize; }
            }
    
            [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
            public override void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                base.GetObjectData(info, context);
                info.AddValue("invalidSize", invalidSize);
            }
        }
    }
    

Creating Proxies for Structs

ShapeAppCSharp defines three serializable structs named Color, Point, and Size. To ensure that these structs are serialized correctly between ShapeApp and add-ins, manually define the proxies for the structs. The proxies have the same definitions as the structs in the host application's object model, and they also have the HostTypeAttribute attribute applied to them. For more information, see Creating Proxies for Managed Structs.

To create proxy structs

  1. In Solution Explorer, right-click ShapeAppCSharpProxy, point to Add, and then click Class.

  2. In the Name box, type Proxy.StructSerialization.cs, and then click Add.

  3. Replace the contents of the Proxy.StructSerialization.cs file with the following code. This code defines the Color, Point, and Size structs in the same way that they are defined in ShapeAppCSharp.

    namespace Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp
    {
        using System;
        using System.Runtime.Serialization;
        using System.Security.Permissions;
    
        [Serializable]
        [global::Microsoft.VisualStudio.Tools.Applications.Runtime.HostTypeAttribute(
            "ShapeAppCSharp, Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp.Color")]
        public struct Color
        {
            private short a;
            private short b;
            private short g;
            private short r;
    
            private static Color red = new Color(System.Drawing.Color.Red);
            private static Color green = new Color(System.Drawing.Color.Green);
            private static Color blue = new Color(System.Drawing.Color.Blue);
    
            public short A
            {
                get
                {
                    return a;
                }
                set
                {
                    a = value;
                }
            }
    
            public short B
            {
                get
                {
                    return b;
                }
                set
                {
                    b = value;
                }
            }
    
            public short G
            {
                get
                {
                    return g;
                }
                set
                {
                    g = value;
                }
            }
    
            public short R
            {
                get
                {
                    return r;
                }
                set
                {
                    r = value;
                }
            }
    
            public static Color Red
            {
                get
                {
                    return red;
                }
            }
    
            public static Color Green
            {
                get
                {
                    return green;
                }
            }
    
            public static Color Blue
            {
                get
                {
                    return blue;
                }
            }
    
            public Color(System.Drawing.Color color)
            {
                this.a = color.A;
                this.b = color.B;
                this.g = color.G;
                this.r = color.R;
            }
    
            public override bool Equals(object obj)
            {
                if (!(obj is Color))
                    return false;
                Color that = (Color)obj;
                if (that == null)
                    return false;
                return this == that;
            }
    
            public override int GetHashCode()
            {
                return a.GetHashCode() ^ b.GetHashCode() ^ g.GetHashCode() ^ r.GetHashCode();
            }
    
            static public bool operator ==(Color left, Color right)
            {
                return left.a == right.a && left.b == right.b && left.g == right.g && left.r == right.r;
            }
    
            static public bool operator !=(Color left, Color right)
            {
                return left.a != right.a || left.b != right.b || left.g != right.g || left.r != right.r;
            }
    
            static public implicit operator System.Drawing.Color(Color color)
            {
                return System.Drawing.Color.FromArgb(color.a, color.r, color.g, color.b);
            }
        }
    
        [Serializable]
        [global::Microsoft.VisualStudio.Tools.Applications.Runtime.HostTypeAttribute(
            "ShapeAppCSharp, Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp.Point")]
        public struct Point
        {
            private int x;
            private int y;
    
            public int X
            {
                get
                {
                    return x;
                }
                set
                {
                    x = value;
                }
            }
    
            public int Y
            {
                get
                {
                    return y;
                }
                set
                {
                    y = value;
                }
            }
    
            public Point(System.Drawing.Point point)
            {
                this.x = point.X;
                this.y = point.Y;
            }
    
            public Point(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
    
            public override bool Equals(object obj)
            {
                if (!(obj is Point))
                    return false;
                Point that = (Point)obj;
                if (that == null)
                    return false;
                return this == that;
            }
    
            public override int GetHashCode()
            {
                return x ^ y;
            }
    
            static public bool operator ==(Point left, Point right)
            {
                return left.x == right.x && left.y == right.y;
            }
    
            static public bool operator !=(Point left, Point right)
            {
                return left.x != right.x || left.y != right.y;
            }
    
            static public implicit operator System.Drawing.Point(Point point)
            {
                return new System.Drawing.Point(point.x, point.y);
            }
        }
    
        [Serializable]
        [global::Microsoft.VisualStudio.Tools.Applications.Runtime.HostTypeAttribute(
            "ShapeAppCSharp, Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp.Size")]
        public struct Size
        {
            private int width;
            private int height;
    
            public int Width
            {
                get
                {
                    return width;
                }
                set
                {
                    width = value;
                }
            }
    
            public int Height
            {
                get
                {
                    return height;
                }
                set
                {
                    height = value;
                }
            }
    
            public Size(System.Drawing.Size size)
            {
                this.width = size.Width;
                this.height = size.Height;
            }
    
            public Size(int width, int height)
            {
                this.width = width;
                this.height = height;
            }
    
            public override bool Equals(object obj)
            {
                if (!(obj is Size))
                    return false;
                Size that = (Size)obj;
                if (that == null)
                    return false;
                return this == that;
            }
    
            public override int GetHashCode()
            {
                return width ^ height;
            }
    
            static public bool operator ==(Size left, Size right)
            {
                return left.width == right.width && left.height == right.height;
            }
    
            static public bool operator !=(Size left, Size right)
            {
                return left.width != right.width || left.height != right.height;
            }
    
            static public implicit operator System.Drawing.Size(Size size)
            {
                return new System.Drawing.Size(size.width, size.height);
            }
        }
    }
    

Signing and Building the Proxy Assembly

For this walkthrough you must sign the assembly with a strong name before you build the solution, so you can save the proxy assembly in the global assembly cache. You must sign any assembly that you want to store in the global assembly cache with a strong name. For more information about how to sign an assembly by using Visual Studio, see How to: Sign an Assembly (Visual Studio).

To sign the assembly with a strong name

  1. Right-click ShapeAppCSharpProxy in Solution Explorer, and then click Properties.

  2. On the Signing page, select the Sign the assembly check box.

  3. In the Choose a strong name key file list, click <New…>.

    The Create Strong Name Key dialog box opens.

  4. In the Key file name box, type key.snk.

  5. Clear the Protect my key file with a password check box, and click OK.

  6. On the File menu, click Save All.

  7. On the Build menu, click Build ShapeAppCSharpProxy.

    ShapeAppCSharpProxy.dll is created and saved to the drive:\ShapeAppSamples\ShapeAppCSharp\ShapeAppCSharpProxy\bin\Debug folder.

Next Steps

To enable add-in projects to use the proxy assembly, you must install the proxy assembly into the global assembly cache. For more information, see How to: Install an Assembly into the Global Assembly Cache.

If you performed this walkthrough as part of the comprehensive series of walkthroughs for the ShapeApp sample, return to Walkthrough: Integrating Visual Studio Tools for Applications with ShapeApp.

If you performed this walkthrough as a stand-alone walkthrough, you might want to learn how to create a project template using the proxy assembly you created in this walkthrough. For more information, see Walkthrough: Creating a Project Template Using the Project Template Wizard.

See Also

Tasks

How to: Build and Run the ShapeAppCSharp Sample

Concepts

Creating Proxies

Defining Entry Points and Other Proxy Changes

Creating Proxies for Custom Exceptions

Creating Proxies for Managed Structs

Architecture of Generated Proxy Code

ProxyGen Descriptor Schema Reference

Creating Project Templates (Visual Studio Tools for Applications)