Integrating VSTA with an Unmanaged VBA-Enabled Application
Summit Software and Microsoft have worked together to produce a sample that shows how to integrate Microsoft Visual Studio Tools for Applications (VSTA) into an existing, unmanaged VBA-enabled MFC application, for the purpose of showing VBA/VSTA side-by-side interoperability, as well as to identify some of the issues that may be faced by VBA Partners who wish to add VSTA to their VBA-enabled applications.
The sample is available for download from summsoft.com/files.
Introduction
This walkthrough demonstrates how to integrate Microsoft Visual Studio Tools for Applications (VSTA) into an existing, unmanaged VBA-enabled MFC application, for the purpose of showing VBA/VSTA side-by-side interoperability, as well as to identify some of the issues that may be faced by VBA Partners who wish to add VSTA to their VBA-enabled applications.
Overview
Tasks illustrated in this walkthrough include:
- Installation and setup of the unmanaged, VBA host application.
- Creating a proxy source DLL.
- Creating project templates.
- Loading and unloading VSTA Add-ins.
- Displaying the VSTA IDE programmatically from the host application.
- Testing a simple Add-in.
Some of the common issues described within each related task include:
- Changes to the Visual Studio 2005 environment require modifications of several VBA SDK files in order to successfully compile the ShapeAppVBA sample.
- The Visual Studio Tools for Applications ProxyGen.exe utility may throw an exception the first time it is run.
- ProxyGen.exe auto-generated code will fail due to the host Object Model implementation of Application.Application syntax.
- The Visual Studio Tools for Applications ProjectGen.exe utility may throw an exception on first time use.
- Manual creation of the TypeInfrastructureManager, based on the application type information and the ProxyGen.exe auto-generated code. For additional information about the TypeInfrastructureManager, see Type Maps Overview.
- Adding support for showing the VSTA IDE from the host application, and safely shutting it down.
- Deployment and testing of a VSTA add-in.
Tasks not specifically described in this walkthrough include:
- Creation of and property settings for the ShapeAppVBA.Proxy.dll VC project.
For information about creating a proxy, see Creating Proxies.
- Creation of and property settings for the VSTAHookup.dll VC Project.
For information about loading and unloading add-ins, see Add-in Management Overview.
- Creation of the ShapeAppVBA Host Item Provider. For more information, see Host Item Provider Overview2abcfef0-409d-4787-8fb2-38472f86ed05.
Prerequisites
To complete this walkthrough, you will need:
- Microsoft Windows XP with Service Pack 2 installed on the computer.
- Microsoft Visual Studio 2005 installed on the computer.
- Microsoft Visual Studio 2005 SDK installed on the computer.
- Microsoft Visual Studio 2005 Tools for Applications installed on the computer.
For information about installing Visual Studio 2005 Tools for Applications, see How to: Install Visual Studio Tools for Applicationsa4c8dea3-0f70-4044-b2cc-f8510c66aca5.
- Microsoft Visual Basic for Applications SDK version 6.4 (Release bits) installed on the computer.
Installation and Setup of the ShapeAppVBA Sample Files
In this step, you will extract the sample files for the unmanaged VBA enabled ShapeApp sample to a folder on your development computer.
Note The directory locations you see may differ from those described in this document depending upon the location where you have extracted the sample files.
To extract the ShapeAppVBA sample files |
1. Create a folder named VSTA at the root of the Windows system drive (%SYSTEMDRIVE%), and then copy the ShapeAppVBA.zip archive to this location. For example, if your system drive is C, the archive would be copied to C:\VSTA\ ShapeAppVBA.zip. 2. Right-click the ShapeAppVBA.zip archive and select Extract All. Note This step assumes that your system is set to open .zip files using Compressed (zipped) Folders. If your system is set to open .zip files with another program, follow the instructions of that program to extract the contents of ShapeAppVBA.zip. 3. Follow the instructions in the Extraction Wizard to extract the contents of ShapeAppVBA.zip to the %SYSTEMDRIVE%\VSTA folder. 4. Click Finish to end the Extraction Wizard. |
Preparing the VBA SDK for use with Visual Studio 2005
In this step, you will replace several VBA 6.4 SDK header files with updated versions that compensate for changes in the MFC8.0 implementation. These changes are required to successfully build the ShapeApp VBA enabled sample application.
To update the VBA 6.4 SDK header files |
1. Extract the contents of the VBASDK_HeaderChanges/mfc_uni8.zip archive over the existing VBA 6.4 SDK header files located in the (%VBASDK%)\Include directory. For example, if the VBA SDK is installed in C:\Program Files\VBASDK, you would extract the contents of the archive into C:\Program Files\VBASDK\Include. 2. Add the VBA SDK Include and Library paths to the VS2005 directory path collections: - Start Visual Studio 2005.
- On the Tools menu, click Options...
- Navigate to and expand the Projects and Solutions node.
- Click on the VC++ Directories node.
- Select "Include Files" from the Show directories for: drop down.
- Add %VBASDK%\Include as the first directory in the list.
- Select "Library Files" from the Show directories for: drop down.
- Add %VBASDK%\Lib as the first directory in the list.
3. Click OK to apply the changes. |
Opening and Running the Solution
In this step, you will open and compile the solution for the unmanaged ShapeApp sample in Visual Studio 2005.
To open the ShapeAppVBA solution |
1. Start Visual Studio. 2. On the File menu, select Open, and then click Project/Solution. 3. In the Open Project dialog box, navigate to %SYSTEMDRIVE%\VSTA\ShapeAppVBA. 4. Select the ShapeAppVBA0.sln file, and click Open. 5. Ensure that the current solution configuration is set to Debug, and press F5 to run the solution. This registers the COM object model. Note When you build the solution, a type library named ShapeAppVBA.tlb is created in the %SYSTEMDRIVE%\VSTA\ShapeAppVBA\Core\Debug directory. You will use this type library in the "Creating the Proxy Source DLL" section of this walkthrough. 6. Test that VBA is functioning properly by pressing Alt+F11 to show the VBA IDE. 7. Close ShapeAppVBA. |
At this point, the unmanaged VBA enabled MFC host application has been compiled, registered, and shown to be able to successfully load and display the VBA IDE. The next step is to create a proxy DLL, which will facilitate communication between the unmanaged ShapeAppVBA host application and the managed VSTA Add-ins.
Preparing ProxyGen for use with ShapeAppVBA
The Proxygen.exe utility is used to generate a proxy descriptor and the proxy code based on the host application object model. Depending on the version installed, the first time you attempt to use the ProxyGen utility you may receive an exception, due to the fact that the assembly and its dependent DLLs are delay signed. To suppress this error, you will need to turn verification off using the "sn" tool.
To suppress ProxyGen.exe exceptions |
1. Open the Visual Studio 2005 Command Prompt. 2. Change the path to the (%VSTASDK%) directory. For example, if the Visual Studio Tools for Applications SDK is installed in C:\Program Files\Visual Studio 2005 SDK\2006.02\VisualStudioToolsForApplications, you would change the current path to be C:\Program Files\Visual Studio 2005 SDK\2006.02\VisualStudioToolsForApplications. Note To simplify access to the ProxyGen.exe utility, map a drive letter to the %VSTASDK%\Tools location. Execute the following command: subst x: "%VSTASDK%\Tools" 3. Change the path to x:\ProxyGen\x86. 4. Execute the following commands: sn -Vr ProxyGen.exe sn -Vr Microsoft.VisualStudio.Tools.Applications.ProxyServices.dll sn -Vr Microsoft.TLI.Interop.dll |
Generating the Proxy Descriptor and Proxy Code
Once verification has been turned off for ProxyGen and its related dependencies, you are ready to begin generating the proxy descriptor and the proxy code.
To generate the proxy descriptor files |
1. Navigate to the (%SHAPEAPPVBA%) directory. For example, if the sample is installed in C:\VSTA\ShapeAppVBA, you would change the current directory to be C:\VSTA\ShapeAppVBA. 2. Create a directory named ShapeAppVBAProxy in the %SHAPEAPPVBA% directory. 3. Copy the %SHAPEAPPVBA%\Archive\ShapeAppVBAProxy.zip file to the %SHAPEAPPVBA%\ShapeAppVBAProxy directory, and extract all files. 4. Open the ShapeAppVBA0.sln solution file in Visual Studio 2005, and add the %SHAPEAPPVBA%\ShapeAppVBAProxy\ShapeAppVBAProxy.csproj to the solution: - Start Visual Studio 2005.
- Open the ShapeAppVBA0.sln solution.
- Right-click the ShapeAppVBA0 Solution in the Solution Explorer Window, select Add, and then Existing Project...
- Navigate to %SHAPEAPPVBA%\ShapeAppVBAProxy and select the ShapeAppVBAProxy.csproj file.
- Click OK to add the project.
5. Open the Visual Studio 2005 Command Prompt. 6. Change the path to x:\ProxyGen\x86. 7. Execute the following command: ProxyGen.exe /l:"%SHAPEAPPVBA%\Core\Debug\ShapeAppVBA.tlb" /c:"%SHAPEAPPVBA%\ShapeAppVBAProxy\Proxy.cs" /o:"%SHAPEAPPVBA%\ShapeAppVBAProxy\Descriptor.xml" /f A proxy descriptor named Descriptor.xml, and a proxy named Proxy.cs are created in the %SHAPEAPPVBA%\ShapeAppVBAProxy directory. 8. Open the Descriptor.xml file in Visual Studio 2005: - On the File menu, select Open, and then click File...
- Navigate to %SHAPEAPPVBA%\ShapeAppVBAProxy, and select the Descriptor.xml file.
9. Append the Add-in entry point attribute to the "ShapeAppVBA.Application" class description: - On the Edit menu, select Find and Replace, and then click Quick Find.
- Type ShapeAppVBA.Application into the Find what: drop down. Make sure that the Look in: drop down is set to "Current Document", and click Find Next.
- Add the following attribute after the isStatic="false" attribute:
isAddInEntryPoint="true" Note The isAddInEntryPoint attribute is similar to the appobject IDL attribute required by VBA to determine the Application Class. - Save and close the Descriptor.xml file.
10. The modified Descriptor.xml is now used as input for ProxyGen to further define the auto-generated Proxy.cs output code. Execute the following command from the Visual Studio 2005 Command Prompt: ProxyGen.exe /l:"%SHAPEAPPVBA%\Core\Debug\ShapeAppVBA.tlb" /c:"%SHAPEAPPVBA%\ShapeAppVBAProxy\Proxy.cs" /i:"%SHAPEAPPVBA%\ShapeAppVBAProxy\Descriptor.xml" /f 11. Switch back to Visual Studio 2005, and add the newly generated Proxy.cs file to the ShapeAppVBAProxy project: - Right-click ShapeAppVBAProxy in the Solution Explorer window, and select Add, and then Existing Item...
- Navigate to the %SHAPEAPPVBA%\ShapeAppVBAProxy directory, and select the Proxy.cs file.
- Click OK to add the file.
|
Generating the ShapeAppVBA Proxy DLL
In this section you will compile the generated proxy code to create the proxy DLL. This proxy library will be used by the Visual Studio Tools for Applications project templates to facilitate communication between the ShapeAppVBA application and the Visual Studio Tools for Applications Add-ins.
To generate the ShapeAppVBA.Proxy.DLL |
1. Set the inner project dependencies to ensure a successful clean build: - Right-click the ShapeAppVBAProxy project in the Solution Explorer window, and select Project Dependencies...
The "Project Dependencies" dialog will display. - On the Dependencies tab, check the box next to ShapeAppVBA within the Depends on: section.
- Click OK to apply the changes.
2. Add the required Visual Studio Tools for Applications assembly references: - Right-click the ShapeAppVBAProxy project in the Solution Explorer window, and select Add Reference...
The "Add Reference" dialog will display. - On the .NET tab, select the following assemblies:
Microsoft.VisualStudio.Tools.Applications.Adapter Microsoft.VisualStudio.Tools.Applications.Contract System.Addin System.Addin.Contract - Click OK to add the references to the project.
3. Compile the ShapeAppVBAProxy assembly by right-clicking the ShapeAppVBAProxy project in the Solution Explorer window, and selecting Build. The Proxy.cs code errors, and the assembly fails to build. |
The auto-generated proxy code will fail to build because of a language restriction imposed by the Visual C# compiler. Many VBA enabled applications base their object model on the Microsoft Office VBA design, meaning they have likely implemented the Application.Application scripting syntax. Visual C# does not allow member names to be the same as their containing type name, so the Proxy.cs code requires manual modification in order to successfully build and to preserve object model consistency with the host application.
To manually modify the Proxy.cs generated code |
1. Open the Proxy.cs file in Visual Studio 2005. - Right-click Proxy.cs, and click View Code.
2. Add the following code after the ShapeAppVBA namespace declaration, and immediately before the Application partial class implementation: public abstract class CApplication { } Note An abstract class serves no purpose by itself, must be inherited from, and can not be instantiated on its own. To avoid exposing this class as a public creatable class to VSTA, it is marked with the abstract modifier. 3. Modify the Application partial class definition to inherit from CApplication. You can do this by adding CApplication as the first item in the inheritance chain: public partial class Application : CApplication, ... 4. Navigate to the Application.Application property member implementation by double-clicking on the first Proxy.cs error listed in the Visual Studio 2005 Output window, or by locating the ShapeAppVBA.Application.Application method definition in Proxy.cs. 5. Cut the entire Application property implementation from the Application partial class, and paste it into the CApplication abstract class implementation. 6. Cut the remoteType variable declaration from the Application partial class, and paste it at the top of the CApplication class implementation. 7. Change the remoteType variable scope from private to internal: internal global::System.Type remoteType; Note The remoteType variable scope needs to be changed because the Application partial class requires programmatic access to the remoteType member variable. Marking the CApplication::remoteType member variable with the internal modifier changes its accessibility from the containing type to the containing assembly, allowing it to be accessed from within the Application partial class. 8. Cut the @__vstaCacheApplication6 variable declaration from the Application partial class, and paste it after the CApplication::remoteType variable declaration. 9. Compile the proxy by right-clicking the ShapeAppVBAProxy project in the Solution Explorer window, and selecting Build. The Proxy DLL is successfully built and saved to the %SHAPEAPPVBA%\ShapeAppVBAProxy\bin\Debug folder. |
Registering the Host Application
Before creating the project templates, the ShapeAppVBA application needs to be registered with Visual Studio Tools for Applications.
To register ShapeAppVBA with VSTA |
1. Click Start, and then click Run. 2. Type regedit, and then press ENTER. 3. In the Registry Editor, expand the HKEY_LOCAL_MACHINE node, expand the Software node, expand the Microsoft node, right-click the VSTAHostConfig node, select New, and then click Key. Rename the newly created key to ShapeAppVBA. 4. Right-click the ShapeAppVBA node, select New, and then click String Value. Rename the newly created value to be AppName. 5. Double-click AppName, type ShapeAppVBA in the Value data text box, and then click OK. 6. Right-click the ShapeAppVBA node again, select New, and then click String Value. Rename the newly created value to be ProjectTemplatesLocation. 7. Double-click ProjectTemplatesLocation, type %SHAPEAPPVBA%\Templates in the Value data text box, and then click OK. Note The ShapeAppVSTA.reg file is included with this sample as an alternate method of inserting these values into the registry. You must be sure to modify the path locations to match your current installation. The registry file can be found in the %SHAPEAPPVBA% directory. 8. Open the Visual Studio 2005 Command Prompt, and change the path to %SYSTEMDRIVE%\Program Files\Microsoft Visual Studio 8\Common7\IDE. 9. Execute the following command: vsta /hostid ShapeAppVBA /setup |
Adding the Proxy DLL to the Global Assembly Cache
In order to successfully utilize the project templates, it is also necessary to add the ShapeAppVBA.Proxy.DLL assembly to the global assembly cache.
To add the ShapeAppVBA.Proxy.DLL assembly to the GAC |
1. Open the Visual Studio 2005 Command Prompt, and change the path to %SYSTEMDRIVE%\Program Files\Microsoft Visual Studio 8\SDK. 2. Execute the following command: gacutil /i %SHAPEAPPVBA%\ShapeAppVBAProxy\bin\debug\ShapeAppVBA.Proxy.dll 3. To verify that the assembly was successfully added to the cache, locate it in the %WINDOWS%\Assembly directory. |
Preparing ProjectGen for use with ShapeAppVBA
The ProjectGen.exe utility is used to generate the add-in project templates, which are used to author Visual Studio Tools for Applications add-ins for the ShapeAppVBA host application. As with the ProxyGen utility, the first time you attempt to run the ProjectGen utility you may receive an exception. Again, this is due to the fact that the assembly and its dependent DLLs are delay signed. To suppress this error, you will need to turn verification off using the "sn" tool.
To suppress ProjectGen.exe exceptions |
1. Open the Visual Studio 2005 Command Prompt. 2. Change the path to x:\ProjectGen\x86. Note To simplify access to the ProjectGen.exe utility, we previously mapped a drive letter to the %VSTASDK%\Tools location. If necessary, executing the following command will restore this drive mapping: subst x: "%VSTASDK%\Tools" 3. Execute the following commands: sn -Vr ProjectGen.exe sn -Vr Microsoft.VisualStudio.Tools.Applications.ProjectGen.dll |
Creating the ShapeAppVBA Project Templates
Once you have registered the host application, added the proxy assembly to the global assembly cache, and suppressed the runtime exceptions, you can successfully load the ProjectGen.exe wizard that will guide you through the creation of the project templates.
To run the ProjectGen.exe Wizard |
1. Open the Visual Studio 2005 Command Prompt, and change the path to x:\ProjectGen\x86. 2. Execute the following command: ProjectGen.exe |
There are four pages in the Project Template Wizard that must be completed before you can continue. The following sections describe the values for each of the fields on each page in the wizard. The first page is the Specify Template Properties page.
To complete the Specify Template Properties page |
1. In the Template name field, type ShapeAppVBA Add-in. This specifies the name of the add-in displayed on the Templates pane of the New Project dialog. 2. In the Template description field, type A project for creating add-ins for ShapeAppVBA. This description will appear above the Name box of the New Project dialog whenever the associated template is selected. 3. In the Default project name field, type ShapeAppVBA. This name will be used as the default project name that appears in the New Project dialog box. An incremental number is appended to this name for each project created. 4. In the Template icon box, click the ellipsis (...) button and navigate to the %SYSTEMDRIVE%\Program Files\Microsoft Visual Studio 8\Common7\IDE\Extensibility Projects\Visual Studio Add-In.ico. This is the icon that will appear in the Templates pane on the New Project dialog. 5. In the Host identifier list, select ShapeAppVBA. If successfully registered, ShapeAppVBA will automatically be added to this list of available host identifiers. 6. Click Next to continue to the next page of the wizard. |
The next page is the Specify Host Item page.
To complete the Specify Host Item page |
1. In the Proxy assembly name field, click the ellipsis (...) button and navigate to the %SHAPEAPPVBA%\ShapeAppVBAProxy\bin\Debug\ShapeAppVBA.Proxy.Dll proxy assembly. 2. In the Base type list, select ShapeAppVBA.Application. 3. In the Host item name field, type ThisApplication. This name is used to determine the name of the code file. For example, ThisApplication.cs and ThisApplication.vb. 4. Leave the remaining fields empty, and click Next to continue to the next page of the wizard. |
The next page is the Specify Project Properties page.
To complete the Specify Project Properties page |
1. In the Debug exe field, click the ellipsis (...) button and navigate to the %SHAPEAPPVBA%\Debug\ShapeAppVBA.exe application. 2. Leave the remaining fields empty, and click Next to continue to the next page of the wizard. |
The next page is the Generate Project Template page.
To complete the Generate Project Template page |
1. Check the Create project template box, if not already checked, and then click the ellipsis (...) button and navigate to the %SHAPEAPPVBA%\Templates directory. 2. Check the Register template with host application box, if not already checked. 3. Check the Save project template descriptor file box, if not already checked, and then click the ellipsis (...) button and navigate to the %SHAPEAPPVBA% directory, and name the file ShapeAppVBADescriptor.xml. 4. Click Finish to complete the wizard. 5. Click OK on the Registering Project Templates dialog, after the templates have been successfully registered. |
Now that the project templates have been created, you can test to see that they are accessible from within Visual Studio Tools for Applications.
To test the ShapeAppVBA project templates |
1. Open the Visual Studio 2005 Command Prompt, and change the path to %SYSTEMDRIVE%\Program Files\Microsoft Visual Studio 8\Common7\IDE. 2. Execute the following command: vsta /hostid ShapeAppVBA 3. On the File menu, click New Project. 4. In the Project Types pane, select the Visual C# node. 5. In the Templates pane, select ShapeAppVBA Add-in, and click OK. 6. Verify that the ShapeAppVBA Add-in project opens in the Visual Studio Tools for Applications IDE. |
Creating the VSTAHookup Library Assembly
In this step you will create a managed intermediate library. The ShapeAppVBA application will use this library to communicate with the managed VSTA components.
To create the managed intermediate library |
1. Navigate to the %SHAPEAPPVBA% directory. 2. Create a directory named VSTAHookup in the %SHAPEAPPVBA% directory. 3. Copy the %SHAPEAPPVBA%\Archive\VSTAHookup.zip file to the %SHAPEAPPVBA%\VSTAHookup directory, and extract all files. 4. Open the ShapeAppVBA0.sln solution file in Visual Studio 2005, and add the %SHAPEAPPVBA%\VSTAHookup\VSTAHookup.csproj to the solution: - Open the ShapeAppVBA0.sln solution.
- Right-click the ShapeAppVBA0 Solution in the Solution Explorer Window, select Add, and then Existing Project...
- Navigate to %SHAPEAPPVBA%\VSTAHookup and select the VSTAHookup.csproj file.
- Click OK to add the project.
5. Set the project dependencies to ensure a successful clean build: - Right-click the ShapeAppVBA project in the Solution Explorer window, and select Project Dependencies...
The "Project Dependencies" dialog will display. - On the Dependencies tab, check the box next to VSTAHookup within the Depends on: section.
- Click OK to apply the changes.
6. Add the required Visual Studio Tools for Applications assembly references: - Right-click the VSTAHookup project in the Solution Explorer window, and select References...
The "VSTAHookup Property Pages" dialog will display. - Add references to the following assemblies:
Microsoft.VisualStudio.Tools.Applications.Adapter Microsoft.VisualStudio.Tools.Applications.AddInManager Microsoft.VisualStudio.Tools.Applications.Contract Microsoft.VisualStudio.Tools.Applications.InteropAdapter System.Addin.Contract Note The VSTAHookup Property Pages dialog does not allow multiple selections within the References: pane, therefore you must set each reference individually. To do so, click the Add New Reference button, select the assembly reference from the .NET tab, and then click OK. Repeat this process for each of the references listed above. - Click OK to close the VSTAHookup Property Pages dialog.
7. Compile the VSTAHookup assembly by right-clicking the VSTAHookup project in the Solution Explorer window, and selecting Build. Note It is expected at this point that compiling the VSTAHookup project will generate two compiler warnings. These will be addressed and resolved in the next section. |
At this point, the VSTAHookup assembly is almost complete. The final task required to make the VSTAHookup library functional is to define the TypeInfrastructureManager, which describes the host application type library. The compiler warnings are indicating variables in CreateTypeInfrastructureManager have been declared but not assigned values. Navigate to the CreateTypeInfrastructureManager implementation by double-clicking on the first VSTAHookup.cpp warning listed in the Visual Studio 2005 Output window, or by locating the VSTAHookup::CreateTypeInfrastructureManager function definition in VSTAHookup.cpp.
To define the TypeInfrastructureManager |
1. Define and load the ShapeAppVBA type library: - Add the following variable declarations, replacing the TODO comment in the function body:
// ShapeAppVBA.IDL - LIBID System::Guid theGuid = System::Guid("58559A1C-EB4A-44fa-96F2-8034A7EE95CD"); ITypeLib* pTypeLib; GUID libID = {0x58559A1C,0xEB4A,0x44fa,{0x96,0xF2,0x80,0x34,0xA7,0xEE,0x95,0xCD}}; Note This GUID above corresponds to the ShapeAppVBA host application LIBID, defined in the ShapeAppVBA.IDL definition file. - Using the LIBID, load the ShapeAppVBA type library with a call to:
::LoadRegTypeLib(libID,1,0,0,&pTypeLib); - Assign the ITypeLib managed type:
typeLib = (System::Runtime::InteropServices::ComTypes::ITypeLib^)System::Runtime::InteropServices::Marshal::GetTypedObjectForIUnknown( (IntPtr)pTypeLib, System::Runtime::InteropServices::ComTypes::ITypeLib::typeid); Note The above code satisfies the first compiler warning. 2. Create a code region to identify the section of the TypeInfrastructureManager implementation that defines the ShapeAppVBA.Drawing class interfaces: #pragma region ShapeAppVBA.Drawing Implementation #pragma endregion 3. Add the definition for the ShapeAppVBA.IDrawing interface to the ShapeAppVBA.Drawing Implementation region: // ShapeAppVBA.IDrawing theGuid = System::Guid("58559A1D-EB4A-44fa-96F2-8034A7EE95CD"); typeLib->GetTypeInfoOfGuid(theGuid, typeInfo); typeInfrastructureManager->TypeToCanonicalNameMap->Add( typeInfo,"ShapeAppVBA, ShapeAppVBA.IDrawing" ); Note The variable theGuid is assigned the ShapeAppVBA.IDrawing interface identifier, defined in the ShapeAppVBA.IDL definition file. The last two parameters passed to the TypeToCanonicalNameMap->Add procedure must match the corresponding named identifiers passed to the AddTypeToMap implementation, located in the CShapeAppVBAInitializer partial class, whose definition can be found within the previously generated Proxy.cs file. Note The above code satisfies the second compiler warning. 4. Add the definition for the ShapeAppVBA.DDrawing dispatch interface to the ShapeAppVBA.Drawing Implementation region: // ShapeAppVBA.DDrawing theGuid = System::Guid("58559A1E-EB4A-44fa-96F2-8034A7EE95CD"); typeLib->GetTypeInfoOfGuid(theGuid, typeInfo); typeInfrastructureManager->TypeToCanonicalNameMap->Add( typeInfo,"ShapeAppVBA, ShapeAppVBA.DDrawing" ); 5. Add the definition for the ShapeAppVBA.IDrawingEvents event interface to the ShapeAppVBA.Drawing Implementation region: // ShapeAppVBA.IDrawingEvents theGuid = System::Guid("58559A1F-EB4A-44fa-96F2-8034A7EE95CD"); typeLib->GetTypeInfoOfGuid(theGuid, typeInfo); typeInfrastructureManager->TypeToCanonicalNameMap->Add( typeInfo,"ShapeAppVBA, ShapeAppVBA.IDrawingEvents" ); 6. Add the definition for the ShapeAppVBA.DDrawingEvents dispatch interface to the ShapeAppVBA.Drawing Implementation region: // ShapeAppVBA.DDrawingEvents theGuid = System::Guid("58559A20-EB4A-44fa-96F2-8034A7EE95CD"); typeLib->GetTypeInfoOfGuid(theGuid, typeInfo); typeInfrastructureManager->TypeToCanonicalNameMap->Add( typeInfo,"ShapeAppVBA, ShapeAppVBA.DDrawingEvents" ); 7. Add the definition for the ShapeAppVBA.Drawing class to the ShapeAppVBA.Drawing Implementation region: // ShapeAppVBA.Drawing theGuid = System::Guid("58559A21-EB4A-44fa-96F2-8034A7EE95CD"); typeLib->GetTypeInfoOfGuid(theGuid, typeInfo); typeInfrastructureManager->TypeToCanonicalNameMap->Add( typeInfo,"ShapeAppVBA, ShapeAppVBA.Drawing" ); Note This completes the ShapeAppVBA.Drawing Implementation region. 8. Define the remaining ShapeAppVBA.IDL type library definitions, following the steps used to define the ShapeAppVBA.Drawing Implementation region. Create the following named code regions, and define the type information members described for each: ShapeAppVBA.Shape Implementation ShapeAppVBA.Drawings Implementation ShapeAppVBA.Shapes Implementation ShapeAppVBA.Application Implementation - ShapeAppVBA.IApplicationEvents
- ShapeAppVBA.DApplicationEvents
ShapeAppVBA.SizeInfo Implementation ShapeAppVBA.PointInfo Implementation ShapeAppVBA.ColorInfo Implementation Note A complete TypeInfrastructureManager implementation for ShapeAppVBA is provided with this sample, and located in the %SHAPEAPPVBA%\VSTAHookup directory. If you do not wish to manually generate this portion of code, you may remove the VSTAHookup::CreateTypeInfrastructureManager implementation from the VSTAHookup.cpp file, and replace it with implementation found in the %SHAPEAPPVBA%\VSTAHookup\TIM.txt file. 9. Compile the VSTAHookup assembly by right-clicking the VSTAHookup project in the Solution Explorer window, and selecting Build. |
Modifying ShapeAppVBA to Load and Unload Add-ins
The ShapeAppVBA project properties must be modified to allow programmatic access to StartVSTA, LoadAddIns, UnloadAddIns and StopVSTA, which are methods exported by the VSTAHookup assembly.
To modify the ShapeAppVBA project properties |
1. Right-click the ShapeAppVBA project in the Solution Explorer window, and click Properties. 2. Select All Configurations in the Configuration: drop down list. 3. On the ShapeAppVBA Property Pages dialog, expand the C/C++ node in the left pane, and select General. 4. Append "$(SolutionDir)\VSTAHookup" to the Additional Include Directories field. 5. Expand the Linker node in the left pane, and select Input. 6. Append "$(SolutionDir)$(ConfigurationName)\VSTAHookup.lib" to the Additional Dependencies field. 7. Click OK. |
Once programmatic access to the exported methods has been established, code needs to be added in order to utilize them.
To modify ShapeAppVBA |
1. Copy %SHAPEAPPVBA%\Archive\Core.zip to the %SHAPEAPPVBA%\Core directory, and extract its contents. The VSTA.cpp file will be extracted to the %SHAPEAPPVBA%\Core directory. 2. Add the VSTA.cpp source file to the ShapeAppVBA project: - Right-click ShapeAppVBA in the Solution Explorer window, and select Add, and then Existing Item...
- Navigate to the %SHAPEAPPVBA%\Core directory, and select the VSTA.cpp file.
- Click OK to add the file.
3. Right-click ShapeAppVBA.h, and then click View Code. 4. Add these method declarations immediately following the private: keyword in the CShapeAppVBA class definition: void StartVSTA(); void StopVSTA(); void LoadAddIns(); void UnloadAddIns(); bool AddInsLoaded(); Note These method implementations can be found in the VSTA.CPP source file. 5. Several of the CShapeAppVBA routines require modification in order to make use of the Add-in loading and unloading functionality: - Right-click ShapeAppVBA.cpp, and then click View Code.
- Locate the InitInstance function definition, and add the following code immediately before the final return TRUE statement:
this->StartVSTA(); - Locate the CShapeAppVBA::Exit function definition, and add the following code to its implementation:
this->StopVSTA(); - Locate the OnVisualstudiotoolsforapplicationsaddinsLoad function definition, and add the following code to its implementation:
this->LoadAddIns(); - Locate the OnVisualstudiotoolsforapplicationsaddinsUnload function definition, and add the following code to its implementation:
this->UnloadAddIns(); - Locate the OnUpdateVisualstudiotoolsforapplicationsaddinsLoad function definition, and change its implementation to the following:
pCmdUI->Enable(!(this->AddInsLoaded())); - Locate the OnUpdateVisualstudiotoolsforapplicationsaddinsUnload function definition, and change its implementation to the following:
pCmdUI->Enable(this->AddInsLoaded()); 6. Compile the ShapeAppVBA application by right-clicking the ShapeAppVBA project in the Solution Explorer window, and selecting Build. |
Showing the Visual Studio Tools for Applications IDE
It is possible to create, edit and debug Add-ins without providing access to the VSTA IDE from the host application itself. This can be accomplished by executing the vsta /hostid ShapeAppVBA command from the Visual Studio 2005 Command Prompt, or by creating a shortcut that performs a similar action. However, providing direct access to the VSTA IDE from a running instance of the host application creates a productive, easy to use environment for VSTA developers who would like to customize the application.
To modify VSTAHookup |
1. Add the required Visual Studio Tools for Applications assembly references: - Right-click the VSTAHookup project in the Solution Explorer window, and select References...
The "VSTAHookup Property Pages" dialog will display. - Add references to the following assemblies:
EnvDTE VSTADTEProvider.Interop Note The VSTAHookup Property Pages dialog does not allow multiple selections within the References: pane, therefore you must set each reference individually. To do so, click the Add New Reference button, select the assembly reference from the .NET tab, and then click OK. Repeat this process for each of the references listed above. - Click OK to close the VSTAHookup Property Pages dialog.
2. Right-click VSTAHookup.h, and select View Code. 3. Add these namespaces after the existing namespaces at the top of the file: using namespace VSTADTEProvider::Interop; using namespace EnvDTE; Note These references provide access to the Visual Studio Tools for Applications design time environment (VSTA IDE). 4. Locate the StopVSTA method declaration in the VSTAHookup class definition, and add this method declaration immediately following it: void ShowVSTAIDE(bool bShow); 5. Add these declarations immediately following the private: keyword in the VSTAHookup class definition: EnvDTE::DTE^ m_DTE; void OnBeginShutdown(void); 6. Right-click VSTAHookup.cpp, and select View Code. 7. Locate the VSTAHookup::VSTAHookup constructor implementation, and append the m_DTE(nullptr) member variable initialization to match the following: VSTAHookup::VSTAHookup(IDispatch *pApp) : m_pApp(pApp), m_DTE(nullptr) 8. Locate the VSTAHookup::StopVSTA method, and add this at the top of the implementation: if (this->m_DTE != nullptr) { if (this->m_DTE->Mode == EnvDTE::vsIDEMode::vsIDEModeDebug) { this->m_DTE->Debugger->Stop(true); } m_DTE->Quit(); } Note The code above is required to safely exit debug mode, prior to unloading the Visual Studio Tools for Applications design time environment. 9. Add the VSTAHookup::ShowVSTAIDE implementation following the VSTAHookup::StopVSTA method: void VSTAHookup::ShowVSTAIDE(bool bShow) { if (m_DTE == nullptr) { IDTEProvider ^dteProvider = (IDTEProvider^)gcnew VSTADTEProviderClass(); String^ HostID = "ShapeAppVBA"; unsigned int TimeOut = 10000; m_DTE = dteProvider->GetDTE(HostID,TimeOut); if (m_DTE != nullptr) { m_DTE->Windows->DTE->Events->DTEEvents-> OnBeginShutdown += gcnew EnvDTE::_dispDTEEvents_OnBeginShutdownEventHandler( this,&VSTAHookup::OnBeginShutdown ); m_DTE->MainWindow->Visible = bShow; } } else { m_DTE->MainWindow->Visible = bShow; } } Note The code above is the programmatic equivalent of the command line approach to loading the VSTA IDE in the ShapeAppVBA host context. Once loaded, the VSTA IDE visibility property is manipulated programmatically. 10. Define the VSTAHookup::OnBeginShutdown event handler following the VSTAHookup::ShowVSTAIDE method implementation: void VSTAHookup::OnBeginShutdown(void) { m_DTE = nullptr; } Note The OnBeginShutdown event handler has been provided to demonstrate connecting to VSTA IDE event handler callbacks. 11. Add the ShowVSTAIDE export definition to the VSTAHookup assembly, making it accessible from the ShapeAppVBA host application. - Right-click StartVSTA.h, and select View Code.
- Add the definition for ShowVSTAIDE following the existing declarations:
void __declspec(dllexport) __stdcall ShowVSTAIDE(bool bShow); - Right-click StartVSTA.cpp, and select View Code.
- Add the implementation for ShowVSTAIDE following the existing methods:
void __declspec(dllexport) __stdcall ShowVSTAIDE(bool bShow) { ShapeApp::Integration::VSTAHookup^ hookup = ShapeApp::Integration::VSTAHookup::GetInstance(0); hookup->ShowVSTAIDE(bShow); } 12. Compile the VSTAHookup assembly by right-clicking the VSTAHookup project in the Solution Explorer window, and selecting Build. |
With the ShowVSTAIDE functionality implemented and exposed by the VSTAHookup assembly, the next step is to modify the host application to utilize this new API.
To modify ShapeAppVBA |
1. Right-click ShapeAppVBA.h, and select View Code. 2. Locate the AddInsLoaded method declaration, and add the ShowVSTA_IDE method declaration immediately following it: void ShowVSTA_IDE(bool bShow); 3. Right-click VSTA.cpp, and select View Code. 4. Locate the AddInsLoaded method implementation, and add the ShowVSTA_IDE method implementation immediately following it: void CShapeAppVBA::ShowVSTA_IDE(bool bShow) { ::ShowVSTAIDE(bShow); } Note The ShowVSTA_IDE method calls the exported ShowVSTAIDE method, which has been implemented in the VSTAHookup assembly. 5. Right-click ShapeAppVBA.cpp, and select View Code. 6. Locate the OnVstaIde method implementation, and replace the TODO comment with the following statement: ShowVSTA_IDE(true); Note This method will be called when the Ctrl+Alt+F11 key combination is pressed. This shortcut was chosen to avoid a conflict with the standard VBA IDE Alt+F11 shortcut, while at the same time providing a familiar key combination sequence for the user. 7. Locate the OnUpdateVstaIde callback implementation, and change the parameter passed to Enable from FALSE to TRUE: pCmdUI->Enable(TRUE); Note The OnUpdateVstaIde callback enables the Show VSTA IDE button on the host application toolbar, which calls the OnVstaIde method when clicked. 8. Compile the ShapeAppVBA application by right-clicking the ShapeAppVBA project in the Solution Explorer window, and selecting Rebuild. |
Testing the ShapeAppVBA Application
The pre-built add-in included with the ShapeAppVBA host application sample is provided for the purposes of testing the host implementation of loading and unloading add-ins.
To test ShapeAppVBA |
1. Create a folder named ShapeAppVBA in %USERPROFILE%\My Documents. 2. Copy %SHAPEAPPVBA%\Archive\AppAddins.zip to the %USERPROFILE%\My Documents\ShapeAppVBA directory, and extract its contents. Note The add-in will be extracted to the AppAddins subfolder. The ShapeAppVBA host application has specified the location to search for add-ins, defined by the VSTAHookup::AppAddInPath class member variable. Modify AppAddInPath in VSTAHookup.h if a different search location is desired. 3. Press F5 in Visual Studio 2005 to run the ShapeAppVBA.EXE host application. 4. On the ShapeAppVBA main application menu, select Tools, select Visual Studio Tools for Applications Addins, and click Load. 5. Verify that the Add-in loads. Note Although ShapeAppVBA focuses on the loading and unloading of add-ins into the host application process, it is possible for add-ins to be loaded into the following contexts: - A new AppDomain
- A separate, existing AppDomain
- A new AppDomain in a new process
- The existing application AppDomain (default AppDomain)
6. Close the ShapeAppVBA sample application to complete the walkthrough. |
Tasks illustrated in this sample include:
· Installation and setup of the unmanaged, VBA host application.
· Creating a proxy source DLL.
· Creating project templates.
· Loading and unloading VSTA Add-ins.
· Displaying the VSTA IDE programmatically from the host application.
· Testing a simple Add-in.