Welcome!

PowerBuilder Authors: Chris Pollach, Yeshim Deniz, Jayaram Krishnaswamy, Kevin Benedict, Avi Rosenthal

Related Topics: PowerBuilder, Microsoft Cloud

PowerBuilder: Article

Using Add-ins with PowerBuilder .NET 12.0

Creating a basic add-in

When Sybase originally released PowerBuilder 10.0, one of the new features they added with that version was the PowerDesigner plug-in. There had been a number of IDE "add-in" third-party products for PowerBuilder before (e.g, SmartPaste, SmartJump), but this was the first time that Sybase had opened up an API to officially support add-ins to the IDE. Unfortunately, Sybase never documented how the API worked. So, even today in PowerBuilder 12 Classic, you can go to the Tools-> Plug-in Manager option and be presented with a dialog that appears to originally have been intended to support a number of plug-ins, but only lists one (see Figure 1).

With the release of PowerBuilder.NET 12.0, the possibility of having plug-ins to the IDE officially supported gets a new life. That's because PowerBuilder.NET 12.0 is based on the Visual Studio Isolated Shell and Visual Studio has supported (and documented the API for) plug-ins for the IDE since 2002. Visual Studio even supplies templates that you can use to create your own plug-ins (or as they are called in Visual Studio parlance: add-ins). The PowerBuilder.NET 12.0 documentation indicates that it supports those add-ins.

In this article we're going to look at a number of existing Visual Studio add-ins and see if they actually do work with PowerBuilder.NET 12.0. We'll also look at creating our own add-in for PowerBuilder.NET 12.0 using Visual Studio.  In a follow up article in a later issue we'll look at using PowerBuilder 12.NET to create an add-in for itself. I did speak to the technical support department at one of the vendors (Designbox) and we were able to determine the registry entry that their installer was looking for that was different between Visual Studio and the Visual Studio Isolated Shell.  Creating that registry entry allowed the add-in to install, but it also turned out to be a VSPackage Module, not a standard add-in (see below).

There's no official comprehensive list of the various add-ins currently available for Visual Studio. To ensure that we would be working with a fairly representative cross-section however, I decided to use the list included in the Wikipedia "List of Microsoft Visual Studio add-ins." At the time of this writing, that list included 21 different add-ins for Visual Studio: Aggiorno, AnksSVN, CodeRush, CopyAsHTML, DesignBox, Dotfuscator, Koders, PhatStudio, Resharper, Software Diagnostics Developer Edition, TracExplorer, Visual Assist, VisualSVN, VsTortoise, HgSccPackage, VisualHG, XMLSpy, Bugnet Explorer Suite, Tabs Studio, ShartSort, UModel, WinGDB and wave-vs.net. In the end, seven of those 21 (one-third) actually work in the PowerBuilder.NET 12.0 IDE. We'll look at which ones worked, and why some of the others didn't.

Problem 1: Installer Looks Specifically for the Visual Studio IDE
One of the problems I ran into immediately with a couple of the add-ins (Aggiornois and Designbox) is that their installer looks specifically for the Visual Studio IDE and refuses to install the product if it can't find it. Perhaps if some version of Visual Studio was also installed on the machine I was testing the add-ins on I might have gotten a bit further in determining whether the add-in would have worked. However, I didn't think the information would be that useful for a majority of PowerBuilder developers, who most likely don't have Visual Studio installed on their machines.

Problem 2: The Add-in Is Actually a VSPackage Module
When add-in support was originally introduced in Visual Studio 2002, the add-in (a .NET assembly) had to be registered as a COM component using REGASM and a number of additional registry entries had to be made so that Visual Studio could find the COM component registry entries. Beginning with Visual Studio 2005, Microsoft added support for XML registration through the use of an XML configuration file with an .Addin extension. Support for the COM registration method was retained in the IDE for backward compatibility. The Visual Studio Isolated Shell appears to support only XML registration. Or, if it does support COM registration, it's not well documented, and it doesn't use the same registration keys that the full Visual Studio IDE uses. That all will become important later, because in order to use the add-in with PowerBuilder.NET 12.0, we need to modify that XML .addin file to let it know the HostApplication name that PowerBuilder uses.

With all that said, 13 of these 21 "add-ins" (AnksSVN, CodeRush, Dotfuscator, Resharper, Visual Assist, VisualSVN, HgSccPackage, VisualHG, XMLSpy, Bugnet Explorer Suite, UModel, WinGDB and wave-vs.net) didn't include an XML .addin file. As we will discuss later, an add-in implements a couple of .NET interfaces and several methods of those interfaces, particularly the OnConnection method of the Extensibility.IDTExtensibility interface.

I've examined a number of these "add-ins" that did not provide an XML .addin file, and none of the assemblies packaged with these products appear to implement that interface (see Figure 2 in which .NET Reflector is being used to search for assemblies that implement that interface). Finally most, if not all, of these "add-ins" also threw an error from attempting to run the devenv.exe file in an attempt to register themselves with the IDE (see Figure 3). What this seems to imply is that these add-ins are actually VSPackages, a method of adding modules to Visual Studio. For example, DataWindow.NET is a module that can be added into the Visual Studio IDE via the VSPackage approach. The Designbox technical support department did indicate that the Isolated Shell should support VSPackage Modules, and indicated they would be looking into it further because they would like their product to work with PowerBuilder.NET.

The Isolated Shell does support VSPackages, so it's unclear to me at this time whether their inability to work is a result of something Sybase hasn't supported in PowerBuilder.NET 12.0, or a result of modifications that would have to be made by the vendors to support the additional IDE. I did speak to the technical support department for one of the products (Dotfuscator), who indicated that they did not support integration within the PowerBuilder.NET 12.0 IDE, but did work with it via the command line or a MSbuild task.

Problem 3: The Add-in Does Something Very VS IDE Specific
At this point, all of the remaining add-ins did provide an XML .addin for XML registration that - once edited - allowed the add-in to load properly into the PowerBuilder.NET IDE. However, one of those (ShartSort) attempted to add a submenu item to a script editor popup menu item that doesn't exist in the PowerBuilder.NET IDE. In particular, that add-in (which is open source, so I was able to obtain the source code) does this:

private CommandBarPopup GetRefactorPopup()
{
CommandBars commandBars = (CommandBars)Application.CommandBars;
Guard.IsNotNull(commandBars, "CommandBars");
CommandBar itemContextBar = GetCommandBarByName(commandBars, VSMenuConstants.EditItemContextMenu);
Guard.IsNotNull(commandBars, "itemContextBar");

CommandBarPopup editCodePopup = GetCommandBarPopup(itemContextBar, "Code Window");
Guard.IsNotNull(editCodePopup, "Code window");
CommandBarPopup refactorPopup = GetCommandBarPopup(editCodePopup.CommandBar, "Refactor");
Guard.IsNotNull(refactorPopup, "Refactor popup");

return refactorPopup;
}

In order to add a submenu item to the Refactor menu option that appears in the script editor popup menu for C# (see Figure 4a) and which doesn't appear in the PowerScript script editor popup menu (see Figure 4b). As a result, the add-in throws an exception. I wasn't expecting this particular add-in to add much functionality to the PowerBuilder.NET IDE, but included it for completeness.

Looking at Those That Work
Once we know we're dealing with a real add-in, the first thing we need to do after installing it is to determine where it installed the .addin XML file. In most cases, the add-in installed them in one of two locations, depending on whether it was attempting to do an All Users install or an install for a specific user. Generally, you would look in one of the following locations (based on XP, the location will vary on Vista and Windows7):

  • All Users: All Users\Application Data\Microsoft\Visual Studio\<version>\Addins - Where <version> is the version of Visual Studio that the add is supports (e.g., 9.0)
  • Specific User: <username>\My Documents\Visual Studio 2008\Addins - Where <username> is the login name of the user who installed the add-in

Once we've located the .addin file, we need to edit one portion so that it knows about the PowerBuilder.NET IDE. The following is an excerpt from an .addin file that I've modified. The file originally came with one <HostApplication> section referring to Visual Studio; I've added a second HostApplication section so that the plugin will work with PowerBuilder.NET as well. Note that the spelling of the HostApplication text must be exact. I spent a couple of hours trying to figure out why one of the add-ins wouldn't load (or even show up in the list of available add-ins) until I realized that I had used "PowerBuilder .Net" rather than "PowerBuilder .NET" (note the capitalization difference) in the .addin file. When you are editing add-in files, also note that there should be a space between "PowerBuilder" and ".NET". One final caution: make sure that the file is saved out with the encoding that is indicated in the XML tag within the file. The Visual Studio shell is very picky about the encoding of the file and the encoding declared in the XML matching:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Extensibility xmlns="http://schemas.microsoft.com/AutomationExtensibility">
<HostApplication>
<Name>Microsoft Visual Studio</Name>
<Version>9.0</Version>
</HostApplication>
<HostApplication>
<Name>PowerBuilder .NET</Name>
<Version>12.0</Version>
</HostApplication>
<Addin>

Similarly, PowerBuilder.NET 12.0 does by default look in a couple of particular locations for such .addin files. In particular:

  • All Users: All Users\Sybase\PowerBuilder 12.0\Addins
  • Specific User: <username>\Application Data\Sybase\PowerBuilder 12.0\Addins - Where <username> is the login name of the user who installed the add-in

Once again, those are for XP. The location will vary in a later operating system. For example, on Windows 7 the specific user addin location is:

Users\<username>\AppData\Roaming\Sybase\PowerBuilder 12.0\Addins

So after modifying the .addin file, I copied it to one of those locations (the latter one specifically). PowerBuilder.NET also provides a configuration setting in the Tools->Options dialog that allows you to modify the locations where it will look for those files (see Figure 5). Once the .addin files are located, the Tools->Add-In Manager dialog within the IDE that allows you to control whether the add-ins are enabled and when they load (see Figure 6).

Let's look at what worked:

CopySourceAsHTML: An open source add-in that allows you to copy source code with formatting preserved to be pasted into web pages as HTML.

Black Duck Koders: Black Duck Koders maintains an indexed database of billions of lines of open source project source code. The plug-in allows you to do searches against that database looking for code snippets or examples of how to use certain language features. At the time of this writing, the database does not include any PowerBuilder code projects, although it does contain a few projects written in other languages that are intended to interoperate with PowerBuilder. I did submit the open source PFC project to Black Duck Koders, and they have indicated that they will include it in the database in a future update.

PhatStudio: An open source add-in that does file search by substring match within a solution. While the add-in loaded correctly, it looks like it may need some configuration to work correctly with a PowerBuilder solution. The initial configuration is highly tailored for specific Visual Studio file extensions (.cpp, .aspx, etc.).

Software Diagnostics Developer Edition: Software Diagnostics makes an integrated recorder, debugger and profiler to aid in application debugging. The plugin integrates those utilities directly into the IDE.

TracExplorer: An open source add-in that allows you to interact with Trac, an open source web-based project management and bug reporting tool.

VsTortoise: An open source add-in that provides integration to the Subversion source control system.

Tabs Studio: When you have a large number of tabs open simultaneously in Visual Studio, it becomes hard to navigate between them, because only one row of tab controls is used and then a dropdown list is provided to navigate to the other tabs. Tabs Studio modified the behavior of Visual Studio so that multiple rows of tab controls are supported, allowing all of the tabs to be visible at once.

Figure 7 shows the PowerBuilder.NET 12.0 IDE with a number of the add-ins enabled. Tabs Studio has arranged the numerous tabs I have opened and added a toolbar with items to work with them. There is a Koders search pane on the left side of the screen. Also note the Copy As HTML, Koders Search, and VSTortoise menu options in the context menu in the script painter. Finally, also note the "TeamSybaseAddin" menu option in the context menu. That's a result of our creating our own add-in, something we're covering in the next part of this article.

Let's Build Our Own
One of the reasons that a number of these add-ins are open source is because Visual Studio provides the ability to create an add-in for Visual Studio within Visual Studio. In fact, there is a wizard that will walk you through the initial creation of one (see Figure 8).

If you've got Visual Studio available, fire it up and we'll walk through the creation of a simple add-in.  If not, don't worry, because in a later article we'll look at how we can create the same add-in using PowerBuilder.NET. Just follow along in this part so you gain an understanding of what needs to be done to create one.

The initial source code template that the add-in wizard creates simply adds a menu item to the Tools menu that doesn't do anything. We're going to expand on that a bit by adding a menu item to the source editor context window and having both of them display a message box so we know they're working.

The main thing the add-in needs to do is provide a class that implements the Extensibility.IDTExtensibility and EnvDTE.IDTCommandTarget interfaces from the .NET Framework. By convention, the wizard automatically creates a class called Connect that does this, and many of the add-ins we've looked at simply kept that name.

public class Connect : IDTExtensibility2, IDTCommandTarget

There are a number of methods of those interfaces that have to be implemented by the class: Connect, OnConnection, On Disconnection, OnAddInsUpdate, OnStartupComplete, OnBeginShutdown, QueryStatus and Exec. Implemented means that the method has to be declared in the implementing class, in most cases it doesn't mean that the code has to do anything. The wizard creates "virtual" declarations (no code other than the declaration) for all but the OnConnection, QueryStatus and Exec functions, and we won't need to code any of those functions. We will be adding a helper function of our own, and modifying the code generated by the wizard for the OnConnection, QueryStatus and Exec methods.

If your popup is going to be adding menu options to various toolbars and popup menus (called CommandBars), you're going to need to be able to locate them by name. So the first thing we're going to do is create a private helper function within the add-in to do that:

private CommandBar GetCommandBarByName ( CommandBars commandBars, String name ){
foreach (CommandBar commandBar in commandBars)
{
if (commandBar.Name == name)
return commandBar;
}
return null ;
}

The OnConnection method is the method the IDE first calls when it's getting ready to invoke the add-in, so it's your opportunity to do your initialization, including the addition of any menu or toolbar items into the IDE. We're going to modify the code generated by the wizard so that it looks like Listing 1.For simplicity, I've removed the code that the wizard was using to handle localization of the toolbars. You may want to keep it if you're supporting multiple languages. I've modified the method that the wizard was using to locate the Tools entry on the main menu so that it uses our new GetCommandBarByName method. I'm also using that same method to find the popup menu for the script editor.

Now that we have those two references, we're adding the AddNamedCommand2 method to create our two new commands: one for the Tools menu item and one for the popup menu. The AddControl method of the Tools and popup menu commandbars is then used to add those commands to each location.

Once the add-in has been loaded, the next thing the IDE will do is call the QueryStatus method passing in the name of the command item to determine the status it should have. We're going to modify the wizard-generated code to the following so that a status is returned for each of our two new command items, indicating that they should both be enabled:

public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)
{
if(neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
{
if(commandName == "TeamSybaseAddin.Connect.TeamSybaseAddinToolbar")
{
status = (vsCommandStatus)vsCommandStatus.vs CommandStatusSupported|vsCommandStatus.vsCommandStatusEnabled;
return;
}
if (commandName == "TeamSybaseAddin.Connect.TeamSybaseAddinEditor")              {
status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
return;
}
}
}

Finally, the add-in has to do something to be useful. The IDE calls the Exec method of our adding, passing in the name of the command (and potentially options). We're going to modify the wizard-generated code to do something not terribly useful by simply showing a messagebox so that we know the add-in is working:

public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
handled = false;
if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if(commandName == "TeamSybaseAddin.Connect.TeamSybaseAddinToolbar")
{
MessageBox.Show("If this was a real plugin, something real would have just happened.");
handled = true;
return;
}
if (commandName == "TeamSybaseAddin.Connect.TeamSybaseAddinEditor")
{
MessageBox.Show("If this was a real plugin, something real would have just happened.");
handled = true;
return;
}
}
}

The wizard also created an .addin file for us. We're going to have to edit it to include the reference to PowerBuilder.NET as a HostApplication. I also stripped out a lot of the non-essential information it included, such as the help dialog text and icon (see Listing 2).

Compile the code, and then drop the DLL and the .addin file into the Addin directory that PowerBuilder uses and it should show up in the Add-In Manager for use in PowerBuilder.NET. Note that since it is a Visual Studio add-in, it will start showing up in Visual Studio as well unless you remove it from the Visual Studio add-in path and/or remove the HostApplication entry for Visual Studio from the .addin file.

Next Steps
Now that you know how to create a basic addin, you can research extending it to something more useful on your own. Microsoft's documentation on Automation and Extensibility for Visual Studio is a good reference. A number of those open source addins we've looked at already are good sources for samples of how to implement that functionality.

What would we create? Well, one thing that Visual Studio has that seems to be missing from PowerBuilder.NET 12.0 is the Edit->Advanced->Format Document command for reformatting of source code. We need something like a PowerBuilder.NET version of SmartScripter. We might also be able to use a PowerBuilder.NET version of PBCommenter.

If you do create something, be sure to share. Perhaps making it available on an open source project hosting site like CodePlex, or even writing a PBDJ article explaining how you accomplished it. The add-in API for the PowerBuilder IDE is finally open for use, and so it's up to us to make good use of it.

More Stories By Bruce Armstrong

Bruce Armstrong is a development lead with Integrated Data Services (www.get-integrated.com). A charter member of TeamSybase, he has been using PowerBuilder since version 1.0.B. He was a contributing author to SYS-CON's PowerBuilder 4.0 Secrets of the Masters and the editor of SAMs' PowerBuilder 9: Advanced Client/Server Development.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.