[...] Now how do I send my pointer to string since I can't obviously import SendMessageA under different internal names?
My WinFile.mqh library (https://www.mql5.com/en/forum/118999) uses a well-known workaround for this for this sort of thing. See the last section of the overview notes in the code. There are limits to how far you can go with this; there comes a point where there's no alternative to using a custom DLL as a bridge between MQ4 and the Windows API.
Problem changed a bit since 20 minutes ago.
I can import SendMessage and use it for numeric messages, and use the string version with SendMessageA.
However, it sends quite nothing. The array pointed seems to contain nothing (output is a series of null).
#import "user32.dll" int RegisterWindowMessageA(string s); int SendMessage(int hWnd,int Msg,int wParam,int lParam); int SendMessageA(int hWnd,int Msg,int wParam,string lParam); #import .... string b=" "; b=AccountCompany(); Print(b); Print("111=",SendMessageA(SERVERHANDLE,WM_USER+SPECACCOUNTBROKERMSG,0,b));
target application:
type CharArray=array[0..255] of byte; type PChar=^CharArray; .... if (amessage=WM_USER+SPECACCOUNTBROKERMSG) then begin s:=PChar(lparam); assign(f,'c:\test.txt'); rewrite(f); writeln(f,'Rough:'); for i:=0 to 5 do write(f,chr(s^[i])); close(f); WindowProc:=111; exit; end;
Problem changed a bit since 20 minutes ago.
[...] target application:
You can't use SendMessage() to give one process the address of some memory within another process. If you could do this, then it would destroy process security, and also some aspects of process stability.
Your simplest alternative mechanism is going to be something like writing to a pre-agreed file on disk, and then sending a message which means "read the new contents from the file".
Yeah normally the target app should have blown up with a 216 "General Protection Fault" like in the old good times that it belongs to after all...
It's a good idea. These days I struggled to use GlobalAlloc like in the old times, but the dll that was supposed to work with the main program (dll done in Dev-Pascal too) was unable to get a lock. GlobalLock failed all the time, no matter what flag combination I used. That brought me to message communication..
Ok, will do the file version. Thx!
These days I struggled to use GlobalAlloc like in the old times [...]
That's quite some "old times". I don't think GlobalAlloc() has been usable in this way since Windows 3.x.
Ok, will do the file version. Thx!
One extra option, if you're dealing with multiple instances of MT4, is to have a pre-agreed directory but allocate an integer ID for each message which gets sent (e.g. just a random number). The filename for the message then includes the ID. And you send the ID as the lparam so that the receiving process knows which file to look at (and then deletes it when finished reading).
The target app will work with more EAs. But one of the messages will return a busy status, and if I think better, I should also use an EA magic. When an EA locks in the server will answer "busy" to all the others. The EA magic will be an addon, to also know which EA is allowed to work with at a given time.
About the GlobalAlloc issue, it's very daunting. The server allocated memory with GHND (GMEM_MOVEABLE || GMEM_ZEROINIT) or with GMEM_MOVEABLE alone, could lock in, and write in the pointer. From any other place I tried to lock with GlobalLock, even if it was locked or not from the server, always got a GlobalLock fail ( 0 ), with a GetLastError of 6, invalid handler. Normally invalid handler should happen only after a GlobalFree... But I didn't understand why for two days and dumped it...
The target app will work with more EAs. But one of the messages will return a busy status, and if I think better, I should also use an EA magic. When an EA locks in the server will answer "busy" to all the others. The EA magic will be an addon, to also know which EA is allowed to work with at a given time.
You've obviously also got the 32 bits of wparam to play with. Basically, you can pass up to 64 bits of information (wparam + lparam) without life becoming complicated.
Another alternative would be to talk to the server application using HTTP. That gives you the potential to scale the whole thing out across multiple computers. There's been some recent discussion of this, from a different perspective, in https://www.mql5.com/en/forum/124014.
About the GlobalAlloc issue, it's very daunting. The server allocated memory with GHND (GMEM_MOVEABLE || GMEM_ZEROINIT) or with GMEM_MOVEABLE alone, could lock in, and write in the pointer. From any other place I tried to lock with GlobalLock, even if it was locked or not from the server, always got a GlobalLock fail ( 0 ), with a GetLastError of 6, invalid handler. Normally invalid handler should happen only after a GlobalFree... But I didn't understand why for two days and dumped it...
I would have guessed I was the only person on this forum who'd ever used GlobalAlloc() in this way. It hasn't worked since the days of 16-bit processes and shared address spaces. See http://msdn.microsoft.com/en-us/library/aa366596(VS.85).aspx
Isn't wparam a word (16 bits) ? Thus making 16+32 = 48 bits ?
The server has to work on one computer, so no need to complicate even more...
This are the applications (original versions, Dev-Pas ):
server:
Program OrderCopyMain; uses Crt; const GMEM_FIXED =$0000; GMEM_MOVEABLE =$0002; GMEM_NOCOMPACT =$0010; //obsolete GMEM_NODISCARD =$0020; //obsolete GMEM_ZEROINIT =$0040; GMEM_MODIFY =$0080; GMEM_DISCARDABLE =$0100; //obsolete GMEM_NOT_BANKED =$1000; //obsolete GMEM_SHARE =$2000; //obsolete GMEM_DDESHARE =$2000; //obsolete GMEM_NOTIFY =$4000; //obsolete GMEM_LOWER =GMEM_NOT_BANKED; //obsolete GMEM_DISCARDED =$4000; GMEM_LOCKCOUNT =$00ff; GMEM_INVALID_HANDLE =$8000; GHND =$0042;//GMEM_MOVEABLE or GMEM_ZEROINIT; GPTR =$0040;//GMEM_FIXED or GMEM_ZEROINIT; type RecordCollectionStruct=record Available:boolean; LastUpdate:longint; Data:string; end; type CharArray=array[0..255] of byte; type hglobal=longint; type PCollection=^RecordCollectionStruct; var Collection:PCollection; var hmem,hfree:hglobal; var dereferred:boolean; function GetTickCount:dword;external 'KERNEL32.DLL'; function GlobalAlloc(uFlags:longint;dwBytes:dword):hglobal; external 'KERNEL32.DLL'; function GlobalFree(ghmem:hglobal):hglobal; external 'KERNEL32.DLL'; function GlobalLock(hmem:hglobal):pointer; external 'KERNEL32.DLL'; function GlobalUnlock(hmem:hglobal):boolean; external 'KERNEL32.DLL'; function GetLastError:dword; external 'KERNEL32.DLL'; begin Collection:=nil; ClrScr; WriteLn('Allocating memory...'); hmem:=GlobalAlloc(GHND + GMEM_MODIFY,sizeof(RecordCollectionStruct)); if (hmem<>0) then begin WriteLn('My handler : ',hmem,' -> THIS IS EA PARAMETER!'); end else begin WriteLn('GlobalAlloc() failed.'); WriteLn('Error code : ',GetLastError); WriteLn('See ya next time!'); Readkey; halt; end; WriteLn('Locking memory...'); Collection:=GlobalLock(hmem); if (Collection=nil) then begin WriteLn('GlobalLock() failed.'); WriteLn('Error code : ',GetLastError); WriteLn('Unallocating memory...'); hfree:=GlobalFree(hmem); if (hfree<>0) then begin WriteLn('F$%!.. couldn`t free memory.'); WriteLn('Error code = ',GetLastError); WriteLn('Anyway...screw it...'); end; Readkey; halt; end; WriteLn('Locked pointer ',dword(Collection) ); Collection^.Available:=false; Collection^.LastUpdate=GetTickCount; Collection^.Data='xxx'; Collection^.Available:=true; WriteLn('You can use it now ... or later (it is locked now)'); readkey; WriteLn('Unlocking memory...'); dereferred:=GlobalUnlock(hmem); if (dereferred=false) then begin WriteLn('GlobalUnlock() failed.'); WriteLn('Error code = ',GetLastError() ); end; WriteLn('waiting for you to use... (it's not locked now)'); readkey; WriteLn('Unallocating memory...'); hfree:=GlobalFree(hmem); if (hfree<>0) then begin WriteLn('F$%!.. couldn`t free memory.'); WriteLn('Error code = ',GetLastError); Readkey; end; end.
and the tester
program test; const GMEM_FIXED =$0000; GMEM_MOVEABLE =$0002; GMEM_NOCOMPACT =$0010; GMEM_NODISCARD =$0020; GMEM_ZEROINIT =$0040; GMEM_MODIFY =$0080; GMEM_DISCARDABLE =$0100; GMEM_NOT_BANKED =$1000; GMEM_SHARE =$2000; GMEM_DDESHARE =$2000; GMEM_NOTIFY =$4000; GMEM_LOWER =GMEM_NOT_BANKED; GMEM_DISCARDED =$4000; GMEM_LOCKCOUNT =$00ff; GMEM_INVALID_HANDLE =$8000; GHND = GMEM_MOVEABLE or GMEM_ZEROINIT; GPTR = GMEM_FIXED or GMEM_ZEROINIT; type RecordCollectionStruct=record Available:boolean; LastUpdate:dword; Data:string; end; type CharArray=array[0..255] of byte; type hglobal=longint;casttype=array[0..3] of byte; type PCollection=^RecordCollectionStruct; function GetTickCount:dword;external 'KERNEL32.DLL'; function GlobalAlloc(uFlags:longint;dwBytes:dword):hglobal; external 'KERNEL32.DLL'; function GlobalFree(ghmem:hglobal):hglobal; external 'KERNEL32.DLL'; function GetLastError:dword; external 'KERNEL32.DLL'; function GlobalLock(hmem:hglobal):pointer; external 'KERNEL32.DLL'; function GlobalUnlock(hmem:hglobal):boolean; external 'KERNEL32.DLL'; var col:pcollection;hmem:hglobal; var addr:dword; var m:integer; var cast:casttype; begin WriteLn('Give method : '); ReadLn(m); if m=1 then begin WriteLn('Give memory handler : '); Readln(hmem); cast:=casttype(hmem); WriteLn(cast[0],' ',cast[1],' ',cast[2],' ',cast[3]); WriteLn('Attempting with hmem= ',hmem); col:=GlobalLock(hmem); if col=nil then begin WriteLn('Error= ',GetLastError); Readln; halt; end; WriteLn(col^.LastUpdate); WriteLn(col^.AccountsNo); //col^.Available:=False; //col^.LastUpdate:=GetTickCount; //col^.Available:=True; WriteLn(GlobalUnlock(hmem)); ReadLn; end else begin WriteLn('Give pointer : '); Readln(addr); WriteLn('Attempting with hmem= ',addr); col:=PCollection(addr); WriteLn(col^.LastUpdate); WriteLn(col^.AccountsNo); //col^.Available:=False; //col^.LastUpdate:=GetTickCount; //col^.Available:=True; Readln; end; end.
Whatever you do, it fails. First method gently. Second one bad. Second one fails even if you attempt GPTR or GMEM_FIXED.
Couldn't find anything to explain this.
Isn't wparam a word (16 bits) ?
Not since 1995. WPARAM is defined as UINT_PTR; UINT_PTR is a __int3264; and __int3264 depends on whether you're running a 64-bit version of Windows. See, for example, http://blogs.msdn.com/oldnewthing/archive/2003/11/25/55850.aspx
![MQL5 - Language of trade strategies built-in the MetaTrader 5 client terminal](https://c.mql5.com/i/registerlandings/logo-2.png)
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
I need to use SendMessage with a whole array of messages; some of them have the normal use of lparam ; but in other cases I want lparam to be a pointer to a string that has to be sent to target window.
That means that sometimes I need
and other times I need
Now how do I send my pointer to string since I can't obviously import SendMessageA under different internal names?