forked from AustenConrad/mql4zmq
-
Notifications
You must be signed in to change notification settings - Fork 12
/
OTMql4Zmq.mqh
410 lines (344 loc) · 13 KB
/
OTMql4Zmq.mqh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
// -*-mode: c; c-style: stroustrup; c-basic-offset: 4; coding: utf-8-dos -*-
#property copyright "Copyright © 2012, Austen Conrad and Open Trading"
#property link "https://github.com/OpenTrading/"
#import "kernel32.dll"
int lstrlenA(int);
void RtlMoveMemory(uchar & arr[], int, int);
int LocalFree(int); // May need to be changed depending on how the DLL allocates memory
#import
#import "OTMql4/mql4zmq.dll"
//+--------------------------------------------------------------------------------+
//| mql4zmq.dll exported functions with datatypes reconfigured for
//| MetaTrader 4's reduced type set. The intention is to not call these
//| diretly. Please use renamed versions in next section to reduce confusion.
//|
//| Type Changes:
//| zmq_msg_t => int
//| const char => string
//| size_t => int
//| void (if it's a param that's passed) => string
//| zmq_free_fn => int
//+--------------------------------------------------------------------------------+
// Tests.
int ping(uchar &pong[]);
// Version.
void mql4zmq_version(int &major[],int &minor[],int &patch[]);
// Errors.
int mql4zmq_errno();
int mql4zmq_strerror(int errnum);
// Messages.
int mql4zmq_msg_init(int &msg[]);
int mql4zmq_msg_init_size (int &msg[], int iSize);
int mql4zmq_msg_init_data (int &msg[], uchar &data[], int iSize);
int mql4zmq_msg_close (int &msg[]);
int mql4zmq_msg_move (int dest, int src);
int mql4zmq_msg_copy (int dest, int src);
// was string
int mql4zmq_msg_data (int &msg[]);
int mql4zmq_msg_size (int &msg[]);
// Infrastructure.
int mql4zmq_init (int iIoThreads);
int mql4zmq_term (int context);
// Sockets.
int mql4zmq_socket (int context, int type);
int mql4zmq_close (int socket);
int mql4zmq_setsockopt (int socket, int option, uchar & optval[], int optvallen);
int mql4zmq_getsockopt (int socket, int option, uchar & optval[], int optvallen);
int mql4zmq_bind (int socket, uchar & addr[]);
int mql4zmq_connect (int socket, uchar &addr[]);
int mql4zmq_send (int socket, int &msg[], int flags);
int mql4zmq_recv (int socket, int &msg[], int flags);
// I/O multiplexing.
int mql4zmq_poll (int items, int nitems, int timeout);
// Built-in devices.
int mql4zmq_device (int device, int insocket, int outsocket);
// Helper Functions.
// now int - was string
int mql4s_recv (int socket, int flags);
int mql4s_send (int socket, uchar &text[]);
int mql4s_sendmore (int socket, uchar &text[]);
#import
void vStringToCharArrayDebug(string uData, uchar&sCharData[]) {
int ansiLength = StringLen(uData);
StringToCharArray(uData, sCharData);
int iSpos=0;
uchar sChar;
//int iChar;
while (iSpos < ansiLength) {
sChar = sCharData[iSpos];
if (sChar < 32 || sChar > 127) {
Print("ERROR: Illegal char " + IntegerToString((int)sChar) + " in " + uData);
}
iSpos=iSpos+1;
}
}
//+---------------------------------------------------------------------------------+
//| Renaming of functions to original naming structure. Use these when buiding
//| your Expert Advisors so that we are consistant with ZeroMQ Naming conventions.
//+---------------------------------------------------------------------------------+
string zmq_ping(string uSource) {
uchar sCharData[];
uchar sCharArray[];
int iRecvPtr, iMessLen;
string uMessage;
StringToCharArray(uSource, sCharData);
// Call the DLL function and get its block of string memory as an int pointer to the
// memory rather than as a string
iRecvPtr = ping(sCharData);
// Get the length of the string
iMessLen = lstrlenA(iRecvPtr);
// if message length is 0, leave.
if (iMessLen < 1) {
Print("zmq_ping: Warning! Pong Message has zero length.");
return("");
}
/*! replace with uAnsi2Unicode
// Create a uchar[] array whose size is the string length (plus null terminator)
ArrayResize(sCharArray, iMessLen);
// Use the Win32 API to copy the string from the block returned by the DLL
// into the uchar[] array
RtlMoveMemory(sCharArray, iRecvPtr, iMessLen);
//?ArrayCopy(sCharArray, iRecvPtr, iMessLen+1);
// Convert the uchar[] array to a message string
uMessage = CharArrayToString(sCharArray);
// Free the string memory returned by the DLL.
// This step can be removed but, without it,
// there will be a memory leak.
// The correct method for freeing the string
// *depends on how the DLL allocated the memory*
// The following assumes that the DLL has used LocalAlloc
// (or an indirect equivalent). If not,
// then the following line may not fix the leak, and may even cause a crash.
LocalFree(iRecvPtr);
*/
uMessage = uAnsi2Unicode(iRecvPtr);
return(uMessage);
}
// Version.
void zmq_version(int &major[],int &minor[],int &patch[]) {
mql4zmq_version(major,minor,patch);
}
// Errors.
int zmq_errno() {
return(mql4zmq_errno());
}
string zmq_strerror(int errnum) {
uchar sCharArray[];
int iRecvPtr, iMessLen;
string uMessage;
// Call the DLL function and get its block of string memory as an int pointer to the
// memory rather than as a string
iRecvPtr = mql4zmq_strerror(errnum);
// Get the length of the string (without a null terminator)
iMessLen = lstrlenA(iRecvPtr);
// if message length is 0, leave.
if (iMessLen < 1) {
Print("zmq_strerror: Warning! Error Message has zero length.");
return("");
}
/*! replace with uAnsi2Unicode
// Create a uchar[] array whose size is the string length (plus null terminator)
ArrayResize(sCharArray, iMessLen+1);
// Use the Win32 API to copy the string from the block returned by the DLL
// into the uchar[] array
RtlMoveMemory(sCharArray, iRecvPtr, iMessLen+1);
//?ArrayCopy(sCharArray, iRecvPtr, iMessLen+1);
// Convert the uchar[] array to a message string
uMessage = CharArrayToString(sCharArray);
// Free the string memory returned by the DLL.
// This step can be removed but, without it,
// there will be a memory leak.
// The correct method for freeing the string
// *depends on how the DLL allocated the memory*
// The following assumes that the DLL has used LocalAlloc
// (or an indirect equivalent). If not,
// then the following line may not fix the leak, and may even cause a crash.
LocalFree(iRecvPtr);
*/
uMessage = uAnsi2Unicode(iRecvPtr);
return(uMessage);
}
// Messages.
int zmq_msg_init(int &msg[]) {
return(mql4zmq_msg_init(msg));
}
int zmq_msg_init_size (int &msg[], int iSize) {
return(mql4zmq_msg_init_size(msg, iSize));
}
int zmq_msg_init_data (int &msg[], string data, int iSize) {
uchar sCharData[];
StringToCharArray(data, sCharData);
return(mql4zmq_msg_init_data(msg, sCharData, iSize));
}
int zmq_msg_close (int &msg[]) {
return(mql4zmq_msg_close(msg));
}
int zmq_msg_move (int dest, int src) {
return(mql4zmq_msg_move(dest, src));
}
int zmq_msg_copy (int dest, int src) {
return(mql4zmq_msg_copy (dest, src));
}
string zmq_msg_data (int &msg[]) {
uchar sCharArray[];
int iRecvPtr, iMessLen, iRetval;
string uMessage;
// Call the DLL function and get its block of string memory as an int pointer to the
// memory rather than as a string
iRecvPtr = mql4zmq_msg_data(msg);
// Get the length of the string
iMessLen = mql4zmq_msg_size(msg);
// if message length is 0, leave.
if (iMessLen < 1) {
// Print("zmq_msg_data: Warning! Message has zero length.");
return("");
}
Print("zmq_msg_data: Message Length mql4zmq_msg_size "+IntegerToString(iMessLen));
/*? replace with uAnsi2Unicode */
if (true) {
// Create a uchar[] array whose size is the string length (plus null terminator)
iRetval = ArrayResize(sCharArray, iMessLen+1);
if (iRetval < 1) {
Print("zmq_msg_data: Warning! Message resize failed: " + iRetval);
return("");
}
// Use the Win32 API to copy the string from the block returned by the DLL
// into the uchar[] array
RtlMoveMemory(sCharArray, iRecvPtr, iMessLen+1);
//? added just to be sure
//?sCharArray[iMessLen+1] = (uchar)0x00;
// Convert the uchar[] array to a message string
uMessage = CharArrayToString(sCharArray);
// Free the string memory returned by the DLL.
// This step can be removed but, without it,
// there will be a memory leak.
// The correct method for freeing the string
// *depends on how the DLL allocated the memory*
// The following assumes that the DLL has used LocalAlloc
// (or an indirect equivalent). If not,
// then the following line may not fix the leak, and may even cause a crash.
//?
LocalFree(iRecvPtr);
} else {
uMessage = uAnsi2Unicode(iRecvPtr);
}
return(uMessage);
}
int zmq_msg_size (int &msg[]) {
return(mql4zmq_msg_size(msg));
}
// Infrastructure.
int zmq_init(int iIoThreads) {
int iRetval, iError;
if (iIoThreads < 1) {
Print("mql4zmq_init: iIoThreads must be >= 1: " +iIoThreads);
return(0);
}
// ctx_new in 4.x
iRetval = mql4zmq_init(iIoThreads);
if (iRetval < 1) {
iError = zmq_errno();
Print("mql4zmq_init: Initialization failed: " +zmq_strerror(iError));
return(-iError);
}
return(iRetval);
}
int zmq_term (int context) {
return(mql4zmq_term(context));
}
// Sockets.
int zmq_socket (int context, int type) {
return(mql4zmq_socket(context, type));
}
int zmq_close (int socket) {
return(mql4zmq_close(socket));
}
int zmq_setsockopt (int socket, int option, string optval) {
uchar optvalChar[];
StringToCharArray(optval, optvalChar);
return(mql4zmq_setsockopt(socket, option, optvalChar, StringLen(optval)));
}
int zmq_getsockopt (int socket, int option, string optval) {
uchar optvalChar[];
StringToCharArray(optval, optvalChar);
return(mql4zmq_getsockopt(socket, option, optvalChar, StringLen(optval)));
}
int zmq_bind (int socket, string addr) {
uchar addrChar[];
StringToCharArray(addr, addrChar);
return(mql4zmq_bind(socket, addrChar));
}
int zmq_connect (int socket, string addr) {
uchar addrChar[];
StringToCharArray(addr, addrChar);
return(mql4zmq_connect(socket, addrChar));
}
// Defaults to no flags; meaning the flag is an optional paramater.
// Common flags are: ZMQ_NOBLOCK, ZMQ_SNDMORE
int zmq_send (int socket, int &msg[], int flags=0) {
return(mql4zmq_send(socket, msg, flags));
}
// Defaults to no flags; meaning the flag is an optional paramater.
// Common flags are: ZMQ_NOBLOCK, ZMQ_SNDMORE
int zmq_recv (int socket, int &msg[], int flags=0) {
return(mql4zmq_recv(socket, msg, flags));
}
// I/O multiplexing.
int zmq_poll (int items, int nitems, int timeout) {
return(mql4zmq_poll(items, nitems, timeout));
}
// Built-in devices.
int zmq_device (int device, int insocket, int outsocket)
{
return(mql4zmq_device(device, insocket, outsocket));
}
// zhelper functions.
string s_recv (int socket, int flags=0) {
uchar sCharArray[];
int iRecvPtr, iMessLen;
string uMessage;
//vTrace("Call the DLL function and get its block of string memory");
// as an int pointer to the memory rather than as a string
iRecvPtr = mql4s_recv(socket, flags);
iMessLen = lstrlenA(iRecvPtr);
// if message length is 0, leave.
if (iMessLen < 1) {
//vTrace("s_recv: Message has zero length.");
return("");
}
//vTrace("s_recv: lstrlenA: "+iMessLen);
/*! replace with uAnsi2Unicode
//vTrace("Create a uchar[] array whose size is the string length (plus terminator)");
ArrayResize(sCharArray, iMessLen+1);
// Use the Win32 API to
//vTrace("copy the string from the block returned by the DLL");
// into the uchar[] array
RtlMoveMemory(sCharArray, iRecvPtr, iMessLen+1);
//vTrace("Convert the uchar[] array to a message string");
uMessage = CharArrayToString(sCharArray);
//vTrace("Free the string memory returned by the DLL");
// This step can be removed but, without it,
// there will be a memory leak.
// The correct method for freeing the string
// *depends on how the DLL allocated the memory*
// The following assumes that the DLL has used LocalAlloc
// (or an indirect equivalent). If not,
// then the following line may not fix the leak, and may even cause a crash.
LocalFree(iRecvPtr);
*/
uMessage = uAnsi2Unicode(iRecvPtr);
//vTrace("Drop excess null's from the pointer.");
//uMessage = StringSubstr(uMessage, 0, iMessageLen);
// vDebug("Return message string "+uMessage);
return(uMessage);
}
int s_send (int socket, string text) {
uchar textChar[];
StringToCharArray(text, textChar);
return(mql4s_send(socket, textChar));
}
int s_sendmore (int socket, string text) {
uchar textChar[];
StringToCharArray(text, textChar);
return(mql4s_sendmore(socket, textChar));
}