I’ve been struggling with a problem that I have for days now and I just cannot find a solution.
My problem is I have an application that calls a DLL (Metatrader 4 is the application). The DLL receives arrays and integers from Metatrader, does a lot of calculations, and returns a double value to Metatrader.
The C# DLL looks as follows:
using System;
using System.Collections.Generic;
using System.Text;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Linq;
using System.Threading;
using Encog;
using Encog.Neural.Networks;
using Encog.Neural.Networks.Layers;
using Encog.Neural.Networks.Training;
using Encog.Neural.Networks.Training.Propagation.Resilient;
using Encog.Engine.Network.Activation;
using Encog.ML.Data;
using Encog.ML.Data.Basic;
using Encog.App.Quant.Indicators;
using Encog.App.Quant;
using Encog.Neural.NeuralData;
using System.Data;
using System.ComponentModel;
namespace NN_1_DLL
{
public static class UnmanagedExports
{
static DataTable dt;
static DataGridView gridview;
static Form frm;
static double NeuralOutput = 0;
static double LowNormalize;
static double HighNormalize;
static double dataHigh;
static double dataLow;
static int NNInputs;
static int NNOutputs;
static double[] trainingData;
static double[] neuralInput;
static int trainingDataSize;
static int trainingSets;
static int epochMax;
static int hiddenLayerNeurons;
static double[][] TRAINING_INPUT;
static double[][] TRAINING_OUTPUT;
static double[] NEURAL_INPUT;
static bool isShowGUI;
static bool FormInitiated = false;
public static void GUI()
{
int i, j;
dt = new DataTable("Table");
for (i = 0; i < NNInputs; i++)
{
dt.Columns.Add("Input " + i, typeof(double));
}
dt.Columns.Add("Output", typeof(double));
for (i = 0; i < TRAINING_INPUT.GetLength(0); i++)
{
DataRow dataRow = dt.NewRow();
for (j = 0; j < TRAINING_INPUT[i].GetLength(0); j++)
{
//dataRow["Input " + j] = TRAINING_INPUT[i][j];
dataRow["Input " + j] = ((((dataLow - dataHigh) * TRAINING_INPUT[i][j] - HighNormalize * dataLow + dataHigh * LowNormalize) / (LowNormalize - HighNormalize)));
}
//dataRow["Output"] = TRAINING_OUTPUT[i][0];
dataRow["Output"] = ((((dataLow - dataHigh) * TRAINING_OUTPUT[i][0] - HighNormalize * dataLow + dataHigh * LowNormalize) / (LowNormalize - HighNormalize)));
dt.Rows.Add(dataRow);
}
if (FormInitiated == false)
{
frm = new Form();
frm.Name = "frm";
frm.ControlBox = false;
frm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
frm.BackColor = System.Drawing.Color.LightGray;
frm.Size = new System.Drawing.Size(800, 600);
frm.Show();
gridview = new DataGridView();
gridview.Name = "gridview";
gridview.Height = 600;
gridview.Width = 800;
frm.Controls.Add(gridview);
FormInitiated = true;
}
gridview.DataSource = dt;
}
static void PrepareData()
{
double[] array_input = new double[NNInputs];
double[] array_output = new double[NNOutputs];
int i = 0;
int j = 0;
int refpoint = 0;
//PREPARE DATA FOR NEURAL NETWORK
dataHigh = Math.Max(trainingData.Max(), neuralInput.Max());
dataLow = Math.Min(trainingData.Min(), neuralInput.Min());
for (i = 0; i < trainingData.GetLength(0); i++)
{
trainingData[i] = (((trainingData[i] - dataLow) / (dataHigh - dataLow)) * (HighNormalize - LowNormalize) + LowNormalize);
}
NEURAL_INPUT = new double[neuralInput.GetLength(0)];
for (i = 0; i < neuralInput.GetLength(0); i++)
{
NEURAL_INPUT[i] = (((neuralInput[i] - dataLow) / (dataHigh - dataLow)) * (HighNormalize - LowNormalize) + LowNormalize);
}
TRAINING_INPUT = new double[trainingSets][];
TRAINING_OUTPUT = new double[trainingSets][];
for (i = 0; i < trainingSets; i++)
{
refpoint = (i * (NNInputs + NNOutputs));
for (j = refpoint; j < refpoint + NNInputs; j++)
{
array_input[j - refpoint] = trainingData[j];
}
refpoint = refpoint + NNInputs;
for (j = refpoint; j < refpoint + NNOutputs; j++)
{
array_output[j - refpoint] = trainingData[j];
}
TRAINING_INPUT[i] = array_input;
TRAINING_OUTPUT[i] = array_output;
array_input = new double[NNInputs];
array_output = new double[NNOutputs];
}
}
static void ComputeNN()
{
int i = 0;
BasicNetwork network = new BasicNetwork();
network.AddLayer(new BasicLayer(new ActivationTANH(), true, NNInputs));
network.AddLayer(new BasicLayer(new ActivationTANH(), true, hiddenLayerNeurons));
network.AddLayer(new BasicLayer(new ActivationTANH(), true, NNOutputs));
network.Structure.FinalizeStructure();
network.Reset();
IMLDataSet trainingSet = new BasicMLDataSet(TRAINING_INPUT, TRAINING_OUTPUT);
ITrain train = new ResilientPropagation(network, trainingSet);
int epoch = 1;
do
{
train.Iteration();
epoch++;
} while ((epoch < epochMax));
INeuralData input = new Encog.Neural.Data.Basic.BasicNeuralData(NNInputs);
for (i = 0; i < NNInputs; i++)
{
input[i] = NEURAL_INPUT[i];
}
IMLData output = network.Compute(input);
NeuralOutput = ((((dataLow - dataHigh) * output[0] - HighNormalize * dataLow + dataHigh * LowNormalize) / (LowNormalize - HighNormalize)));
}
[DllExport("NNExportDLL", CallingConvention = CallingConvention.StdCall)]
static double NNExportDLL([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] double[] training_data, int training_data_size, int inputs, int outputs, int training_sets, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] double[] neural_input, int epoch_Max, int hidden_Layer_Neurons, double Low_Normalize, double High_Normalize, int ShowGUI)
{
//Define some global variables
LowNormalize = new double();
HighNormalize = new double();
NNInputs = new int();
NNOutputs = new int();
trainingData = new double[training_data_size];
trainingDataSize = new int();
trainingSets = new int();
epochMax = new int();
hiddenLayerNeurons = new int();
neuralInput = new double[inputs];
LowNormalize = Low_Normalize;
HighNormalize = High_Normalize;
NNInputs = inputs;
NNOutputs = outputs;
trainingData = training_data;
trainingDataSize = training_data_size;
trainingSets = training_sets;
epochMax = epoch_Max;
hiddenLayerNeurons = hidden_Layer_Neurons;
neuralInput = neural_input;
if (ShowGUI == 1) { isShowGUI = true; } else { isShowGUI = false; }
if (isShowGUI == true)
{
PrepareData();
ComputeNN();
GUI();
}
if (isShowGUI == false)
{
PrepareData();
ComputeNN();
}
return (NeuralOutput);
}
}
}
I have to use threading due to the fact that the GUI freezes during calculations, there is absolutely no response from the GUI(). I have tried the backgroundworker class but the DLL returns the value before the functions are completed and the GUI still freezes.
The GUI() is built from the data calculated in the PrepareData() and ComputeNN() function, so they have to be executed first before the GUI() function is executed. Also the PrepareData() and ComputeNN() functions must be completed before the function returns the double value to Metatrader.
I have absolutely no experience with threading and GUIs within DLL’s, so would appreciate any advice!
Maybe I’m trying to do something that is either impossible or stupid. The whole reason for the GUI is for me to see if the data is calculated as it is supposed to be (more of a way for me to debug the code). I will later on add charts and such to visualize the training process/data. If there is a better way to do this please let me know!*
Try using the GUI thread’s dispatcher:
you can look at this link for a tutorial on the WPF dispatcher.
Give the BackgroundWorker another try. Declare these static fields:
and these static methods (the event handlers):
then instead of:
try something like this:
Based on all of your code, and in order to test your app you should try this:
the main problem was actually your trying to run the frm.show() without using Application.Run.
Another edit: don’t forget to substitute what’s in the bw.DoWork delegate with your own logic.