Q: Problem passing array (int) to system DLL

 

Hello

Have this problem in MT5/MQL5 (64bit on W10 64bit) only (note: the same code works in MT4/MQL4 (32bit on W10 64bit)):

I need to pass an array of handles to kernel32::WaitForMultipleObjects; the function is defined here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms687025(v=vs.85).aspx

I import (declare) the Function like so in MQL4/5:

uint WaitForMultipleObjects(uint, uint&[], uint, uint);

The array looks just like so:

uint handles[num];

The call looks like so:

uint dwResult = WaitForMultipleObjects(num, handles, 0, 0);

When run in MT4 all works well; however, when run in MT5, I get the system error code 6 (ERROR_INVALID_HANDLE).

The produced handles to the respective event objects are correct (no errors) and work with kernel32::WaitForSingleObject in MT5 - which demands only one handle instead of an array of handles.. Why does it fail to pass the array in MT5?

WaitForMultipleObjects function (Windows)
  • msdn.microsoft.com
Waits until one or all of the specified objects are in the signaled state or the time-out interval elapses. Syntax Parameters nCount [in] The number of object handles in the array pointed to by lpHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS. This parameter cannot be zero. lpHandles [in] An array of object handles. For a...
 

Forum on trading, automated trading systems and testing trading strategies

Converting MSDN C++ functions to MQL4 functions! WINAPI, User32.dll...

JC, 2017.07.28 15:25

Yes, but the handle length varies for 64-bit applications versus 32-bit applications (and thus for 64-bit MQL5 versus 32-bit MQL5, or MQL4). In many cases, you can get away with passing 4-byte values to a 64-bit O/S but, in 64-bit Windows, things like window handles, sockets etc are defined as 8 bytes. Therefore, to be properly compliant with the Windows API, and fully future-proofed, you need to do things like the following:

#import "user32.dll"
   int ShowWindow(int, int); // For 32-bit
   int ShowWindow(long, int); // For 64-bit
#import

...

if (TerminalInfoInteger(TERMINAL_X64)) {
   long handle = ChartGetInteger(0, CHART_WINDOW_HANDLE);
   ShowWindow(handle, 1); // Force MQL to use the 64-bit import by specifying long parameter
} else {
   int handle = (int)ChartGetInteger(0, CHART_WINDOW_HANDLE);
   ShowWindow(handle, 1); // Force MQL to use the 32-bit import by specifying int parameter
}

Failure to do this sort of thing may work now - will probably work now in most cases, except where Windows expects or returns a raw memory pointer rather than a managed handle - but could theoretically stop working in any future Windows update from today onwards.

Going back to my earlier socket example, socket handles are, in effect, always only 4 bytes even on x64 (and very likely to remain so), and therefore you can get away with using an int import in MQL because the value will get converted from 4 bytes to 8 bytes by the all the code between you and the Windows API. However, something like the hostent structure has different sizes on x86 and x64, because all the pointers within it become 8 bytes long on x64.

 
Alain Verleyen:

Thank you, Alain. I will try around with long type.

 
F0RC3:

Thank you, Alain. I will try around with long type.

Please give us some feedback.

 
Alain Verleyen:

Please give us some feedback.

It works now - so, variables of the windows type HANDLE have to be ulong in MT5 (64bit).

Thanks again.