[Mono-dev] Class built by mono throws FileNotFoundException when run on windows

Alex J Lennon ajlennon at dynamicdevices.co.uk
Wed Sep 2 09:03:05 UTC 2015


On 01/09/2015 21:04, Edward Ned Harvey (mono) wrote:
> I've always used separate project files on windows and linux, in order to include different compiler symbols, in order to make projects build with different dependencies. I've been chastised here for doing it, so I'd like to find a better way. (Miguel and others tore apart a pull request, saying I should never check __MONO__, if I need behavior to be different on windows and non-windows, I need to use a runtime check. The problem is, as described below, the runtime check can't build or run on windows, so I'd like to figure out how it should be done).
>
> Right now, I have a class, which is using Mono.Unix.Native, because of a method that does this: 
>     if (Type.GetType("Mono.Runtime") != null) {
>         Syscall.chmod(...);
>     }
>
> When built and run on mono, works great. The problem is building and running on windows. In order to make it build, I copied Mono.Posix.dll into the project and referenced it, with CopyLocal = False. This way, Mono.Posix.dll doesn't get copied to the build directory, which is good because it's already present on mono systems, and not needed on windows systems - the only reason for it to exist in the project is because windows can't build without it.
>
> So it builds. But unfortunately, it won't run on windows. It throws FileNotFoundException "Mono.Posix.dll" before evaluating the if-clause.
>
> The workaround I've found is to create a wrapper class MonoSpecific, so the if-clause and the Mono.Posix call are not in the same file. But this is clearly a hack. Is there a better way?
>
> Hello.cs:
>     using System;
>     namespace helloProject
>     {
>         static class Hello
>         {
>             static void ChangePermsIfNecessary()
>             {
>                 if (Type.GetType("Mono.Runtime") != null) {
>                     MonoSpecific.DoChmod();
>                 }
>             }
>         }
>     }
>
> MonoSpecific.cs:
>     using System;
>     using Mono.Unix.Native;
>     namespace helloProject
>     {
>         static class MonoSpecific
>         {
>             static void DoChmod()
>             {
>                 Syscall.chmod(...);
>             }
>         }
>     }

Ned - I use a runtime check, interface definitions, and a factory method
that loads the concrete implementations from specific BSP DLLS using
Activator.

I do this a few commercial apps we have which I need to run "out of the
box" on Windows and Embedded Linux platforms running Mono.

e.g. Check here is the same as yours

    public class MonoHelper
    {
        public static bool IsRunningOnMono
        {
            get { return Type.GetType("Mono.Runtime") != null; }
        }
        ...

Then a BSP interface and a factory method to create a specific class
from a specific DLL based on a naming convention. I have some platform
auto-detection logic around this elsewhere.

        private static  IBSP _thisBSP;
        private static readonly object _objLock = new object();
       
        public static IBSP CreateBSP(string platform)
        {
            lock (_objLock)
            {
                if (_thisBSP == null)
                {
                    _logger.Debug("Creating BSP for platform: " + platform);

                    try
                    {
                        var oh = Activator.CreateInstanceFrom(
                           
Path.Combine(Directory.GetCurrentDirectory(), "MyApp.BSP." + platform +
".dll"),
                                                             
"MyApp.BSP." + platform + ".BSP");
                        _thisBSP = (IBSP) oh.Unwrap();
                    } catch(Exception e)
                    {
                        _logger.Error("Can't create BSP: " + e.Message);
                    }

                }
                return _thisBSP;
            }
        }

So this'll use MyApp.BSP.Mono.dll or MyApp.BSP.Win32.dll or whatever and
instantiate a BSP object implementing IBSP

Then I tend to have a set of other interfaces exposed by that BSP class
and the concrete implementations can then
have the dependencies on the platform specific DLLs e.g. Mono.Posix.

public interface IBSP
    {
        ISignalHandler SignalHandler { get; }

        IFuelGauge FuelGauge { get; }
       
        ISecurityHandler SecurityHandler { get; }

        ISystemInfo SystemInfo { get; }
}

public class BSP : IBSP
    {
        private Win32SignalHandler _signalHandler = new
Win32SignalHandler();
        private Win32SecurityHandler _securityHandler = new
Win32SecurityHandler();
        private Win32SystemInfo _systemInfo = new Win32SystemInfo();

        public ISignalHandler SignalHandler
        {
            get { return _signalHandler;  }
        }

        public ISecurityHandler SecurityHandler
        {
            get { return _securityHandler; }
        }

        public ISystemInfo SystemInfo
        {
            get { return _systemInfo; }
        }
    }

...

using System;
using System.Threading;
using SensorNetGateway.Core;

using Mono.Unix;
using Mono.Unix.Native;

namespace MyApp.BSP.Mono
{
    class MonoSignalHandler : ISignalHandler
    {
        ...

        private void Worker()
        {
            _workerIsRunning = true;

            var signalHUP = new UnixSignal(Signum.SIGHUP);
            var signalTERM = new UnixSignal(Signum.SIGTERM);
            ...



It works well for me, although as the platform specific DLL references
are decoupled through
use of Activator you do have to make sure you add a reference to the
main project so your needed DLLS
are copied out to the build folder.

Hope that is of some interest.

Cheers,

Alex



More information about the Mono-devel-list mailing list