Notes on Mono integration

Building the Mono UNO bridge
============================

+ configure with --enable-mono
+ ./download
+ You absolutely need mono >= 1.1.6

+ Test with demo programs:

  cd odk/examples/CLI/CSharp/Spreadsheet
  mcs ViewSample.cs SpreadsheetDocHelper.cs  -r:../../../../../cli_ure/unxlngi6.pro/bin/cli_basetypes.dll  -r:../../../../../cli_ure/unxlngi6.pro/bin/cli_types.dll -r:../../../../../cli_ure/unxlngi6.pro/bin/cli_cppuhelper.dll -r:../../../../../cli_ure/unxlngi6.pro/bin/cli_ure.dll

  # To compile SpreadsheetSample.cs, you need mcs from mono 1.1.6 or
  # later, the others can be compiled with older mcs.

  mono ViewSample.exe


Notes on the Mono UNO bridge
============================

+ What works already?

    + "A little bit of everything" :-/

    + The ViewSample.cs which seems to work does:
        + get initial ComponentContext using bootstrap (i.e.
	  get a UNO interface wrapped in Mono object)
	+ test wrapped UNO objects for implented interfaces.
	+ call methods on Mono objects, parameters and return values
	  are mapped to/from UNO (numbers, strings, anies, structs,
	  inherited structs)
	+ pass a Mono implementation of a UNO interface
	  (XRangeSelectionListener) to UNO (i.e. wrap a Mono object in
	  a UNO interface)

    + The other two spreadsheet examples need Mono >= 1.1.8.3.

    + testtools has a "bridgetest" for various bridges, also for cli.
      Works with Mono >= 1.1.8.3

+ What doesn't work/What's missing?

    + lots of FIXMEs near TypeDescription declarations: The
      corresponding C++ code uses a wrapper class for automatic
      acquire/release. The C# code doesn't and leaks TypeDescriptions

    + lots of FIXMEs in switch default: cases, after null checks:
      consistent error handling is missing here.

    + Exception handling is untested. (Catching UNO exceptions in Mono,
      throwing Mono exceptions to UNO)

    + The reference counting for uno_Interfaces isn't correct. Rebuild
      cppu with debug=true to get statistics when UNO shuts down.

+ New source files:

    + cli_ure/source/bootstrap/* provide cppuhelper wrappers,
      analogous to cli_ure/source/native. The use of mono_gchandle_new
      in bootstrap/native_glue.cxx seems ugly.

    + bridges/source/mono_uno/* the Mono bridge. Ported from
      briges/source/cli_uno C++ code to C# and very thin C++
      glue. Most of the C# is translated statement by statement.
      [ Tried to use C# coding style and not use cli_uno's
      namespace. But failed sometimes ]

+ How do the wrappers work:

    + UnoProxy, wrapper for UNO objects that are used in Mono land

        + Uses Remoting, inherits RealProxy, i.e. all casts are 
	  checked with CanCastTo, all method invocations go through Invoke.
	  Almost statement by statement translation of UnoInterfaceProxy
	  from cli_uno's cli_proxy.cxx

    + MonoProxy, wrapper for Mono objects that are sent to UNO

        + Essentially the required function pointers (for uno_Interface)
	  and a GC handle for a ManagedProxy. Uses mono api to call
	  ManagedProxy methods
	  
	+ ManagedProxy is the translation of cli_uno's CliProxy.

+ What about the precompiled dll: It contains the CLI representations
  of structs, exceptions, enums, interfaces, etc. of udkapi and offapi.

  It was generated using climaker (see notes below). How to port that:

    + completely port it to C# and use the Mono UNO bridge. This would
      cause circular dependencies (cli_types.dll is needed to build
      the bridge) or:

    + Look at cilc (comes with mono) to make a C wrapper for
      Reflection.Emit and port the bytecode generation in climaker to
      use that.

+ Can I use Mono to write add-ins for OOo? No, there's no "component
  loader" for Mono yet. Not even for the Windows .Net Bridge.


Notes on the Windows dot Net bridge
===================================

+ Work from cli_ure
    + de-louse prj/build.lst dependencies
        + check for MCS in config_office/configure.in, util/makefile.pmk
        + rename csc -> $(CSC) & set it up right.
            + mcs can't cope with '-o'
                  ** We should switch to -optimize instead. **
        + rene has a patch for this
          http://people.debian.org/~rene/openoffice.org/mono.diff

    + All(?) the C++ here is managed C++ (CFLAGS contains -clr)

+ cli_ure/source/basetypes/uno
    + C# implementations according to
      http://udk.openoffice.org/common/man/draft/uno_dotnet_typemapping.html
      of uno.Any
    + Contrary to that specification, there is no MethodAttribute, but
      separate custom attributes for
        + Bound (UNO) attributes, (i.e. properties)
        + Exceptions that methods may throw
        + Oneway methods
    + PolymorphicType, TypeParameters Attribute (for classes), TypeArguments
      Attribute (for fields in classes with TypeParameters) to emulate UNO
      structs with type arguments.
    + compiles with msc without problems

+ cli_ure/source/climaker
    + takes one or more uno registry files (.rdb) and emits an assembly
      containing the mapped types, mapped according to:
      http://udk.openoffice.org/common/man/draft/uno_dotnet_typemapping.html
    + output looks like
      http://udk.openoffice.org/cli/download/CLI-UNO.zip - cli_types.dll
    + uses System.Reflection.Emit to build the assembly
    + uses the native C++ UNO binding to read the registry files and for
      reflection of UNO types
    + uses native C++ to be able to use OUString
    + Tests in cli_ure/tests/climaker

+ cli_ure/source/native
    + produces cli_cppuhelper.dll as found in CLI-UNO.zip
    + "Provides bootstrapping code to bootstrap native UNO"
    + native_share.h:
        + to_cli
            + get a mapping <compiler's c++ abi>->cli (uses the uno2cli
              mapping impl. in the cli_uno bridge)
            + it uses the C++ wrapper Mapping which consists entirely of
              inline functions that use the C uno_Mapping
            + get the CLI proxy
            + extracts the object reference from the returned GCHandle
        + to_uno -- unused (!)
            + get a mapping cli-><compiler's c++ abi>
            + wrap the object reference in a new GCHandle
            + get the C++ proxy
            + wrap it in com::sun::star::uno::Reference < T >
    + native_bootstrap.cxx:
        + implementation of defaultBootstrap_InitialComponentContext as used
          in cli_language_binding.sxw from CLI-UNO.zip
        + uses cppuhelper's C++ native defaultBootstrap_InitialComponentContext
        + then uses to_cli to make a cli proxy for the component context
        + some Windows delayLoadHook thing
    + this is an easy? candidate for rewriting in C#, with P/Invokable glue
      for cppuhelper's defaultBootstrap_InitialComponentContext.
    + (Java uses jni but also cppuhelper; apparently cppuhelper has the only
      implementation of defaultBootstrap...;
      javaunohelper/source/bootstrap.cxx)

+ cli_ure/source/ure/uno/util
    + C# Implementation cli_ure.dll from CLI-UNO.zip
    + "Contains helper classes which are useful for implementing UNO interfaces.
      Types from this assembly are not necessarily used"
    + WeakAdapter, WeakComponentBase: description in cli_language_binding.sxw
    + WeakBase: base class for WeakComponentBase
    + DisposeGuard: IDisposable, "Helper class to conveniently auto dispose
      UNO objects from within managed code."
    + depends on cli_types.dll, otherwise this should be no problem for mcs

+ cli_ure/unotypes
    + use climaker to generate cli_types.dll as found in CLI-UNO.zip

+ cli_ure/util
    + Makefile snippets
    + uses -o in CSCFLAGS

+ cli_ure/workbench/dynload/dynload.cs
    + a test program for Bootstrap / cli_cppuhelper?

+ bridges/source/cli_uno/*

    + cli_bridge.h -- forked from jni_bridge.h
        + struct Mapping : public uno_Mapping { Bridge* m_bridge; };
            - uno_Mapping is a C struct
            - m_bridge: pointer to the real implementation

    + cli_bridge.cxx
        + uno_initEnvironment
            - installs cli_env_disposing callback (called before the env is destroyed)
            - nulls pExtEnv (would be "interface registration functionality, if supported")
            - could be used to start mono -- the java bridge doesn't init its jvm here.
	      Instead of setting pContext here, it's comes from the 3rd parameter of
	      uno_getEnvironment, called (using JNI) in
	      com.sun.star.comp.helper.Bootstrap.cppuhelper_bootstrap and in
	      com.sun.star.comp.helper.RegistryServiceFactory.createRegistryServiceFactory
        
        + uno_ext_getMapping
            - "is called by the UNO runtime to get the mappings for both directions"
            - ppMapping: [inout] parameter to contain the (new) mapping
            - pFrom, pTo: envs to map between
            - test their type names for being {"cli", "uno"}
            - construct a Bridge (cli-env, uno-env, <direction is cli -> uno?>)
        
        + Mapping_acquire, Mapping_release: call the corresponding Bridge methods
        
        + Bridge_free: delete the Bridge
        
        + Mapping_cli2uno
            - implementation of mapInterface for the cli2uno Mapping
            - Parameters:
                - mapping - the mapping
                - ppOut   - [inout] destination interface; existing interfaces are released
                - pIn     - source interface (in the cli environment)
                - td      - type description of the interface
            - cliObj = GCHandle::op_Explicit((intptr_t)pIn).Target: the object reference stored in pIn
            - bridge->map_cli2uno(cliObj, td) -- implementation in cli_data.cxx
        
        + Mapping_uno2cli
            - implementation of mapInterface for the uno2cli mapping
            - free ppOut if not NULL
            - bridge->map_uno2cli((uno_Interface *)pIn, td) -- in cli_data.cxx
            - wrap the resulting object reference in a GCHandle, return as a pointer
        
        + Mapping_uno2cli and Mapping_cli2uno contain managed-unmanaged transitions IIUC

    + cli_data.cxx
        + map_uno2cli: get the mapped type, try to get the Proxy from
	  the Cli_environment and add new interfaces to the Proxy if
	  necessary, if there is no existing proxy, make a new one.
	+ map_cli2uno: get the UNO proxy from the uno_Environment (C-API),
	  create a CliProxy, return that.
	+ loadCliType: load the mapped System.Type from a (climaker-produced)
	  assembly (by name)
	+ mapUnoType: take a typelib_TypeDescriptionReference and return a
	  System.Type
	+ mapCliType: the reverse

    + cli_proxy.h, cli_proxy.cxx -- can be split into C and C# files in a straightforward way
        + UnoInterfaceInfo (managed)
            + stores a uno_Interface,
              typelib_InterfaceTypeDescription of the uno_Interface,
              the mapped cli type of the uno_Interface, the bridge
            + accesses UNO only via the core C API
        + UnoInterfaceProxy : public System.Runtime.Remoting.{Proxies.RealProxy,IRemotingTypeInfo}
          (managed)
            + proxy on the managed side
            + CanCastTo uses C++ UNO: cssu::TypeDescription because that's a Smart Pointer
            + CanCastTo calls XInterface::queryInterface via helpers and binary uno
            + invokeObject: impl. helper for Invoke of System.Object methods
            + RealProxy::Invoke implementation
        + CliProxy : public uno_Interface
            + proxy on the native side
            + keeps a list of all MethodInfos of the mapped type and its superclasses
            + a mapping of method offsets in the UNO interface and in the array of
              MethodInfos

    + cli_uno.cxx
        + Bridge::call_uno -- cli-callable wrapper for uno_Interface.pDispatcher
        + Bridge::call_cli -- native-callable wrapper for System.Reflection.MethodInfo:Invoke

    + cli_base.h
        + string constants with type names (managed/CTS and unmanaged/C++)
        + struct BridgeRuntimeError (thrown when error occur)
        + an STL allocator using rtl
        + a typelib_TypeDescription wrapper

    + cli_environment
        + holds a big string indexed threadsafe hashtable of all proxies
	+ well, WeakReference holding the proxies
	+ the keys (oids) consist of the proxy's HashCode, ";cli[0]", a GUID
	  representing the Cli_environment type, optionally an UNO interface
	  name

+ Decision
    + should attempt to link to & map specifically to Mono
        + ie. a new binding bridges/source/mono_uno/*
        + since we have no 'managed C++' equivalent
        + ergo, no point in doing slow C->Mono calls that
          then call more 'standard' .Net calls to do
          conversions/boxing etc.
        + Just map as directly to Mono types / layout
          as possible.

    + Few hours later:
        martink michael_: http://udk.openoffice.org/servlets/ReadMsg?list=dev&msgNo=2942
        michael_ martink: it's a good point to try and re-write the bridge in C# :-)
        michael_ martink: a much better plan in fact,
        michael_ martink: bin my 'go-low-level-native' suggestion I guess;

+ misc. UNO places
    + cppu/inc/uno/lbnames.h: #define UNO_LB_CLI "cli"
      [LB = language binding]
    + cppu/source/uno/lbmap.cxx: implements uno_getMapping, loading/unloading of
      bridges etc.
    + cppuhelper/source/shlib.cxx in cws_srx644_cliuno01 has #ifdef CLI_PLATFORM
      a CLI component loader?
    + testtools/source/bridgetest/cli
    + cppuhelper/source/exc_thrower.cxx: implements a uno interface using the
      C interface

+ Mono notes
    + mono_gchandle_new etc. is native glue for System.GCHandles 

+ JNI bridge notes
    + a JNI_type_info is a wrapper around a jclass that has a destruct method
      to do jni_env->DeleteGlobalRef on the jclass
    + a JNI_interface_type_info is a JNI_type_info + array of jmethodIDs + ...
    + bridge->m_jni_info is a JNI_info (jni_info.h) that maps TypeDescriptions
      to JNI_type_infos

+ UNO links

    + http://api.openoffice.org/docs/DevelopersGuide/ProfUNO/ProfUNO.htm
        + UNO concepts

    + http://udk.openoffice.org/common/man/bridge.html
        + Bridge
        + Proxy - client side
        + Stub - server side
        + (c) 2001, mentions msvc 4.2, egcs; but RCS id says 2004

    + http://api.openoffice.org/docs/DevelopersGuide/AdvancedUNO/AdvancedUNO.htm
        + "Advanced UNO"
        + "Implementing UNO Language Bindings"
        + Milestones for bridge writing:
            + Unidirectional mapping (call UNO from your language, remote
               controlling the office)
            + limited Bidirectional (can implement UNO interfaces, e.g.
               Listeners)
            + Bidirectional, with ComponentLoader (can implement UNO components
              that the Global Service Manager can instantiate)
              Not (yet?) possible with CLI-UNO, according to
              cli_language_binding.sxw Chapter 8.

    + http://udk.openoffice.org/cpp/man/cpp_bridges.html
        + Implementing a C++-UNO-bridge
        + Some overlap with the previous link
        + "Environment" cppu/inc/environment.h
            - one per programming language or compiler
            - e.g. gcc3, cli
            - uno environment
        + "Mapping" cppu/inc/mapping.h
            - way to publish an interface into another environment
            - a mapped interface is called a proxy
        + "Bridge"
            - infrastructure for exchanging interfaces between two envs
            - bidirectional, i.e. one mapping for each direction

    + http://udk.openoffice.org/cli/download/CLI-UNO.zip
        + contains cli_language_binding.sxw

testtool problems
=================

Apply patches/test/mono-testtools.diff

It seems we're failing to bootstrap UNO; we have to
export the contents of unxlngi6.pro/lib/cli_bridgetest_inprocess.ini:

[Bootstrap]
UNO_TYPES=$SYSBINDIR/uno_types.rdb
UNO_SERVICES=$SYSBINDIR/uno_services.rdb

which helps. 

The bootstrapping code in:

sal/rtl/source/bootstrap.cxx uses 'getExecutableFile_Impl'
-> sal/osl/unx/source/process_impl.cxx (osl_bootstrap_getExecutableFile_Impl)
   -> grabs 'main' symbol, 

It may help to copy the mono binary locally to execute - since
a number of tasks do nasties with dlsym(main) -> where did main
come from.

There really is some disgraceful bootstrapping problem lurking in here.
Replacing the .ini file with simply:

[Bootstrap]
UNO_TYPES=uno_types.rdb
UNO_SERVICES=uno_services.rdb

yields some success ...

We also need (eg.) 'libsal.so' and this symlink is made only on
install: => add {install}/program to the LD_LIBRARY_PATH.

With more fixing we get:

CallUno member 'com.sun.star.lang.XMain::run'
Map parameter 0 '[]string'
dispatch 0x83abdb0
Thread attach, invoke 'com.sun.star.bridges.mono_uno.ManagedProxy:Dispatch (uno.Typelib.TypeDescription*,void*,void**,uno.Binary.Any**)'
exception occured: cannot get test object!

testtools/source/bridgetest/cli/cli_bridgetest_inprocess.cs:
    xClient.run(
	new String [] {
	"com.sun.star.test.bridge.cli_uno.CsTestObject" } );
    
