DLL Hell

 

We've all tried it.  There's something we want to do in a DLL but Metatrader is still stuck in the 19th century.  For my inquiry, I give you this:

The EA:

//+------------------------------------------------------------------+
//|                                                   MT4Exports.mq4 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

#import "MT4Exports.dll"
int addthem(int a, int b);
int addthemO(int a, int b);
#import
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
  
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   int result=addthem(3,5);
   Print("result:",result);
   result=addthemO(4,6);
   Print("result:",result);
  }
//+------------------------------------------------------------------+

The DLL

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RGiesecke.DllExport;
using System.IO;

namespace MT4Exports
{
    public class Class1
    {
        [DllExport]
        public static int addthem(int a, int b)
        {
            WriteMe("Running addthem");
            return a + b;
        }

        [DllExport]
        public static int addthemO(int a, int b)
        {
            return FigureO.addthem(a, b);
        }

        public static void WriteMe(string line)
        {
            using (StreamWriter writer = new StreamWriter(@"ClientMessage.txt", true))
            {
                writer.WriteLine(line);
            }
        }

    }

    public class FigureO
    {
        public static int addthem(int a, int b)
        {
            return a + b;
        }
    }
}

Run that and get this:

Unhandled exception 0xE0434352

Change the DLL to this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RGiesecke.DllExport;
using System.IO;

namespace MT4Exports
{
    public class Class1
    {
        [DllExport]
        public static int addthem(int a, int b)
        {
            //WriteMe("Running addthem");
            return a + b;
        }

        [DllExport]
        public static int addthemO(int a, int b)
        {
            return FigureO.addthem(a, b);
        }
/*
        public static void WriteMe(string line)
        {
            using (StreamWriter writer = new StreamWriter(@"ClientMessage.txt", true))
            {
                writer.WriteLine(line);
            }
        }
*/

    }

    public class FigureO
    {
        public static int addthem(int a, int b)
        {
            return a + b;
        }
    }
}

..And it works flawlessly.

So the question is, why?  Is this something I'm doing wrong?  I don't think so.

So, anyone got any ideas?

 
Michael:

We've all tried it.  There's something we want to do in a DLL but Metatrader is still stuck in the 19th century.  For my inquiry, I give you this:

The EA:

        public static void WriteMe(string line)        {
            using (StreamWriter writer = new StreamWriter(@"ClientMessage.txt", true))
            {
                writer.WriteLine(line);
            }
        }

    }
}

Run that and get this:

Unhandled exception 0xE0434352

I do not know this language, but is the "using" keyword in the WriteMe method OK? 
 

"Unhandled exception 0xE0434352" means that you have unhandled exception in your managed code.

Add try/catch block inside the  WriteMe() function and check if you can write to the file.

 
Michael:

So, anyone got any ideas?

Your file ClientMessage.txt is potentially going to be written into the working directory of the MT4 executable. This can be the \Program Files area, and attempts to write there will fail unless the MT4 executable is running with escalated privileges.

So, you may simply have an unhandled .NET exception arising from a file access error. Try explicitly writing ClientMessage.txt to an unprotected area of disk.

 
Ovo Cz:
I do not know this language, but is the "using" keyword in the WriteMe method OK? 
(Yes. It's simply telling .NET to dispose of the object at the end of the Using block, closing the file handle. I believe it's equivalent to java.io.Closeable: http://stackoverflow.com/a/2016311)
 
JC:

Your file ClientMessage.txt is potentially going to be written into the working directory of the MT4 executable. This can be the \Program Files area, and attempts to write there will fail unless the MT4 executable is running with escalated privileges.

So, you may simply have an unhandled .NET exception arising from a file access error. Try explicitly writing ClientMessage.txt to an unprotected area of disk.

As you said, I was thinking the problem is it writes outside the sandbox. However I don't have enough experience with DLL, what's the difference with using a WINAPI DLL to write anywhere outside MT4 sandbox ?
 
Alain Verleyen:
However I don't have enough experience with DLL, what's the difference with using a WINAPI DLL to write anywhere outside MT4 sandbox ?
No difference. The issue with the C# code appears to be that it's not specifying a location for the ClientMessage.txt file, and therefore it may be defaulting to the startup/working directory of terminal.exe. If that's within Program Files, then attempts to write the file will fail.
 
JC:
No difference. The issue with the C# code appears to be that it's not specifying a location for the ClientMessage.txt file, and therefore it may be defaulting to the startup/working directory of terminal.exe. If that's within Program Files, then attempts to write the file will fail.
Ah ok I see. Thanks.
 

Ok.  It's not where the DLL writes the file.  The '@' symbol specifies to write the file where the DLL was launched from.  In this case, the MQL/Libraries folder.  I've changed this to my documents / downloads / etc.   Doesn't matter.

It's the using statement.  Metatrader bombs on that statement.  Why?  Has anyone gotten a using statement to work in a C# DLL for Metatrader?  I thought this worked in previous builds.

 
JC:
(Yes. It's simply telling .NET to dispose of the object at the end of the Using block, closing the file handle. I believe it's equivalent to java.io.Closeable: http://stackoverflow.com/a/2016311)
Thank you, everything's clear now.
 
Michael:

Ok.  It's not where the DLL writes the file.  The '@' symbol specifies to write the file where the DLL was launched from.  In this case, the MQL/Libraries folder.  I've changed this to my documents / downloads / etc.   Doesn't matter.

It's the using statement.  Metatrader bombs on that statement.  Why?  Has anyone gotten a using statement to work in a C# DLL for Metatrader?  I thought this worked in previous builds.

As far as I am aware, the @ simply indicates a verbatim string literal. It is not going to control where the file is written.

Your code works for me in a copy of MT4 installed outside \Program Files, and crashes if MT4 is installed inside \Program Files. 

If I run MT4 from a location such as C:\MyMT4, i.e. such that the executable is C:\MyMT4\terminal.exe, then the file ClientMessage.txt is created at C:\MyMT4\ClientMessage.txt. This is obviously going to cause problems if MT4 is inside a protected area of disk such as \Program Files.

If I change your code as follows ...

        public static void WriteMe(string line)
        {
            try
            {
                using (StreamWriter writer = new StreamWriter(@"ClientMessage.txt", true))
                {
                    writer.WriteLine(line);
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Trace.WriteLine(e.Message);
            }
        }

... then the exception which is logged when I use the DLL from a copy of MT4 within Program Files is, very unsurprisingly, as follows:

Access to the path 'C:\Program Files (x86)\xxxx\ClientMessage.txt' is denied.