What version?
First we had do decide what version of #Develop we wanted to integrate with. There were two choices: Version 4.3 is the current stable version and therefore the obvious candidate. Version 5 is the upcoming version and currently in preview state. Looking at the future, it made sense to choose version 5. However it is still in preview state and even though we believe it is already quite stable, we did experience several crashes. Also, we don't know when version 5 goes into beta or RTM so we decided to choose 4.3. We tested with both versions and we expect to quickly upgrade to version 5 once it has stabilized.
Custom build or stock version?
With an IDE like Visual Studio this is a simple choice because there are only stock versions and everybody uses those. #Develop, however, is open source so we may choose to do a custom build. Because we want to minimize the maintenance load on our team, the initial approach was to extend a stock version using the standard addin model of #Develop. Doing so we ran into several issues. Especially, extending the debugger forced us to change this approach. We still use the stock 4.3.1 code base, but we had to remove the debugger addin. We also decided to integrate the entire IDE into our own setup. This makes it easier for us to test our integration because we know the exact version and we avoid potential problems in the field with existing #Develop installations.
The dot42 addin
#Develop is a highly extensible platform. It consists of a small core that has a namespace tree and an addin system. An addin extends the functionality of #Develop. The namespace tree is used to extend all kinds of functions like menus, debuggers, project types etc. An addin is implemented by an xml file (.addin) and usually one or more assemblies. The addins are automatically loaded from the AddIns folder.
Parts of the dot42 addin is a dot42 specific project behavior (this is similar to a project sub type in Visual Studio). To add this project behavior, we had to write one C# class and include the following snippet in our .addin file:
<Path name="/SharpDevelop/Workbench/ProjectBehaviors"> <Condition guid="{337B7DB7-2D1E-448D-BEBF-17E887A46E37}" name="ProjectBehaviorSupported"> <Class class="Dot42.SharpDevelop.Dot42ProjectBehavior" id="Dot42ProjectBehavior" /> </Condition> </Path>
This snippet registers a class (Dot42.SharpDevelop.Dot42ProjectBehavior) in the namespace tree under the well known path "/SharpDevelop/Workbench/ProjectBehaviors". The Condition element ensures that the dot42 project behavior is used only when the project has the sub type identified by the given guid.
Next to the project behavior, the dot42 addin contains a debugger, various "pads" (UI elements) for the debugger, menu items, XML editors and more. All of these are integrated into the #Develop platform using Path elements in the addin file.
We ran into another issue. Implementing our own debugger was a matter of implementing the simple interface IDebugger as published by #Develop. However, the standard debugger UI (pads for running threads, call stacks, local variables, etc.) assumes that the current debugger is always of type WindowsDebugger. Even worse, the UI crashes if this is not the case. For this reason, we had to remove the stock debugger addin and build our own UI pads for threads, call stacks, etc.
Breakpoints were a lot easier. These are special kind of bookmarks and by just querying the BookmarkService we quickly found BreakpointBookmark. We could use it as is without doing anything special to toggle them in the UI.
Hopefully we can help the #Develop team to improve their platform.
Next to the project behavior, the dot42 addin contains a debugger, various "pads" (UI elements) for the debugger, menu items, XML editors and more. All of these are integrated into the #Develop platform using Path elements in the addin file.
What did we encounter?
The addin system and namespace tree make it easy to extend #Develop but it lacks an important feature: you cannot remove or alter existing elements. For example we wanted to remove several menu items that are added by the stock debugger addin. This is not possible. More precisely, we wanted to add an additional condition to those menu items so they would be hidden for a dot42 project subtype. This is also not possible. A solution to this problem would be to modify the stock addin files, but that was something that we wanted to avoid. We posted a suggestion the #Develop forum to extend the core of #Develop to make this easier in.We ran into another issue. Implementing our own debugger was a matter of implementing the simple interface IDebugger as published by #Develop. However, the standard debugger UI (pads for running threads, call stacks, local variables, etc.) assumes that the current debugger is always of type WindowsDebugger. Even worse, the UI crashes if this is not the case. For this reason, we had to remove the stock debugger addin and build our own UI pads for threads, call stacks, etc.
Breakpoints were a lot easier. These are special kind of bookmarks and by just querying the BookmarkService we quickly found BreakpointBookmark. We could use it as is without doing anything special to toggle them in the UI.
To wrap up
It has been a pleasure to integrate dot42 with #Develop. After the many many many hours we spend digging through tons of COM interfaces that make up Visual Studio, it is an absolute delight to extend an IDE that is fast and has all the sources available.Hopefully we can help the #Develop team to improve their platform.
Interesting read, thanks for sharing.
ReplyDelete#Develop (and .NET in general) supports several other languages besides C#. Dot42 is billed as "C# for Android", but your "how it works" page says you compile IL to Dalvik code, not C# to Dalvik code.
ReplyDeleteI'm looking for an Android solution, but I'd prefer to use other languages rather than C#. If I try to do that, will dot42 support it? What sort of difficulties will I run into?
This really depends on what language you want to use.
DeleteVB.NET uses a completely different set of API's which we do not support. F# uses a lot of value types, which may also give issues.