Technotes, HowTo Series

AddIn Building Guide
Version 2.0 (not finished)

Version 1.0 by Mike Krüger, mike@icsharpcode.net
Version 2.0 by Daniel Grunwald, daniel@danielgrunwald.de

Contents
1 About the AddIn Building Guide
2 File Organization
3 Setting up the project
3.1 Project properties
3.2 The .addin file
4 Using Resources
4.1 XmlForms and other files
4.2 Bitmaps
4.3 Strings (localization)

1 About the AddIn Building Guide
This document may be read as a guide to writing ♯Develop which comply with the building scheme and it gives an introduction about how ♯Develop is build. It is not a documentation about how SharpDevelop can be extended.
2 File Organization
Each AddIn should have an own directory somewhere inside the src\ folder and it should provide a project file that is used to build/clean the project.

Your AddIn has an own directory and the root folder contains a solution file. Inside the root folder, there can be two subdirectories: Project and Test. 'Project' is the Addin itself, 'Test' is a set of unit tests for the AddIn (unit test source files and project file).
The 'Project' directory contains the following subdirectories and files:
Name	Contents	Description	
ProjectName.csproj	MSBuild file	Project file for the addin	
ProjectName.addin	AddIn definition file	Contains the xml code for the XML tree.
Should use 'CopyToOutputDirectory'.	
Src\	Source code files	Here is the source code for your add-in	
Resources\	Any type of file 	Here are all resources which are compiled into the add-in assembly	
Doc\	Documentation (not in *.doc format; use .txt or .html if you need formatting)	Here may lie documentation to the add-in	
RequiredLibraries\	*.dll files	Here are libraries that the add-in uses in binary form	

3 Setting up the project
You can create a test addin project by using the „SharpDevelop AddIn“ template. Note that it won't compile out of the box, you are only given a directory structure with some file to get you started a little faster.
The first thing you need to do it set the project properties.
3.1 Project properties
Set the project output path to some subfolder inside SharpDevelop/AddIns/AddIns. If you're AddIn won't be distributed with SharpDevelop, put it in its own subfolder inside SharpDevelop/AddIns/3rdparty.
What the template didn't do for you, either, is setting up the references to SharpDevelop. You will need a reference to ICSharpCode.Core.dll and ICSharpCode.SharpDevelop.dll. Set 'copy reference to output path' to false on these two references.

3.2 The .addin file
The .addin file is the most important file of your addin. You can specify there what parts of SharpDevelop your addin is extending. Your actual addin library (.dll) will only be loaded when it is first needed.
When you create a new AddIn using the template, the following file has already been generated for you:
<AddIn name        = "MyAddInName"
       author      = "username"
       copyright   = "GNU General Public License"
       url         = ""
       description = "TODO: Put description here">
	
	<Runtime>
		<Import assembly = "MyAddInName.dll"/>
	</Runtime>
	
	<Path name = "/SharpDevelop/Workbench/Pads">
		<Pad id       = "MyAddInNamePad"
		     category = "Main"
		     title    = "MyAddInNamePad"
		     icon     = "PadIcons.NUnitTest"
		     shortcut = "Control|Alt|T"
		     class    = "MyAddInName.TestPad"/>
	</Path>
</AddIn>

This demonstrates how an .addin file works: the <Runtime> section describes what assemblies are used by the AddIn. Then any number of extension paths is following. This way, you can insert elements into the AddInTree. MyAddInName.TestPad is a class defined in MyAddInName.dll. That assembly is only loaded, when the instance of the class is created. This is not when SharpDevelop is started, but when the pad content is shown first. So a pad that is in the background since the start of SharpDevelop won't cause the assembly to be loaded.
For more information about the possible extensions paths and how the AddinTree works in detail, read the document „AddInTree“ in this folder.
The addin file is not compiled into the assembly but copied to the output directory (BuildAction=None, CopyToOuputDirectory=Always; the template should already have set these properties for you).
4 Using Resources
4.1 XmlForms and other files
The template demonstrates the use of resource files by using a XmlForms to display the pad content. Your AddIn does not need to use XmlForms, the template just shows the use of resources (and XmlForms).
You can put any files into the Resources directory (see table in chapter 2.1). Set the build type to 'EmbeddedResource' and file will be compiled into the assembly. You can then access the file by using Assembly.GetExecutingAssembly().GetManifestResourceStream("MyAddInName.Resources.MyUserControl.xfrm").
Unlike SharpDevelop 1.x, the compiler will prepend the resource files name with the root namespace in the project settings and the folder it is stored within the project. Therefore, the file name MyUserControl.xfrm gets expanded to MyAddInName.Resources.MyUserControl.xfrm.
GetManifestResourceStream returns a stream, so don't forget to close it when you are finished.
4.2 Bitmaps
There are two types of bitmaps:
1. Bitmaps you need in your addin
Just put the bitmaps in the Resources directory and set the action to 'EmbedAsResource'. You can then use Assembly.GetExecutingAssembly().GetManifestResourceStream("RootNamespace.Resources.MyImage.png")
to get a stream to the resource file. You can create a bitmap from that stream, and then dispose the stream.

Q: Can I use a resource file (*.resources/*.resx), wouldn't this make things easier?
A: Yes and No. It would be harder to alter the bitmap. I know that most bitmaps won't be altered during their life. The main reason for doing this is that #Develop may be ported to a newer .NET Version and the resource files will be broken onto the next .NET version. 
This will make it more difficult to bring #Develop to the new framework. I recommend all people not storing anything other than strings into resource files. Binary data is a 100% no go.

2. Bitmaps for the ResourceService
Bitmaps must be registered before they can be used in the ResourceService. The ResourceService is used for the icons of the pads and menu items.
Currently, there is no easy way to make the ResourceService aware of icons supplied with your Addin. The easiest way to add new bitmaps is to go into the SharpDevelopResources/BitmapResources directory and put your bitmaps in a subdirectory.
Then you can edit the text file SharpDevelopResources/BitmapResources/BitmapResources.res and include a line for your bitmap (do this near the lines of the other bitmaps of the same subdirectory). Call BitmapResources/build.bat and the resources will be compiled and inserted into the StartUp project (SharpDevelop.exe). Compile SharpDevelop using SharpDevelop/src/build.bat to finally use the new resource file.
There is also another possible way when you want to distribute your resources separately: Make a separate directory like  SharpDevelopResources/BitmapResources for your project and use a similar build file to build the bitmaps in to a BitmapResources.resources binary file. Do not edit the BitmapResources.resources file directly, always use the build script (see question in the previous section)! Then add the BitmapResources.resources file as embedded resource into your addin assembly. To register the file in the ResourceService, create a AutoStart command that calls
ResourceService.RegisterImages("MyAddinName.Resources.BitmapResources",
                               GetType().Assembly)
In the future, we might implement a way where your *.addin file allows you to specify a resource directory for use with the ResourceService without requiring SharpDevelop to load your addin assembly on startup.

4.3 Strings (localization)
For localizable strings, you can use SharpDevelop's resource service.
To request a localized string, use StringParser.Parse(“${res:FullResourceName}”).
The string resource names should be in the format “YourAddInName.ResourceName”.
In all strings in the XML addin definition file; in XmlForms and for the MessageService, resource access in “${...}” are automatically resolved, you do not need to call StringParser.Parse there.
How to supply your strings:
Add a .resources file to the “Resources” directory of your addin (SharpDevelop has a template in the “Misc” section). You should name it “StringResources.resources”.
In this file, you enter the “fall back” values when a resource entry is not found in a language-specific file. Normally, the US-English strings should be placed in that file.
Put the translated strings in files like “StringResources.de.resources” in the resource directory (“de” is the language code). The translated strings will be automatically compiled into satellite assemblies.
How to make SharpDevelop aware of your strings:
Run the following command when your strings are needed the first time:
ResourceService.RegisterStrings("MyAddinName.Resources.StringResources",
                                GetType().Assembly)
This will make SharpDevelop load the strings and merge them into the ResourceService. The correct satellite assembly will automatically be (re)loaded whenever the user changes the UI language.