Within 12 hours of announcing
Moma we received 114
submissions generated by the tool detailing what features were
missing.
There were a number of interesting discoveries, these are:
False Positives: One of the most commonly reported
error were method calls and property accesses to the
System.Net.WebRequest class. These turned out to be
incorrect, since this class is an abstract class that happens
to have stubbed all those methods and throws
NotImplementedExceptions as a mechanism to ensure
that implementors get those methods right.
Developers will always be using a subclass that is created
by the WebRequest.Create factory method (It makes me
wonder why the methods were not flagged as abstract)
New or overwritten methods: In a number of places,
overwritten methods are showing up in the report. For
example, a very common one is Exception.GetType(), or
with Label::set_Text (the Label.Text setter), in both
cases the problem is caused by 2.0 introducing a new method
that overrides the base definition.
The code, if compiled with Mono would have produced the
correct result, but the binaries would not have worked as the
member references were done to newer classes. Most of these
are innocuous, and we already introduced the missing APIs for
the most commonly reported problems.
Outdated MonoTODOs: We have plenty of miss-used
MonoTODOs, these are the messages that we used internally to
flag that something in a method is incomplete, and ideally, it
should provide an explanation of why the flag was set.
But this is an attribute that we have used a bit recklessly
over the past few years, and has had a number of meanings,
from valid uses like "This method only implements half the
specification" to less useful instances like "I do not
like this API", to "Someone should optimize this
routine" to "One day I would like to look improve
this". So plenty of MonoTODOs were hints aimed at the
source code maintainer, and not really to the developer that
consumes the API.
Eliminating all of the bogus MonoTODOs is an ongoing
process, but we might still get a few erroneous reports for a
while that might confuse developers.
In particular, a lot of people hit on various methods in
DataSet. None of those errors are correct, they are
implemented, but they had old "MonoTODO" flags left behind.
Limitations in the .NET API: In a number of cases,
developers have resorted to P/Invoke into the Win32 API, and
the results are very interesting, the top reasons for using
P/Invoke have been:
- Message dispatching: SendMessage,
PostMessage.
- GDI/DC operations: GetDC,
CreateBrush, CreateRgn,
SelectObject, DrawText.
- Window operations: SetWindowPos,
SetForegroundWindow ShowWindow,
GetWindowRect, ClientToScreen,
MoveWindow and Hook handling.
- Allocation: GlobalAlloc
- Fonts and Printing Dialogs.
- Shell access: to get recently used files, icons
for files and a handful of others.
There are of course many more, but these are the majority
of the uses.
Some of those APIs are easily translated into portable
calls (Message dispatching, window operations, allocation)
while others are very hard (GDI/DC operations) and some others
are better if replaced as a chunk with alternative code.
Our next goal will be to provide a portability assembly
that will take care of those operations that are easily
translated, so P/Invoke calls would be replaced with calls
into this portability assembly. On Windows, we will continue
to P/Invoke the same methods, while on other platforms we
would route the request through Mono's internals.
In the case of Shell access, the best thing to do is to
provide a cross-platform API that does the integration with
the user shell, and provide an API that developers can
migrate to. This would be effectively a "complement" for APIs
that are today not available for Windows.Forms and even be a
lot simpler for many people to use than resorting to
P/Invoking.
Lack of Comments: The first version of Moma lacked support for
entering some comments from the person submitting the report,
so all we got in our hands are the list of unimplemented
methods, but we do not know much about the applications that
are using it.
When we ran this over applications we had, we were able to
identify pieces that can be replaced as units based on the
class names where they were used (this is part of the report
that people get, but not part of the information transmitted
to us). For example, a commercial application that we want
to port (with the assistance of the owners) has neatly
isolated things like printing dialogs in its own file.
Cecil and Obfuscated Assemblies: Some of the
applications that were processed were obfuscated. But the
P/Invoke signatures also seem obfuscated, am not sure how
those are actually resolved at runtime.
Moma's version: at some point, we will need to
enable Moma to download new API definitions from our site, to
allow developers to check back if their applications are ready
without having to download a new copy of Moma.
Accounting: There are a number of limitations on the
accounting and statistics that can be done with the results.
It is hard to tell with precision how many of these are
.NET 1.1 vs .NET 2.0, which ones are C# and VB and which ones
are ASP.NET vs Windows.Forms. This is caused because Moma
only uploads lists of missing methods, it does not upload
other information that might be confidential, so Moma erred on
the side of safety and removed data that was not necessary for
us.
The accounting for ASP.NET is further limited, since Moma
does work on assemblies, and not on .aspx files. Those that
used ASP.NET are most likely helper code that is used in
ASP.NET applications.
Another challenge with the data is that each submission
contains the report for all the assemblies submitted. The
end user might have chosen a single program, a single project
(made up of many executables and libraries) or multiple
programs.
This is not a problem, but it is worth keeping in mind when
you read the results below.
Results
From the submitted applications, ten of them work out of
the box without any changes; Another 30 contained reports that
could be ignored (MonoTODOs that should not have been there,
the NotImplementeds that did not exist). Almost all of
them contain calls to methods that are either easy to
implement, or were already implemented.
At least 29 of the applications are 2.0-based
(by looking at Label::set_Text and Exception::GetType) and 16
of them are VisualBasic applications. One of the
applications embeds IKVM.
32 applications were ASP.NET applications; 56 used
Windows.Forms; 32 use System.Data and 44 used System.Drawing
(see the above caveats about interpreting this data; This is
based on assemblies and submissions, not on projects).
P/Invoke usage, from the 114 applications submitted:
- 67 do not contain any P/Invoke calls.
- 9 contain between 1 and 3 P/Invoke calls.
- 10 contain between 4 and 10 P/Invoke calls.
- 9 contain between 11 and 20 P/Invoke calls.
- 5 contain between 22 and 48 P/Invoke calls.
- 6 contain between 55 and 100 P/Invoke calls.
- 5 contain between 102 and 180 P/Invoke calls.
- 3 container more than 200 P/Invoke calls
In the
three cases, about half of the P/Invokes are to their
own libraries.
(details).
So roughly half of the .NET applications can port without
any concerns about P/Invoke. The remaining 40% are easily
portable (those that have less than 48 P/Invokes) another 5%
would take a few weeks, and maybe a Linux/Mono expert to
assist on the port. The last 5% will require some large
refactoring to work on Linux.
The application that uses the most P/Invoke that we have
received so far seems to be some kind of designer and also
happens to use the
System.Security.CodeAccessPermission::Assert a lot.
Update: Sebastien comments that this is most likely
a case of badly designed software, it is intended to avoid
lots of stack walks to check for permissions. The above was
probably copy/pasted from some recipe as an optimization that
was useful in the 1.x frameworks. It is not required for 2.0.
From the received applications, 15 of them need more work
on VisualBasic. Although most of the Visual Basic
applications reported NotImplementedExceptions for a
number of their methods in CompilerServices, that turned out
to be false positives, which leaves us with only 24 methods
missing in the VB.NET runtime
Unsupported Technologies
There are a few features that we do not support, and do not
plan to support, in Mono. These technologies are either being
phased out (EnterpriseServices, System.Messaging, to be
replaced by WCF/Olive), or they would require a lot of work
that we are currently not planning on doing (COM).
EnterpriseServicesis was used only by two applications, and all
they seem to miss is a call to
ServicedComponent::Dispose(). I suspect these are
generated by a tool, considering the lack of any other methods
references (and that we know are flagged).
System.Messaging is another of the libraries that we have
not implemented and it showed up in only three applications.
COM, showed up in three applications.
Update
By the time this post went up this morning, we had received
171 submissions.