How to Use a Free Pascal DLL InputBox() to import strings to an EA?

 

I am very grateful to 7Bit for his contribution elsewhere in the forum on creating a DLL with Lazarus/Free Pascal which can pass data between the DLL and an EA.

I would like to install a Pascal InputBox in 7Bit's DLL foo() function to enable the user to pass text input (commands) to the EA. I have tried writeln() and read(), but MT4 crashes with these compiled into the DLL.

I'm feeling my way gingerly around Pascal, and am wondering if a more experienced person can point me in the right direction.

------

Another possibility is a script using the DLL -- the script could pass the string data from the InputBox to the EA via MT4 Global Variables.

 

DaveUdon:

I have tried writeln() and read(), but MT4 crashes with these compiled into the DLL.

Long answer: readln() and writeln() work on stdin/stdout, this means they can only be used for programs that run on the console. MT4 does not have a console attached to it and stdin and stdout are not open and cannot be used. Trying to read or write to these will trigger an exception that will crash the application (if you don't catch it).


Short answer: You simply cannot use readln() or writeln() in MT4, there is nothing to write to and nothing to read from.


It is possible (but not easy) to open a GUI form from within your DLL but you would have to be aware that

  • when called from a script the form will not be created from within the main thread and not receive any events
  • when called from an indicator you would block and freeze MT4 as long as your DLL GUI is in its GUI event loop.


For this to work you need to

  • start a separate thread that will pretend towards the LCL that it is the main thread and then open a form
  • start the event loop from this new "main" thread (a GUI needs an event loop)
  • optionally if you need more windows open them also only from within this thread.
  • dont call directly any methods of these LCL classes from other threads (from mql4), always call them indirectly via Synchronize() or PostMessage() or similar mechanisms.

additionally:

  • use cmem
  • use no older compiler than 2.4.2

short answer: don't do it. I tried it myself and although i finally (somehow) succeeded I decided that it is not the recommended way of doing things. It is not the way the LCL was meant to be used, it contained too many dirty hacks.

Make a separate application that shows the GUI, start it, stop it and communicate with it through some sort of IPC. For example your DLL could start the separate GUI .exe with a TProcess instance which will also conveniently give you streams for input and output to communicate with it. Compile the GUI as console application (so that it has stdio available). For an example how to start a separate application with TProcess and communicate with it through stdio (TProcess.Input and TProcess.Output) have a look at the mt4 -> R library (mt4R.dll).


Maybe I will try it again at some later time and find a solution that is simple and elegant and robust enough and put it all into a unit that can be easily used but not at the moment because I'm busy with other things and also not before Lazarus 0.9.30 will be finally released.

 

Appreciate your response...

I quickly wrote up a script using:

#import "user32.dll"
bool GetAsyncKeyState(int nVirtKey);
#import

-- and communicated with the EA via MT4 Global Variables.

Nice to have your Lazarus/FPC ddl however.

Regards

 
DaveUdon:

Nice to have your Lazarus/FPC

Its not my Lazarus/FPC, I'm only an enthusiastic user who closely follows its development and maybe contributes a small patch every few months.
 

I know this thread is old but I will ask the question anyway.

Couldn't strings be passed to a running DLL via a file that way the DLL would not be affected or interrupted. The user interface or GUI would be just another windows program that reads and writes to say an input file and an output file then the DLL could check the input file for new data clearing it and output stuff to the output file that the GUI would be monitoring. I know it isn't what a software developer might do but it seems simple and doable to me.

 
Ruptor:

I know this thread is old but I will ask the question anyway.

Couldn't strings be passed to a running DLL via a file that way the DLL would not be affected or interrupted. The user interface or GUI would be just another windows program that reads and writes to say an input file and an output file then the DLL could check the input file for new data clearing it and output stuff to the output file that the GUI would be monitoring. I know it isn't what a software developer might do but it seems simple and doable to me.

I have experimented with something like this (but using stdin/stdout instead of files): The Application consists of 2 parts: A normal .exe file for the GUI (with its own event loop, totally conventional without any ugly hacks, could even run standalone) and a dll. The dll will be used by mql4 as usual and the dll will also create a new process with the GUI .exe and attach to its stdio to communicate with it. This would avoid the ugly file IO. The exe would just need to be linked as console application to have stdio available (uncheck the box "Windows GUI Application") and also have a separate thread running to read commands from stdin and trigger GUI events.

The next simpler solution would be the GUI .exe without any additional dll, simply communicating through file IO as you suggested.

 

Hi 7bit

Thanks for the useful explanation. I suggested using files from the DLL to reduce the useage of MT4 code to a minimum because it can't be trusted. I have used MT4 file I/O and just like the rest of MT4 odd things happen so it is best to put as much code in FPC as possible.

 
7bit:
DaveUdon:
I have tried writeln() and read(), but MT4 crashes with these compiled into the DLL.

Long answer: readln() and writeln() work on stdin/stdout, this means they can only be used for programs that run on the console. MT4 does not have a console
The alternative that work in BOTH mt4 and dll's is dbgview from sysinternals and OutputDebugStringA().
/**
* send information to OutputDebugString() to be viewed and logged by
* SysInternal's DebugView (free download from microsoft) This is ideal for
* debugging as an alternative to Print(). The function will take up to 10
* stringa (or numeric) arguments to be concatenated into one debug message.*/
#import "kernel32.dll"
   void OutputDebugStringA(string msg);
#import
void log(string s1,    string s2="", string s3="", string s4="", string s5="",
         string s6="", string s7="", string s8="", string s9="", string s10=""){
        string out = StringConcatenate(WindowExpertName(), ".mq4 ", Symbol(), " ",
                                   s1, s2, s3, s4, s5, s6, s7, s8, s9, s10);
        OutputDebugStringA(out);
}
 
WHRoeder:
The alternative that work in BOTH mt4 and dll's is dbgview from sysinternals and OutputDebugStringA().

what is the log file's directory?
 
If you had bothered to read about dbgview you would know that there isn't one.