|
| 1 | +/* |
| 2 | + MQL4ZMQ - MQL4 bindings for ZeroMQ |
| 3 | + |
| 4 | + (c) 2012 Austen Conrad. Any of this software, or any part thereof, is allowed as long as the use complies with GPL v3.0: http://www.gnu.org/licenses/gpl-3.0-standalone.html |
| 5 | + Additionally, no warrenty of any kind is made. Use software at own risk. |
| 6 | +
|
| 7 | + =================================== |
| 8 | +
|
| 9 | + The reason for all of this is that MetaTrader is a visual basic application and therefore is written using the STDCALL calling |
| 10 | + convention while ZeroMQ dll EXPORT defaults to the standard C calling convention (CDECL). If not changed, a call to |
| 11 | + libzmq.dll from MetaTrader will result in the trading terminal crashing. |
| 12 | +
|
| 13 | + Therefore, this file generates mql4zmq.dll which wraps each call the zmq.h exports when compiled as libzmq.dll (i.e. each function |
| 14 | + that has ZMQ_EXPORT preceeding it) as a STDCALL instead (i.e. __stdcall via WINAPI definition). |
| 15 | +
|
| 16 | + Additionally, MetaTrader4 has limitations on datatypes and data structures that we attempt to resolve by having the wrapping funtion |
| 17 | + inputs being of a type and in a manner that will jive with MQL4. |
| 18 | +
|
| 19 | + NOTE: Remember to add a link to the "libzmq.lib" file that is created upon building of libzmq to the mql4zmq project via: Add => Existing Item => ../Debug/libzmq.lib |
| 20 | + This .lib file exposes all of the exported functions of the libzmq.dll for use with our program as referenced per zmq.h. |
| 21 | + Also add the "mql4zmq.def" file to the linker input via: Properties => Configuration Properties => Linker => Input => Module Definition File, |
| 22 | + and to change the linker settings from "Windows" to "Console" via: Properties => Configuration Properties => Linker => System => Subsystem. |
| 23 | +
|
| 24 | + NAMING NOTE: To avoid naming collisions with the original zmq.h definitions we renamed our exported functions with 'mql4' appended to the beginning of the name. |
| 25 | + In the mql4zmq.mqh we revert the names back to the original to reduce confusion when writing experts. |
| 26 | +
|
| 27 | + libzmq.dll NOTE: After building the solution, copy ../../../lib/libzmq.dll to c:\Windows\SysWOW64\libzmq.dll so that our bindings and other applications can access ZeroMQ. |
| 28 | +
|
| 29 | + =================================== |
| 30 | +*/ |
| 31 | + |
| 32 | +// Include the original libzmq header file. |
| 33 | +#include "../../../include/zmq.h" |
| 34 | + |
| 35 | +// Handle DSO symbol visibility. This is already defined in zmq.h, but we set it here again to protect against future changes to Microsoft Visual C++ detection methods. |
| 36 | +#define ZMQ_EXPORT __declspec(dllexport) |
| 37 | + |
| 38 | +// Setup the standard call specification keyword for the compiler. |
| 39 | +#define WINAPI __stdcall |
| 40 | + |
| 41 | +// Hello World test function. |
| 42 | +ZMQ_EXPORT const char* WINAPI ping (const char* pong) |
| 43 | +{ |
| 44 | + return(pong); |
| 45 | +} |
| 46 | + |
| 47 | +/******************************************************************************/ |
| 48 | +/* 0MQ versioning support. */ |
| 49 | +/******************************************************************************/ |
| 50 | +ZMQ_EXPORT void WINAPI mql4zmq_version (int *major, int *minor, int *patch) |
| 51 | +{ |
| 52 | + zmq_version(major, minor, patch); |
| 53 | +} |
| 54 | + |
| 55 | +/******************************************************************************/ |
| 56 | +/* 0MQ errors. */ |
| 57 | +/******************************************************************************/ |
| 58 | +ZMQ_EXPORT int WINAPI mql4zmq_errno (void) |
| 59 | +{ |
| 60 | + return zmq_errno(); |
| 61 | +} |
| 62 | + |
| 63 | +ZMQ_EXPORT const char* WINAPI mql4zmq_strerror (int errnum) |
| 64 | +{ |
| 65 | + return zmq_strerror(errnum); |
| 66 | +} |
| 67 | + |
| 68 | +/******************************************************************************/ |
| 69 | +/* 0MQ message definition. */ |
| 70 | +/******************************************************************************/ |
| 71 | +ZMQ_EXPORT int WINAPI mql4zmq_msg_init (zmq_msg_t *msg) |
| 72 | +{ |
| 73 | + return zmq_msg_init(msg); |
| 74 | +} |
| 75 | + |
| 76 | +ZMQ_EXPORT int WINAPI mql4zmq_msg_init_size (zmq_msg_t *msg, size_t size) |
| 77 | +{ |
| 78 | + return zmq_msg_init_size(msg, size); |
| 79 | +} |
| 80 | + |
| 81 | +// Used to satisfy zmq_msg_init_data requirement to have a function passed to it that will free the data buffer |
| 82 | +// provided when it is no longer needed. For more info on the 'free' call see: http://www.cplusplus.com/reference/clibrary/cstdlib/free/ |
| 83 | +// |
| 84 | +// NOTICE: We are no longer using this (passing NULL instead) as it was causing windows to close MetaTrader due to |
| 85 | +// thinking it was a virus since we were clearing memory that was originally allocated MetaTrader and not mql4zmq.dll |
| 86 | +void release_buffer(void *data, void *hint) |
| 87 | +{ |
| 88 | + free(data); |
| 89 | +} |
| 90 | + |
| 91 | +ZMQ_EXPORT int WINAPI mql4zmq_msg_init_data (zmq_msg_t *msg, void *data, size_t size) |
| 92 | +{ |
| 93 | + return zmq_msg_init_data(msg, data, size, NULL, NULL); |
| 94 | +} |
| 95 | + |
| 96 | +ZMQ_EXPORT int WINAPI mql4zmq_msg_close (zmq_msg_t *msg) |
| 97 | +{ |
| 98 | + return zmq_msg_close(msg); |
| 99 | +} |
| 100 | + |
| 101 | +ZMQ_EXPORT int WINAPI mql4zmq_msg_move (zmq_msg_t *dest, zmq_msg_t *src) |
| 102 | +{ |
| 103 | + return zmq_msg_move(dest, src); |
| 104 | +} |
| 105 | + |
| 106 | +ZMQ_EXPORT int WINAPI mql4zmq_msg_copy (zmq_msg_t *dest, zmq_msg_t *src) |
| 107 | +{ |
| 108 | + return zmq_msg_copy(dest, src); |
| 109 | +} |
| 110 | + |
| 111 | +ZMQ_EXPORT void* WINAPI mql4zmq_msg_data (zmq_msg_t *msg) |
| 112 | +{ |
| 113 | + return zmq_msg_data(msg); |
| 114 | +} |
| 115 | + |
| 116 | +ZMQ_EXPORT size_t WINAPI mql4zmq_msg_size (zmq_msg_t *msg) |
| 117 | +{ |
| 118 | + return zmq_msg_size(msg); |
| 119 | +} |
| 120 | + |
| 121 | +/******************************************************************************/ |
| 122 | +/* 0MQ infrastructure (a.k.a. context) initialisation & termination. */ |
| 123 | +/******************************************************************************/ |
| 124 | +ZMQ_EXPORT void* WINAPI mql4zmq_init (int io_threads) |
| 125 | +{ |
| 126 | + return zmq_init(io_threads); |
| 127 | +} |
| 128 | + |
| 129 | +ZMQ_EXPORT int WINAPI mql4zmq_term (void *context) |
| 130 | +{ |
| 131 | + return zmq_term(context); |
| 132 | +} |
| 133 | + |
| 134 | +/******************************************************************************/ |
| 135 | +/* 0MQ socket definition. */ |
| 136 | +/******************************************************************************/ |
| 137 | +ZMQ_EXPORT void* WINAPI mql4zmq_socket (void *context, int type) |
| 138 | +{ |
| 139 | + return zmq_socket(context, type); |
| 140 | +} |
| 141 | + |
| 142 | +ZMQ_EXPORT int WINAPI mql4zmq_close (void *s) |
| 143 | +{ |
| 144 | + return zmq_close(s); |
| 145 | +} |
| 146 | + |
| 147 | +ZMQ_EXPORT int WINAPI mql4zmq_setsockopt (void *s, int option, const void *optval, size_t optvallen) |
| 148 | +{ |
| 149 | + return zmq_setsockopt(s, option, optval, optvallen); |
| 150 | +} |
| 151 | + |
| 152 | +ZMQ_EXPORT int WINAPI mql4zmq_getsockopt (void *s, int option, void *optval, size_t *optvallen) |
| 153 | +{ |
| 154 | + return zmq_getsockopt(s, option, optval, optvallen); |
| 155 | +} |
| 156 | + |
| 157 | +ZMQ_EXPORT int WINAPI mql4zmq_bind (void *s, const char *addr) |
| 158 | +{ |
| 159 | + return zmq_bind(s, addr); |
| 160 | +} |
| 161 | + |
| 162 | +ZMQ_EXPORT int WINAPI mql4zmq_connect (void *s, const char *addr) |
| 163 | +{ |
| 164 | + return zmq_connect(s, addr); |
| 165 | +} |
| 166 | + |
| 167 | +ZMQ_EXPORT int WINAPI mql4zmq_send (void *s, zmq_msg_t *msg, int flags) |
| 168 | +{ |
| 169 | + return zmq_send (s, msg, flags); |
| 170 | +} |
| 171 | + |
| 172 | +ZMQ_EXPORT int WINAPI mql4zmq_recv (void *s, zmq_msg_t *msg, int flags) |
| 173 | +{ |
| 174 | + return zmq_recv(s, msg, flags); |
| 175 | +} |
| 176 | + |
| 177 | +/******************************************************************************/ |
| 178 | +/* I/O multiplexing. */ |
| 179 | +/******************************************************************************/ |
| 180 | +ZMQ_EXPORT int WINAPI mql4zmq_poll (zmq_pollitem_t *items, int nitems, long timeout) |
| 181 | +{ |
| 182 | + return zmq_poll(items, nitems, timeout); |
| 183 | +} |
| 184 | + |
| 185 | +/******************************************************************************/ |
| 186 | +/* Built-in devices */ |
| 187 | +/******************************************************************************/ |
| 188 | +ZMQ_EXPORT int WINAPI mql4zmq_device (int device, void * insocket, void* outsocket) |
| 189 | +{ |
| 190 | + return zmq_device(device, insocket, outsocket); |
| 191 | +} |
| 192 | + |
| 193 | +/******************************************************************************/ |
| 194 | +/* A Couple Helper Functions For Building Apps More Quickly. */ |
| 195 | +/* Taken from the Z-Guide file at: https://github.com/imatix/zguide/blob/master/examples/C/zhelpers.h |
| 196 | +/******************************************************************************/ |
| 197 | + |
| 198 | +// Receive 0MQ string from socket and convert into C string |
| 199 | +// Caller must free returned string. Returns NULL if the context |
| 200 | +// is being terminated. |
| 201 | +ZMQ_EXPORT const char* WINAPI mql4s_recv (void* socket, int flags) |
| 202 | +{ |
| 203 | + // Strict "C" spec has to be followed because we outputing the function as 'extern "C"' (see mql4zmq.h). |
| 204 | + // Hence specifing our variables right away instead of inline. |
| 205 | + char* string; |
| 206 | + int size; |
| 207 | + |
| 208 | + // Initialize message. |
| 209 | + zmq_msg_t message; |
| 210 | + zmq_msg_init(&message); |
| 211 | + |
| 212 | + // Receive the inbound message. |
| 213 | + if (zmq_recv (socket, &message, flags)) |
| 214 | + return (NULL); // No message received |
| 215 | + |
| 216 | + // Retrive message size. |
| 217 | + size = zmq_msg_size(&message); |
| 218 | + |
| 219 | + // Initialize variable to hold the message. |
| 220 | + string = malloc (size + 1); |
| 221 | + |
| 222 | + // Retrive pointer to message data and store message in variable 'string' |
| 223 | + memcpy (string, zmq_msg_data (&message), size); |
| 224 | + |
| 225 | + // Deallocate message buffer. |
| 226 | + zmq_msg_close (&message); |
| 227 | + |
| 228 | + // Return the message. |
| 229 | + string [size] = 0; |
| 230 | + return (string); |
| 231 | +} |
| 232 | + |
| 233 | +// Convert C string to 0MQ string and send to socket |
| 234 | +ZMQ_EXPORT int WINAPI mql4s_send (void *socket, char *text) |
| 235 | +{ |
| 236 | + // Strict "C" spec has to be followed because we outputing the function as 'extern "C"' (see mql4zmq.h). |
| 237 | + // Hence specifing our variables right away instead of inline. |
| 238 | + int result; |
| 239 | + |
| 240 | + // Initialize message. |
| 241 | + zmq_msg_t message; |
| 242 | + |
| 243 | + // Set the message to have a spcified length. |
| 244 | + zmq_msg_init_size (&message, strlen (text)); |
| 245 | + |
| 246 | + // Place the specified value of variable 'string' inside of the message buffer. |
| 247 | + memcpy (zmq_msg_data (&message), text, strlen (text)); |
| 248 | + |
| 249 | + // Stream the message to the specified socket. |
| 250 | + result = zmq_send (socket, &message, 0); |
| 251 | + |
| 252 | + // Deallocate the message. |
| 253 | + zmq_msg_close (&message); |
| 254 | + |
| 255 | + // Return the response of the zmq_send call. 0 is success, -1 is error. |
| 256 | + return (result); |
| 257 | +} |
| 258 | + |
| 259 | +// Sends string as 0MQ string, as multipart non-terminal |
| 260 | +ZMQ_EXPORT int WINAPI mql4s_sendmore (void *socket, char *text) |
| 261 | +{ |
| 262 | + // Strict "C" spec has to be followed because we outputing the function as 'extern "C"' (see mql4zmq.h). |
| 263 | + // Hence specifing our variables right away instead of inline. |
| 264 | + int result; |
| 265 | + |
| 266 | + // Initialize message. |
| 267 | + zmq_msg_t message; |
| 268 | + |
| 269 | + // Set the message to have a spcified length. |
| 270 | + zmq_msg_init_size (&message, strlen (text)); |
| 271 | + |
| 272 | + // Place the specified value of variable 'string' inside of the message buffer. |
| 273 | + memcpy (zmq_msg_data (&message), text, strlen (text)); |
| 274 | + |
| 275 | + // Stream the message to the specified socket. |
| 276 | + result = zmq_send (socket, &message, ZMQ_SNDMORE); |
| 277 | + |
| 278 | + // Deallocate the message. |
| 279 | + zmq_msg_close (&message); |
| 280 | + |
| 281 | + // Return the response of the zmq_send call. 0 is success, -1 is error. |
| 282 | + return (result); |
| 283 | +} |
0 commit comments