<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4599268833456028124</id><updated>2012-02-19T21:06:18.549+01:00</updated><category term='Polygon Clipping'/><category term='C++'/><category term='Benchmark'/><category term='Interoperability'/><category term='Wrapper'/><category term='Mono'/><category term='Clr'/><category term='C++/Cli'/><category term='Boost'/><category term='Cgal'/><category term='.Net'/><title type='text'>The Crag Of Rogue Modron</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rogue-modron.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4599268833456028124/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://rogue-modron.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Rogue Modron</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>3</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4599268833456028124.post-442035009624937513</id><published>2012-02-18T10:59:00.001+01:00</published><updated>2012-02-18T10:59:30.586+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Boost'/><category scheme='http://www.blogger.com/atom/ns#' term='Clr'/><category scheme='http://www.blogger.com/atom/ns#' term='Cgal'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Cgal /clr</title><content type='html'>&lt;span style="font-size: small;"&gt;Trying to use &lt;a href="http://www.cgal.org/"&gt;Cgal&lt;/a&gt; in a C++ project with Common Language Runtime support (/clr) you may encounter a few problems.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;Tested with Visual Studio 2010 using Cgal 3.9 and Boost  1.49.0 beta 1, x86 build.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;First ...&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If the following message appears when you start your application:&lt;br /&gt;&lt;blockquote&gt;The application failed to initialize properly (0xc000007b).&lt;/blockquote&gt;&lt;br /&gt;The problem may be due to Boost.Thread, which is required by Cgal.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;According to&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lists.boost.org/Archives/boost/2009/04/151043.php"&gt;http://lists.boost.org/Archives/boost/2009/04/151043.php&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;modify&lt;br /&gt;&lt;br /&gt;$BOOST_ROOT/libs/thread/src/win32/tss_pe.cpp&lt;br /&gt;&lt;br /&gt;in this way:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;pre&gt;&lt;code class="cpp"&gt;&lt;br /&gt;#if (_MSC_VER &amp;gt;= 1400)&lt;br /&gt;//#pragma section(".CRT$XIU",long,read)&lt;br /&gt;#pragma section(".CRT$XCU",long,read)&lt;br /&gt;#pragma section(".CRT$XTU",long,read)&lt;br /&gt;#pragma section(".CRT$XLC",long,read)&lt;br /&gt;        __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;&lt;br /&gt;        //__declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;&lt;br /&gt;        __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;&lt;br /&gt;        __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;&lt;br /&gt;#else&lt;/code&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;The __declspec lines were added in order to close this ticket (Severity - Cosmetic):&lt;br /&gt;&lt;br /&gt;&lt;a href="https://svn.boost.org/trac/boost/ticket/2199"&gt;https://svn.boost.org/trac/boost/ticket/2199&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Second ...&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If the following assertion message appears at runtime:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Wrong rounding: did you forget the  -frounding-math  option if you use GCC (or  -fp-model strict  for Intel)?&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Define CGAL_DISABLE_ROUNDING_MATH_CHECK and rebuild your project. &lt;br /&gt;&lt;br /&gt;However, you should have seen this compiler warning:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;warning C4996: '_controlfp_s': Direct floating point control is not supported or reliable from within managed code.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/c9676k6h(v=vs.100).aspx"&gt;_controlfp_s&lt;/a&gt; is used directly by Cgal but, from MSDN:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;This function is deprecated when compiling with /clr (Common Language Runtime Compilation) or /clr:pure because the common language runtime only supports the default floating-point precision.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;So you should not expect identical results if you run the same project compiled with or without Common Language Runtime support.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4599268833456028124-442035009624937513?l=rogue-modron.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rogue-modron.blogspot.com/feeds/442035009624937513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rogue-modron.blogspot.com/2012/02/cgal-clr.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4599268833456028124/posts/default/442035009624937513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4599268833456028124/posts/default/442035009624937513'/><link rel='alternate' type='text/html' href='http://rogue-modron.blogspot.com/2012/02/cgal-clr.html' title='Cgal /clr'/><author><name>Rogue Modron</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4599268833456028124.post-9098310901702761088</id><published>2011-11-02T23:05:00.002+01:00</published><updated>2011-11-05T10:12:49.553+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Benchmark'/><category scheme='http://www.blogger.com/atom/ns#' term='Mono'/><category scheme='http://www.blogger.com/atom/ns#' term='Interoperability'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Invoking Native</title><content type='html'>&lt;span style="font-size: small;"&gt;A quick overview of the different ways to call unmanaged APIs from managed code, with .Net and also with Mono.&lt;br /&gt;&lt;br /&gt;The inspiration for this post came after reading a couple of articles. The first relating to &lt;a href="http://code.google.com/p/sharpdx/"&gt;SharpDX&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code4k.blogspot.com/2010/10/managed-netc-direct3d-11-api-generated.html"&gt;A new managed .NET/C# Direct3D 11 API generated from DirectX SDK headers&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The second:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://ybeernet.blogspot.com/2011/03/techniques-of-calling-unmanaged-code.html"&gt;Techniques of calling unmanaged code from .NET and their speed&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;that in substance is on the same topic of this post but doesn't provide enough  sample code, in particular for the final benchmark.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Native library&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;In the following examples we will use a function exported from a phantomatic library called Native.dll (Native.so for Mono on Unix/Linux), written in C and compiled with Cdecl calling convention.&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="cpp" title="Native.h"&gt;&lt;br /&gt;//&lt;br /&gt;// Native.h&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;void DoWithIntPointer(int a, int b, int* r);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class="cpp" title="Native.c"&gt;&lt;br /&gt;//&lt;br /&gt;// Native.c&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;#include "Native.h"&lt;br /&gt;&lt;br /&gt;void DoWithIntPointer(int a, int b, int* r) {&lt;br /&gt;    *r = a + b;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size: small;"&gt;DoWithIntPointer simply calculates the sum of two integer but having parameters passed by value and by reference it will allow us to see some peculiarities.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Explicit P/Invoke&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;Let's start with a classic P/Invoke example:&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="cs" title="TestPInvoke.cs"&gt;&lt;br /&gt;//&lt;br /&gt;// TestPInvoke.cs&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;using System.Runtime.InteropServices;&lt;br /&gt;&lt;br /&gt;class TestPInvoke {    &lt;br /&gt;    [DllImport(&lt;br /&gt;        "Native.dll", &lt;br /&gt;        CallingConvention = CallingConvention.Cdecl&lt;br /&gt;    )]&lt;br /&gt;    private static extern void DoWithIntPointer(&lt;br /&gt;        int a, &lt;br /&gt;        int b, &lt;br /&gt;        out int r&lt;br /&gt;    );&lt;br /&gt;    &lt;br /&gt;    public static void Main() {&lt;br /&gt;        int result = 0;&lt;br /&gt;        DoWithIntPointer(1, 2, out result);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size: small;"&gt;The extern keyword tells the compiler that DoWithIntPointer is defined elsewhere while the DllImport attribute provides directions to trace it.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Implicit P/Invoke - C++/Cli&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;With C++/Cli we can write wrappers for native libraries with relative ease but it cannot be used with Mono. Here we have the C++/Cli wrapper for our Native library:&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="cpp" title="NativeCppCliWrapper.cpp"&gt;&lt;br /&gt;//&lt;br /&gt;// NativeCppCliWrapper.cpp&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;#include "Native.h"&lt;br /&gt;&lt;br /&gt;namespace NativeCppCliWrapper&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;using namespace System;&lt;br /&gt;using namespace System::Runtime::InteropServices;&lt;br /&gt;&lt;br /&gt;public ref class Wrapper {&lt;br /&gt;public:&lt;br /&gt;    static void CallDoWithIntPointer(&lt;br /&gt;        Int32 a, &lt;br /&gt;        Int32 b, &lt;br /&gt;        [Out] Int32% r&lt;br /&gt;    ) {&lt;br /&gt;        int tmp;&lt;br /&gt;        DoWithIntPointer(a, b, &amp;amp;tmp);&lt;br /&gt;        r = tmp;&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size: small;"&gt;After compiling, the wrapper can be used as any other assembly:&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="cs" title="TestCppCli.cs"&gt;&lt;br /&gt;//&lt;br /&gt;// TestCppCli.cs&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;using NativeCppCliWrapper;&lt;br /&gt;&lt;br /&gt;class TestCppCli {&lt;br /&gt;    public static void Main() {&lt;br /&gt;        int result = 0;&lt;br /&gt;        Wrapper.CallDoWithIntPointer(1, 2, out result);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size: small;"&gt;If we dig through the IL code generated by C++/Cli we can see that CallDoWithIntPointer invokes:&lt;/span&gt; &lt;br /&gt;&lt;pre&gt;&lt;code class="no-highlight" title="CallDoWithIntPointer.il"&gt;&lt;br /&gt; IL_0004: call void modopt(&lt;br /&gt;      [mscorlib]System.Runtime.CompilerServices.CallConvCdecl&lt;br /&gt;   )  '&lt;module&gt;'::DoWithIntPointer(int32, int32, int32*)&lt;br /&gt;&lt;/module&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size: small;"&gt;And DoWithIntPointer is described by the following metadata:&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="no-highlight" title="DoWithIntPointer.il"&gt;&lt;br /&gt;.method assembly static pinvokeimpl("" lasterr cdecl)&lt;br /&gt; void modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)  DoWithIntPointer (&lt;br /&gt;  int32 '',&lt;br /&gt;  int32 '',&lt;br /&gt;  int32* ''&lt;br /&gt; ) native unmanaged preservesig &lt;br /&gt;{&lt;br /&gt; .custom instance void&lt;br /&gt; [mscorlib]System.Security.SuppressUnmanagedCodeSecurityAttribute::.ctor() = (&lt;br /&gt;  01 00 00 00&lt;br /&gt; )&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size: small;"&gt;Converted in C# (with &lt;a href="http://wiki.sharpdevelop.net/ILSpy.ashx"&gt;IlSpy&lt;/a&gt;):&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="cs" title="DoWithIntPointer.cs"&gt;&lt;br /&gt;[SuppressUnmanagedCodeSecurity]&lt;br /&gt;[DllImport("", &lt;br /&gt;    CallingConvention = CallingConvention.Cdecl, &lt;br /&gt;    SetLastError = true&lt;br /&gt;)]&lt;br /&gt;[MethodImpl(MethodImplOptions.Unmanaged)]&lt;br /&gt;internal unsafe static extern void DoWithIntPointer(&lt;br /&gt;    int, &lt;br /&gt;    int, &lt;br /&gt;    int*&lt;br /&gt;);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size: small;"&gt;Does this remind us of anything? Yes, it is very similar to the extern declaration that we have seen previously but among the differences we can note an attribute called &lt;/span&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.security.suppressunmanagedcodesecurityattribute.aspx"&gt;&lt;span style="font-size: small;"&gt;SuppressUnmanagedCodeSecurity&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: small;"&gt;. &lt;/span&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms182311(v=VS.100).aspx"&gt;&lt;span style="font-size: small;"&gt;MSDN&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: small;"&gt; tells us that:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size: small;"&gt;This attribute is primarily used to increase performance; however, the performance gains come with significant security risks.&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;Security risks apart it can be used with explicit P/Invoke, it is not an exclusive of C++/Cli.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;In other situations the native code is called in a more sophisticated way, for example if we poke inside IL code of &lt;/span&gt;&lt;a href="http://slimdx.org/"&gt;&lt;span style="font-size: small;"&gt;SlimDX&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: small;"&gt; we can find things like this:&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="no-highlight" title="SlimDX.Result.Optimize.il"&gt;&lt;br /&gt;.method public hidebysig &lt;br /&gt; instance valuetype SlimDX.Result Optimize () cil managed &lt;br /&gt;{&lt;br /&gt; // Method begins at RVA 0xd0824&lt;br /&gt; // Code size 25 (0x19)&lt;br /&gt; .maxstack 3&lt;br /&gt;&lt;br /&gt; IL_0000: ldarg.0&lt;br /&gt; IL_0001: call instance valuetype &lt;br /&gt;  IUnknown* SlimDX.ComObject::get_UnknownPointer()&lt;br /&gt; IL_0006: dup&lt;br /&gt; IL_0007: ldind.i4&lt;br /&gt; IL_0008: ldc.i4.s 68&lt;br /&gt; IL_000a: add&lt;br /&gt; IL_000b: ldind.i4&lt;br /&gt; IL_000c: calli System.Int32 modopt(&lt;br /&gt;   System.Runtime.CompilerServices.IsLong&lt;br /&gt;  ) modopt(&lt;br /&gt;   System.Runtime.CompilerServices.CallConvStdcall&lt;br /&gt;  )(System.IntPtr)&lt;br /&gt; IL_0011: ldnull&lt;br /&gt; IL_0012: ldnull&lt;br /&gt; IL_0013: call valuetype SlimDX.Result &lt;br /&gt;  SlimDX.Result::Record&lt;br /&gt;  &amp;lt;class SlimDX.Direct3D11.Direct3D11Exception&amp;gt;(&lt;br /&gt;   int32, object, object&lt;br /&gt;  )&lt;br /&gt; IL_0018: ret&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size: small;"&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.calli.aspx"&gt;calli&lt;/a&gt; instruction is used to invoke a native method given the address of the method itself. We will see how to take advantage of calli without C++/Cli in the last example.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Dynamic P/Invoke&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;In order to employ the previos techniques tha native library must be know at compile time, while it must be located in a certain path at runtime. With dynamic P/Invoke we can obtain a greater degree of flexibility.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;In the next example we will benefit by an assembly called &lt;/span&gt;&lt;a href="http://code.msdn.microsoft.com/CSLoadLibrary-cd0019f5/sourcecode?fileId=21679&amp;amp;pathId=350198783"&gt;&lt;span style="font-size: small;"&gt;CSLoadLibrary&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: small;"&gt; but slightly modified, in particular to run on Unix/Linux via Mono (see the download link at the end of this post for the modified version). CSLoadLibrary contains an UnmanagedLibrary class that provides access to native libraries through standard Windows APIs (LoadLibrary, GetProcAddress, FreeLibrary) or Unix/Linux counterparts (dlopen, dlsym, dlclose).&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="cs" title="TestDelegate.cs"&gt;&lt;br /&gt;//&lt;br /&gt;// TestDelegate.cs&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;using System.Runtime.InteropServices;&lt;br /&gt;using CSLoadLibrary;&lt;br /&gt;&lt;br /&gt;class TestDelegate {&lt;br /&gt;    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]&lt;br /&gt;    delegate void DelegateWithIntPointer(&lt;br /&gt;        int a, &lt;br /&gt;        int b, &lt;br /&gt;        out int r&lt;br /&gt;    );&lt;br /&gt;    &lt;br /&gt;    public static void Main() {&lt;br /&gt;        UnmanagedLibrary nativeLib = &lt;br /&gt;            new UnmanagedLibrary(&lt;br /&gt;                "Native"&lt;br /&gt;            );&lt;br /&gt;        &lt;br /&gt;        DelegateWithIntPointer doWithIntPointer = &lt;br /&gt;            nativeLib.GetUnmanagedFunction&lt;br /&gt;                &amp;lt;DelegateWithIntPointer&amp;gt;(&lt;br /&gt;                "DoWithIntPointer"&lt;br /&gt;            );&lt;br /&gt;&lt;br /&gt;        int result = 0;&lt;br /&gt;        doWithIntPointer(1, 2, out result);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size: small;"&gt;In practice, given the name of the native library to load, an UnmanagedLibrary object is instantiated. Then, with GetUnmanagedFunction we obtain a delegate pointing to our native function, DoWithIntPointer. Naturally the signature of the delegate must match the signature of the native function.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Dynamic P/Invoke – Explicit P/Invoke&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;This time, instead of using CSLoadLibrary, the delegate is created via Reflection, replicating the extern declaration shown in the Explicit P/Invoke example.&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="cs" title="TestDynamicS.cs"&gt;&lt;br /&gt;//&lt;br /&gt;// TestDynamicS.cs&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Reflection;&lt;br /&gt;using System.Reflection.Emit;&lt;br /&gt;using System.Runtime.InteropServices;&lt;br /&gt;using System.Security;&lt;br /&gt;&lt;br /&gt;class TestDynamicS {&lt;br /&gt;    delegate void DelegateWithIntPointer(&lt;br /&gt;        int a, &lt;br /&gt;        int b, &lt;br /&gt;        out int r&lt;br /&gt;    );&lt;br /&gt;    &lt;br /&gt;    public static void Main() {&lt;br /&gt;        DelegateWithIntPointer doWithIntPointer = &lt;br /&gt;            GetDynamicSDelegate&lt;br /&gt;                &amp;lt;DelegateWithIntPointer&amp;gt;(&lt;br /&gt;                "Native", &lt;br /&gt;                "DoWithIntPointer", &lt;br /&gt;                CallingConvention.Cdecl&lt;br /&gt;            );&lt;br /&gt;            &lt;br /&gt;        int result = 0;&lt;br /&gt;        doWithIntPointer(1, 2, out result);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static TDelegate GetDynamicSDelegate&lt;br /&gt;        &amp;lt;TDelegate&amp;gt;(&lt;br /&gt;        string libraryName, &lt;br /&gt;        string entryPoint, &lt;br /&gt;        CallingConvention callingConvention&lt;br /&gt;    ) where TDelegate : class &lt;br /&gt;    {&lt;br /&gt;        Type delegateType = typeof(TDelegate);&lt;br /&gt;        MethodInfo invokeInfo = delegateType.GetMethod("Invoke");&lt;br /&gt;        // Gets the return type for the P/Invoke method.&lt;br /&gt;        Type invokeReturnType = invokeInfo.ReturnType;&lt;br /&gt;        // Gets the parameter types for the P/Invoke method.&lt;br /&gt;        ParameterInfo[] invokeParameters = &lt;br /&gt;            invokeInfo.GetParameters();&lt;br /&gt;        Type[] invokeParameterTypes = &lt;br /&gt;            new Type[&lt;br /&gt;                invokeParameters.Length&lt;br /&gt;            ];&lt;br /&gt;        for (int i = 0; i &amp;lt; invokeParameters.Length; i++) {&lt;br /&gt;            invokeParameterTypes[i] = &lt;br /&gt;                invokeParameters[i].ParameterType;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // Defines an assembly with a module and a type.&lt;br /&gt;        AssemblyName assemblyName = &lt;br /&gt;            new AssemblyName(&lt;br /&gt;                "TestAssembly"&lt;br /&gt;            );&lt;br /&gt;        AssemblyBuilder assemblyBuilder = &lt;br /&gt;            AppDomain.CurrentDomain.DefineDynamicAssembly(&lt;br /&gt;                assemblyName, &lt;br /&gt;                AssemblyBuilderAccess.Run&lt;br /&gt;            );&lt;br /&gt;        ModuleBuilder moduleBuilder = &lt;br /&gt;            assemblyBuilder.DefineDynamicModule(&lt;br /&gt;                "TestModule"&lt;br /&gt;            );&lt;br /&gt;        TypeBuilder typeBuilder = &lt;br /&gt;            moduleBuilder.DefineType(&lt;br /&gt;                "TestDynamicS"&lt;br /&gt;            );&lt;br /&gt;            &lt;br /&gt;        //Defines a P/Invoke method called Invoke.&lt;br /&gt;        MethodBuilder methodBuilder = &lt;br /&gt;            typeBuilder.DefinePInvokeMethod(&lt;br /&gt;                "Invoke", &lt;br /&gt;                libraryName + ".dll", &lt;br /&gt;                entryPoint, &lt;br /&gt;                MethodAttributes.Public | &lt;br /&gt;                    MethodAttributes.Static | &lt;br /&gt;                    MethodAttributes.PinvokeImpl,&lt;br /&gt;                CallingConventions.Standard, &lt;br /&gt;                invokeReturnType, &lt;br /&gt;                invokeParameterTypes, &lt;br /&gt;                callingConvention, &lt;br /&gt;                CharSet.Ansi&lt;br /&gt;            );&lt;br /&gt;        methodBuilder.SetImplementationFlags(&lt;br /&gt;            methodBuilder.GetMethodImplementationFlags() | &lt;br /&gt;            MethodImplAttributes.PreserveSig&lt;br /&gt;        );&lt;br /&gt;        &lt;br /&gt;        // Adds SuppressUnmanagedCodeSecurityAttribute to &lt;br /&gt;        // the method.&lt;br /&gt;        Type attributeType = &lt;br /&gt;            typeof(&lt;br /&gt;                SuppressUnmanagedCodeSecurityAttribute&lt;br /&gt;            );&lt;br /&gt;        ConstructorInfo attributeConstructorInfo = &lt;br /&gt;            attributeType.GetConstructor(&lt;br /&gt;                new Type[] {}&lt;br /&gt;            );&lt;br /&gt;        CustomAttributeBuilder attributeBuilder = &lt;br /&gt;            new CustomAttributeBuilder(&lt;br /&gt;                attributeConstructorInfo, &lt;br /&gt;                new object[] {}&lt;br /&gt;            );&lt;br /&gt;        methodBuilder.SetCustomAttribute(attributeBuilder);&lt;br /&gt;&lt;br /&gt;        // Finishes the type.&lt;br /&gt;        Type newType = typeBuilder.CreateType();&lt;br /&gt;        &lt;br /&gt;        object tmp = &lt;br /&gt;            (object)Delegate.CreateDelegate(&lt;br /&gt;                delegateType, &lt;br /&gt;                newType.GetMethod("Invoke")&lt;br /&gt;            );&lt;br /&gt;        return (TDelegate)tmp;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size: small;"&gt;Though we are adding the SuppressUnmanagedCodeSecurity attribute, it is not essential.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Dynamic P/Invoke - Emit Calli&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;The last example is more complicated. Here again, we make use of UnmanagedLibrary to get the native function's address. Then, through Reflection, we create a dynamic method which internally passes the address of the native function to calli, the instruction seen previously.&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="cs" title="TestCalli.cs"&gt;&lt;br /&gt;//&lt;br /&gt;// TestCalli.cs&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Reflection;&lt;br /&gt;using System.Reflection.Emit;&lt;br /&gt;using System.Runtime.InteropServices;&lt;br /&gt;using CSLoadLibrary;&lt;br /&gt;&lt;br /&gt;class TestCalli {&lt;br /&gt;    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]&lt;br /&gt;    delegate void DelegateWithIntPointer(&lt;br /&gt;        int a, &lt;br /&gt;        int b, &lt;br /&gt;        out int r&lt;br /&gt;    );&lt;br /&gt;    &lt;br /&gt;    public static void Main() {        &lt;br /&gt;        UnmanagedLibrary nativeLib = &lt;br /&gt;            new UnmanagedLibrary(&lt;br /&gt;                "Native"&lt;br /&gt;            );&lt;br /&gt;        IntPtr nativeMethodAddress = &lt;br /&gt;            nativeLib.GetUnmanagedFunctionAddress(&lt;br /&gt;                "DoWithIntPointer"&lt;br /&gt;            );&lt;br /&gt;        DelegateWithIntPointer doWithIntPointer = &lt;br /&gt;            GetCalliDelegate&lt;br /&gt;                &amp;lt;DelegateWithIntPointer&amp;gt;(&lt;br /&gt;                nativeMethodAddress&lt;br /&gt;            );&lt;br /&gt;        int result = 0;&lt;br /&gt;        doWithIntPointer(1, 2, out result);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    private static TDelegate GetCalliDelegate&lt;br /&gt;        &amp;lt;TDelegate&amp;gt;(&lt;br /&gt;        IntPtr methodAddress&lt;br /&gt;    ) where TDelegate : class&lt;br /&gt;    {&lt;br /&gt;        Type delegateType = typeof(TDelegate);&lt;br /&gt;        MethodInfo invokeInfo = delegateType.GetMethod("Invoke");&lt;br /&gt;        // Gets the return type for the dynamic method and calli.&lt;br /&gt;        // Note: for calli, a type such as System.Int32&amp;amp; must be&lt;br /&gt;        // converted to System.Int32* otherwise the execution &lt;br /&gt;        // will be slower.&lt;br /&gt;        Type invokeReturnType = invokeInfo.ReturnType;&lt;br /&gt;        Type calliReturnType = &lt;br /&gt;            GetPointerTypeIfReference(&lt;br /&gt;                invokeInfo.ReturnType&lt;br /&gt;            );&lt;br /&gt;        // Gets the parameter types for the dynamic method &lt;br /&gt;        // and calli.&lt;br /&gt;        ParameterInfo[] invokeParameters = &lt;br /&gt;            invokeInfo.GetParameters();&lt;br /&gt;        Type[] invokeParameterTypes = &lt;br /&gt;            new Type[&lt;br /&gt;                invokeParameters.Length&lt;br /&gt;            ];&lt;br /&gt;        Type[] calliParameterTypes = &lt;br /&gt;            new Type[&lt;br /&gt;                invokeParameters.Length&lt;br /&gt;            ];&lt;br /&gt;        for (int i = 0; i &amp;lt; invokeParameters.Length; i++) {&lt;br /&gt;            invokeParameterTypes[i] = &lt;br /&gt;                invokeParameters[i].ParameterType;&lt;br /&gt;            calliParameterTypes[i] = &lt;br /&gt;                GetPointerTypeIfReference(&lt;br /&gt;                    invokeParameters[i].ParameterType&lt;br /&gt;                );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // Defines the dynamic method.&lt;br /&gt;        DynamicMethod calliMethod = &lt;br /&gt;            new DynamicMethod(&lt;br /&gt;                "CalliInvoke", &lt;br /&gt;                invokeReturnType, &lt;br /&gt;                invokeParameterTypes, &lt;br /&gt;                typeof(TestCalli), &lt;br /&gt;                true&lt;br /&gt;            );&lt;br /&gt;            &lt;br /&gt;        // Gets an ILGenerator.&lt;br /&gt;        ILGenerator generator = calliMethod.GetILGenerator();   &lt;br /&gt;        // Emits instructions for loading the parameters into &lt;br /&gt;        // the stack.&lt;br /&gt;        for (int i = 0; i &amp;lt; calliParameterTypes.Length; i++) {&lt;br /&gt;            if (i == 0) {&lt;br /&gt;                generator.Emit(OpCodes.Ldarg_0);&lt;br /&gt;            } else if (i == 1) {&lt;br /&gt;                generator.Emit(OpCodes.Ldarg_1);&lt;br /&gt;            } else if (i == 2) {&lt;br /&gt;                generator.Emit(OpCodes.Ldarg_2);&lt;br /&gt;            } else if (i == 3) {&lt;br /&gt;                generator.Emit(OpCodes.Ldarg_3);&lt;br /&gt;            } else {&lt;br /&gt;                generator.Emit(OpCodes.Ldarg, i);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        // Emits instruction for loading the address of the&lt;br /&gt;        //native function into the stack.&lt;br /&gt;        switch (IntPtr.Size) {&lt;br /&gt;            case 4:&lt;br /&gt;                generator.Emit(&lt;br /&gt;                    OpCodes.Ldc_I4, &lt;br /&gt;                    methodAddress.ToInt32()&lt;br /&gt;                );&lt;br /&gt;                break;&lt;br /&gt;            case 8:&lt;br /&gt;                generator.Emit(&lt;br /&gt;                    OpCodes.Ldc_I8, &lt;br /&gt;                    methodAddress.ToInt64()&lt;br /&gt;                );&lt;br /&gt;                break;&lt;br /&gt;            default:&lt;br /&gt;                throw new PlatformNotSupportedException();&lt;br /&gt;        }&lt;br /&gt;        // Emits calli opcode.&lt;br /&gt;        generator.EmitCalli(&lt;br /&gt;            OpCodes.Calli, &lt;br /&gt;            CallingConvention.Cdecl,&lt;br /&gt;            calliReturnType, &lt;br /&gt;            calliParameterTypes&lt;br /&gt;        );&lt;br /&gt;        // Emits instruction for returning a value.&lt;br /&gt;        generator.Emit(OpCodes.Ret);&lt;br /&gt;&lt;br /&gt;        object tmp = &lt;br /&gt;            (object)calliMethod.CreateDelegate(&lt;br /&gt;                delegateType&lt;br /&gt;            );&lt;br /&gt;        return (TDelegate)tmp;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    private static Type GetPointerTypeIfReference(Type type) {&lt;br /&gt;        if (type.IsByRef) {&lt;br /&gt;            return Type.GetType(type.FullName.Replace("&amp;amp;", "*"));&lt;br /&gt;        }&lt;br /&gt;        return type;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-size: small;"&gt;The method GetPointerTypeIfReference converts the type of a parameter like Int32&amp;amp; to Int32*, otherwise calli executes correctly but results slower.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Benchmark&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;Hardware: CPU Intel Core i3-2310M 2.1 GHz, RAM 4 GB.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;Software: VMware Player 3.1.4. on Windows 7 x64.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;[ms] x 100,000,000 iterations&lt;br /&gt;&lt;br /&gt;SUC means that the test has been executed with the SuppressUnmanagedCodeSecurity attribute.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;table border="1" cellpadding="2" cellspacing="2" style="border-collapse: collapse; text-align: left; width: 100%;"&gt;&lt;caption&gt;void DoWithIntPointer(int a, int b, int* r) &lt;/caption&gt;   &lt;thead&gt;&lt;tr&gt;     &lt;th colspan="1" rowspan="3"&gt;&lt;/th&gt;     &lt;th&gt;.Net 4&lt;/th&gt;     &lt;th&gt;Mono 2.10.6&lt;/th&gt;     &lt;th&gt;Mono 2.10.5&lt;/th&gt;     &lt;th&gt;Mono 2.6.7&lt;/th&gt;   &lt;/tr&gt;&lt;tr&gt;     &lt;th&gt;Windows&lt;/th&gt;     &lt;th&gt;Windows&lt;/th&gt;     &lt;th&gt;Ubuntu&lt;/th&gt;     &lt;th&gt;Debian&lt;/th&gt;   &lt;/tr&gt;&lt;tr&gt;     &lt;th&gt;XP x32&lt;/th&gt;     &lt;th&gt;XP x32&lt;/th&gt;     &lt;th&gt;Oneiric amd64&lt;/th&gt;     &lt;th&gt;squeeze i386&lt;/th&gt;   &lt;/tr&gt;&lt;/thead&gt;   &lt;tbody&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Expl. P/I&lt;/td&gt;       &lt;td&gt;8117&lt;/td&gt;       &lt;td&gt;12001&lt;/td&gt;       &lt;td&gt;2346&lt;/td&gt;       &lt;td&gt;3657&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Expl. P/I SUC&lt;/td&gt;       &lt;td&gt;3681&lt;/td&gt;       &lt;td&gt;3485&lt;/td&gt;       &lt;td&gt;2344&lt;/td&gt;       &lt;td&gt;3708&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;C++/Cli&lt;/td&gt;       &lt;td&gt;4760&lt;/td&gt;       &lt;td&gt;&lt;/td&gt;       &lt;td&gt;&lt;/td&gt;       &lt;td&gt;&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Dyn. P/I&lt;/td&gt;       &lt;td&gt;19309&lt;/td&gt;       &lt;td&gt;68303&lt;/td&gt;       &lt;td&gt;2603&lt;/td&gt;       &lt;td&gt;4431&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Dyn. P/I SUC&lt;/td&gt;       &lt;td&gt;7361&lt;/td&gt;       &lt;td&gt;59718&lt;/td&gt;       &lt;td&gt;2615&lt;/td&gt;       &lt;td&gt;4514&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Dyn. P/I Expl. SUC&lt;/td&gt;       &lt;td&gt;4497&lt;/td&gt;       &lt;td&gt;4419&lt;/td&gt;       &lt;td&gt;2480&lt;/td&gt;       &lt;td&gt;4398&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Dyn. P/I Calli&lt;/td&gt;       &lt;td&gt;4136&lt;/td&gt;       &lt;td&gt;4249&lt;/td&gt;       &lt;td&gt;1885&lt;/td&gt;       &lt;td&gt;4353&lt;/td&gt;     &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;&lt;table border="1" cellpadding="2" cellspacing="2" style="border-collapse: collapse; text-align: left; width: 100%;"&gt;&lt;caption&gt;void DoWithDoublePointer(double a, double b, double* r)&lt;/caption&gt;   &lt;thead&gt;&lt;tr&gt;     &lt;th colspan="1" rowspan="3"&gt;&lt;/th&gt;     &lt;th&gt;.Net 4&lt;/th&gt;     &lt;th&gt;Mono 2.10.6&lt;/th&gt;     &lt;th&gt;Mono 2.10.5&lt;/th&gt;     &lt;th&gt;Mono 2.6.7&lt;/th&gt;   &lt;/tr&gt;&lt;tr&gt;     &lt;th&gt;Windows&lt;/th&gt;     &lt;th&gt;Windows&lt;/th&gt;     &lt;th&gt;Ubuntu&lt;/th&gt;     &lt;th&gt;Debian&lt;/th&gt;   &lt;/tr&gt;&lt;tr&gt;     &lt;th&gt;XP x32&lt;/th&gt;     &lt;th&gt;XP x32&lt;/th&gt;     &lt;th&gt;Oneiric amd64&lt;/th&gt;     &lt;th&gt;squeeze i386&lt;/th&gt;   &lt;/tr&gt;&lt;/thead&gt;   &lt;tbody&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Expl. P/I&lt;/td&gt;       &lt;td&gt;8215&lt;/td&gt;       &lt;td&gt;14328&lt;/td&gt;       &lt;td&gt;2194&lt;/td&gt;       &lt;td&gt;4819&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Expl. P/I SUC&lt;/td&gt;       &lt;td&gt;4203&lt;/td&gt;       &lt;td&gt;6658&lt;/td&gt;       &lt;td&gt;2207&lt;/td&gt;       &lt;td&gt;4826&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;C++/Cli&lt;/td&gt;       &lt;td&gt;5576&lt;/td&gt;       &lt;td&gt;&lt;/td&gt;       &lt;td&gt;&lt;/td&gt;       &lt;td&gt;&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Dyn. P/I&lt;/td&gt;       &lt;td&gt;22881&lt;/td&gt;       &lt;td&gt;68789&lt;/td&gt;       &lt;td&gt;3658&lt;/td&gt;       &lt;td&gt;7260&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Dyn. P/I SUC&lt;/td&gt;       &lt;td&gt;7478&lt;/td&gt;       &lt;td&gt;60425&lt;/td&gt;       &lt;td&gt;3780&lt;/td&gt;       &lt;td&gt;7251&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Dyn. P/I Expl. SUC&lt;/td&gt;       &lt;td&gt;4247&lt;/td&gt;       &lt;td&gt;6627&lt;/td&gt;       &lt;td&gt;3655&lt;/td&gt;       &lt;td&gt;7294&lt;/td&gt;     &lt;/tr&gt;&lt;tr&gt;       &lt;td colspan="1" rowspan="1"&gt;Dyn. P/I Calli&lt;/td&gt;       &lt;td&gt;3925&lt;/td&gt;       &lt;td&gt;3766&lt;/td&gt;       &lt;td&gt;3050&lt;/td&gt;       &lt;td&gt;6766&lt;/td&gt;     &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;The above results seem a bit weird and the only certain thing appears to be that Dynamic P/Invoke is always faster if we resort to calli. Anyway, we have seen different ways to invoke unmanaged code from managed code, each with its own pros and cons, and if necessary we can use them or conduct further tests.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Download&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;Benchmark &lt;a href="https://sites.google.com/site/roguemodroninventory/blog/InvokeNative.7z?attredirects=0&amp;amp;d=1"&gt;source code&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Other resources&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;About interoperability:&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.mono-project.com/Interop_with_Native_Libraries"&gt;&lt;span style="font-size: small;"&gt;Interop with Native Libraries&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://1code.codeplex.com/wikipage?title=Invoke%20Native%20C%2b%2b%20DLL%20from%20.NET"&gt;&lt;span style="font-size: small;"&gt;Invoke Native C++ DLL from .NET Code&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;About calli:&lt;/span&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/b/shawnfa/archive/2004/06/14/155478.aspx"&gt;&lt;span style="font-size: small;"&gt;Calli is not Verifiable&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://stackoverflow.com/questions/5893024/c-net-why-is-calli-faster-than-a-delegate-call"&gt;&lt;span style="font-size: small;"&gt;C#/.NET: Why is Calli Faster Than a Delegate Call?&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.delphigl.com/forum/viewtopic.php?f=21&amp;amp;t=4050&amp;amp;view=next"&gt;&lt;span style="font-size: small;"&gt;OpenGL Import für Delphi .Net&lt;/span&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4599268833456028124-9098310901702761088?l=rogue-modron.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rogue-modron.blogspot.com/feeds/9098310901702761088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rogue-modron.blogspot.com/2011/11/invoking-native.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4599268833456028124/posts/default/9098310901702761088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4599268833456028124/posts/default/9098310901702761088'/><link rel='alternate' type='text/html' href='http://rogue-modron.blogspot.com/2011/11/invoking-native.html' title='Invoking Native'/><author><name>Rogue Modron</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4599268833456028124.post-8545942764883035227</id><published>2011-04-17T11:21:00.006+02:00</published><updated>2011-11-01T12:08:07.596+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Wrapper'/><category scheme='http://www.blogger.com/atom/ns#' term='C++/Cli'/><category scheme='http://www.blogger.com/atom/ns#' term='Benchmark'/><category scheme='http://www.blogger.com/atom/ns#' term='Polygon Clipping'/><title type='text'>Polygon Clipping: a Wrapper, a Benchmark</title><content type='html'>&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;An experiment about six open source polygon clipping libraries that have been benchmarked after being wrapped for use with .Net.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Note that there could be errors and however no consideration is made about the robustness or optimization of the libraries so this benchmark must be taken with "a grain of salt".&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: x-small;"&gt;&lt;u&gt;LAST UPDATE - AUGUST 14, 2011&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;The six libraries&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;- &lt;a href="http://www.boost.org/doc/libs/release/libs/geometry/doc/html/index.html"&gt;&lt;b&gt;Boost.Geometry&lt;/b&gt;&lt;/a&gt; -&lt;br /&gt;&lt;br /&gt;Version &amp;nbsp; Subversion trunk rev. 73602&lt;br /&gt;License &amp;nbsp; Boost v1.0&lt;br /&gt;&lt;br /&gt;Boost.Geometry, also known as Ggl, can be used with &lt;a href="http://www.mpir.org/index.html"&gt;Mpir&lt;/a&gt; (a Gmp fork) or with &lt;a href="http://www.ttmath.org/"&gt;TTMath&lt;/a&gt;, for more precision but with a significant slowdown.&lt;br /&gt;&lt;br /&gt;- &lt;a href="http://www.boost.org/doc/libs/release/libs/polygon/doc/index.htm"&gt;&lt;b&gt;Boost.Polygon&lt;/b&gt;&lt;/a&gt; -&lt;br /&gt;&lt;br /&gt;Version &amp;nbsp; Subversion trunk rev. 72191&lt;br /&gt;License &amp;nbsp; Boost v1.0&lt;br /&gt;&lt;br /&gt;Boost.Polygon, also known as Gtl, can be used with Mpir with no speed penalty.&lt;br /&gt;&lt;br /&gt;- &lt;a href="http://angusj.com/delphi/clipper.php"&gt;&lt;b&gt;Clipper&lt;/b&gt;&lt;/a&gt; -&lt;br /&gt;&lt;br /&gt;Version &amp;nbsp; 4.4.0&lt;br /&gt;License &amp;nbsp; Boost v1.0&lt;br /&gt;&lt;br /&gt;- &lt;a href="http://trac.osgeo.org/geos/"&gt;&lt;b&gt;Geos&lt;/b&gt;&lt;/a&gt; -&lt;br /&gt;&lt;br /&gt;Version &amp;nbsp; 3.3.0&lt;br /&gt;License &amp;nbsp; LGPL&lt;br /&gt;&lt;br /&gt;- &lt;a href="http://www.cs.man.ac.uk/~toby/alan/software/"&gt;&lt;b&gt;Gpc&lt;/b&gt;&lt;/a&gt; -&lt;br /&gt;&lt;br /&gt;Version &amp;nbsp; 2.32&lt;br /&gt;License &amp;nbsp; Free for non-commercial use / Commercial&lt;br /&gt;&lt;br /&gt;- &lt;a href="http://boolean.klaasholwerda.nl/bool.html"&gt;&lt;b&gt;KBool&lt;/b&gt;&lt;/a&gt; -&lt;br /&gt;&lt;br /&gt;Version &amp;nbsp; 2.1&lt;br /&gt;License &amp;nbsp; GPL v3 / Commercial&lt;br /&gt;&lt;br /&gt;KBool source has been &lt;a href="http://code.google.com/p/pykbool/source/browse/trunk/patch.sh"&gt;patched&lt;/a&gt; to avoid creating the file keygraphfile.key.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;The guests&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;For comparative purposes, other libraries have been used during the benchmark.&lt;br /&gt;&lt;br /&gt;- &lt;a href="http://www.complex-a5.ru/polyboolean/index.html"&gt;&lt;b&gt;PolyBoolean.c20.NET&lt;/b&gt;&lt;/a&gt; -&lt;br /&gt;&lt;br /&gt;Version &amp;nbsp; 2.0.0 (demo)&lt;br /&gt;License &amp;nbsp; Commercial&lt;br /&gt;&lt;br /&gt;Note that the demo version throws an exception when the number of vertices returned is a multiple of 7.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;- &lt;a href="http://www.microsoft.com/download/en/details.aspx?id=26728"&gt;&lt;b&gt;SQL Server System CLR Types 2008&lt;/b&gt;&lt;/a&gt; -&lt;br /&gt;&lt;br /&gt;Version &amp;nbsp; 10.50.2500.0&lt;br /&gt;License &amp;nbsp; Proprietary&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;The wrapper&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;A light C++/Cli wrapper that exposes only the polygon set operations (union, difference, intersection, disjoint-union).&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Hardware and software&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;CPU &amp;nbsp;- &amp;nbsp;Intel Core 2 Quad Q6600 @ 2.40GHz&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;RAM &amp;nbsp;- &amp;nbsp;4GB&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;OS &amp;nbsp;- &amp;nbsp;Windows XP x64&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;SDK &amp;nbsp;- &amp;nbsp;Win SDK v7.1 / Visual Studio 2010 Express&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;Settings &amp;nbsp;- &amp;nbsp;Default x86 release build&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;The benchmark – known polygons (a)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-YvDjcCUln4o/TkbkjCm_3MI/AAAAAAAAAHo/flODx9aSZmM/s1600/Ex_Known_A1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="270" src="http://4.bp.blogspot.com/-YvDjcCUln4o/TkbkjCm_3MI/AAAAAAAAAHo/flODx9aSZmM/s400/Ex_Known_A1.png" width="270" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-CShQvYWWQmo/TkbksIZuQII/AAAAAAAAAHw/T1F4CYuWCC8/s1600/Ex_Known_A2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="270" src="http://3.bp.blogspot.com/-CShQvYWWQmo/TkbksIZuQII/AAAAAAAAAHw/T1F4CYuWCC8/s400/Ex_Known_A2.png" width="270" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;In this test one operand is a polygon that resembles a gear while the other operand is formed by a set of concentric rings. During the test the gear teeth have been increased in number and length as well as the number of rings. An intersection operation has been executed.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-XBe_guFLQn0/Tkbk6YJHzzI/AAAAAAAAAH4/85W4Dp_j3tE/s1600/X32_Known_A.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-XBe_guFLQn0/Tkbk6YJHzzI/AAAAAAAAAH4/85W4Dp_j3tE/s1600/X32_Known_A.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;The first and the last operation have been executed respectively with 19 and 723347 input vertices. Boost.Geometry has been the fastest library followed by Clipper while Boost.Polygon has started slow but has scaled well.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;The benchmark – known polygons (b)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-Ub-lI5m9fQM/TkbnCJrMpBI/AAAAAAAAAIA/GjCc8eP9XLI/s1600/Ex_Known_B1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="270" src="http://1.bp.blogspot.com/-Ub-lI5m9fQM/TkbnCJrMpBI/AAAAAAAAAIA/GjCc8eP9XLI/s400/Ex_Known_B1.png" width="270" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-7eV6Bhyj1lk/TkbnGa5Im0I/AAAAAAAAAII/rJoydXeM2A0/s1600/Ex_Known_B2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="270" src="http://2.bp.blogspot.com/-7eV6Bhyj1lk/TkbnGa5Im0I/AAAAAAAAAII/rJoydXeM2A0/s400/Ex_Known_B2.png" width="270" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;In this test the polygons have been generated in a manner similar to that of the previous test.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-WF3l8asHrgg/TkbnRZcmfnI/AAAAAAAAAIQ/YrrMfOIUaDg/s1600/X32_Known_B.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-WF3l8asHrgg/TkbnRZcmfnI/AAAAAAAAAIQ/YrrMfOIUaDg/s1600/X32_Known_B.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;The first and the last operation have been executed respectively with 123 and 606201 input vertices. In this case Clipper has been the fastest followed by SQL Server System Types and PolyBoolean.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;The benchmark - random polygons&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-7fWWSoFHgRg/Tkbosqb2OOI/AAAAAAAAAIY/67KSDkukc30/s1600/Ex_Random_A.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="117" src="http://1.bp.blogspot.com/-7fWWSoFHgRg/Tkbosqb2OOI/AAAAAAAAAIY/67KSDkukc30/s400/Ex_Random_A.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;The operands used in this test have been obtained subtracting random triangles from a square. An intersection operation has been executed.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-H4h94Nq6zNE/Tkbo2i5IyFI/AAAAAAAAAIg/v_xofNkN8i8/s1600/X32_Random_A.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-H4h94Nq6zNE/Tkbo2i5IyFI/AAAAAAAAAIg/v_xofNkN8i8/s1600/X32_Random_A.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;The first and the last operation have been executed respectively with 402 and 53359 input vertices. Boost.Geometry has been the fastest followed by SQL Server System Types and Boost.Polygon. Geos has been very slow. During the last test PolyBoolean has raised an exception ("Invalid contour orientation").&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;The benchmark - classic polygons&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-XKdNmVyAoBk/TkbqTmVH1lI/AAAAAAAAAIo/E29x_5qoMBM/s1600/Ex_Classic.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="196" src="http://2.bp.blogspot.com/-XKdNmVyAoBk/TkbqTmVH1lI/AAAAAAAAAIo/E29x_5qoMBM/s400/Ex_Classic.png" width="254" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;Polygons used in this test are the same ones used to test PolyBoolean (C++ version) and Clipper (see their websites).&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-wu_qK2-Xzqk/TkbqelYp6AI/AAAAAAAAAIw/ez56kZrdueg/s1600/X32_Classic.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-wu_qK2-Xzqk/TkbqelYp6AI/AAAAAAAAAIw/ez56kZrdueg/s1600/X32_Classic.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;Boost.Geometry has been the fastest followed by Clipper, SQL Server System Types and Geos. Gpc has been the slowest.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Known polygons - X32 VS X64&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;These are execution times obtained with 723347 input vertices as in "known polygons (a)", but in this case all has been compiled for X64 platform.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-SwkShqIM9Sg/Tkb3bWiU87I/AAAAAAAAAJs/oO4iN1cZvdQ/s1600/X32_X64_Known_A.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-SwkShqIM9Sg/Tkb3bWiU87I/AAAAAAAAAJs/oO4iN1cZvdQ/s1600/X32_X64_Known_A.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;When compiled for X64 the libraries are generally faster.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Gpc – C# wrapper vs C++/Cli wrapper&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;Gpc has a C# wrapper and here is a comparison with the C++/Cli wrapper. The polygons have been generated as in "known polygons (b)".&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-19loRBl1nnA/TkbrqCHslHI/AAAAAAAAAI4/9xIxOqt2Kb0/s1600/X32_GpcW_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-19loRBl1nnA/TkbrqCHslHI/AAAAAAAAAI4/9xIxOqt2Kb0/s1600/X32_GpcW_10.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-_ya_aHnbJ8E/TkbruolNIaI/AAAAAAAAAJA/Crft53H46sk/s1600/X32_GpcW_5000.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-_ya_aHnbJ8E/TkbruolNIaI/AAAAAAAAAJA/Crft53H46sk/s1600/X32_GpcW_5000.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;Not a big difference between a P/Invoke and a C++/Cli wrapper but P/Invoke can be used with Mono.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Clipper – C# vs C++/Cli wrapper&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;Clipper has a C# implementation and here is a comparison with the wrapped C++ implementation. The polygons have been generated as in "known polygons (b)"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-uDyIAm1dVWY/TkbsBkOyctI/AAAAAAAAAJI/wN6vf_86wh8/s1600/X32_Clipper_10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-uDyIAm1dVWY/TkbsBkOyctI/AAAAAAAAAJI/wN6vf_86wh8/s1600/X32_Clipper_10.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-6aMe7pw4rqQ/TkbsFVPrDnI/AAAAAAAAAJQ/9-_Pe0ZmQhs/s1600/X32_Clipper_5000.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-6aMe7pw4rqQ/TkbsFVPrDnI/AAAAAAAAAJQ/9-_Pe0ZmQhs/s1600/X32_Clipper_5000.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;The C# implementation is slower but can be used directly with .Net and Mono.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Downloads&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Wrapper &lt;a href="https://sites.google.com/site/roguemodroninventory/blog/pclw/PclW.7z?attredirects=0&amp;amp;d=1"&gt;source code&lt;/a&gt; (C++/Cli)&lt;br /&gt;(source code for the libraries must be downloaded from the respective sites)&lt;br /&gt;&lt;br /&gt;Benchmark &lt;a href="https://sites.google.com/site/roguemodroninventory/blog/pclw/PclWTest.7z?attredirects=0&amp;amp;d=1"&gt;source code&lt;/a&gt; and binaries (Vb.Net)&lt;br /&gt;(contains only binaries for libraries released under Boost v1.0 license)&lt;br /&gt;&lt;br /&gt;Benchmark &lt;a href="https://sites.google.com/site/roguemodroninventory/blog/pclw/PclWResults.7z?attredirects=0&amp;amp;d=1"&gt;output&lt;/a&gt; (txt files)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: x-small;"&gt;&lt;br /&gt;UPDATES&lt;br /&gt;&lt;br /&gt;AUGUST 14, 2011&lt;br /&gt;- Added Geos and SQL Server System Types.&lt;br /&gt;- Corrected bug on closing vertex for polygons used in all the tests except the one with random polygons.&lt;br /&gt;&lt;br /&gt;JULY 23, 2011&lt;br /&gt;- Added Boost.Geometry.&lt;br /&gt;- Polygons have been closed.&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4599268833456028124-8545942764883035227?l=rogue-modron.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rogue-modron.blogspot.com/feeds/8545942764883035227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rogue-modron.blogspot.com/2011/04/polygon-clipping-wrapper-benchmark.html#comment-form' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4599268833456028124/posts/default/8545942764883035227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4599268833456028124/posts/default/8545942764883035227'/><link rel='alternate' type='text/html' href='http://rogue-modron.blogspot.com/2011/04/polygon-clipping-wrapper-benchmark.html' title='Polygon Clipping: a Wrapper, a Benchmark'/><author><name>Rogue Modron</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-YvDjcCUln4o/TkbkjCm_3MI/AAAAAAAAAHo/flODx9aSZmM/s72-c/Ex_Known_A1.png' height='72' width='72'/><thr:total>17</thr:total></entry></feed>
