Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Interprocess communication using Mailslots


  • Please log in to reply
13 replies to this topic
ebpdoug
  • Members
  • 24 posts
  • Last active: Oct 19 2013 09:50 PM
  • Joined: 28 Oct 2009
The following moved here from original thread 2010-07-19. A little cleanup of the scripts has been done.

It is quite easy to use mailslots by means of calls to functions in kernel32.dll. For interprocess com's they have the avantage over ad-hoc methods, like using a conventional file, that messages are first-in, first-out, so there is no need for contortions to prevent overwriting unread messages, etc. Note the caveat in the MSDN docs for mailslots that messages are sent as datagrams and hence can be lost without notification. Two-way communication requires that each end act a both a server and a client (each end with a separate mailslot).

I've tried using AHK fileappend to send to a mailslot, but I can't get it to work. Interestingly I have been able to use command line
copy (name of small file) \\.\mailslot\TestSlot1

The client can be on the same computer as the server, or on a different one. Mailslots can be used in any conventional or scripting language that allows use of Windows functions , so they are applicable to AHK to AHK or to C/C++, C#, VB.net, etc. A very simple VBScript mailslot client follows the AHK scripts.

When the mailslot server and client are on the same computer, messages can be very long. If the server and client are on different computers, the maximum message length is about 420 characters (MSDN docs inconsistent). If a message is too long, it is lost completely.

A mailslot client can broadcast as messsage to all computers in a domain simply by using * for the computer name. There is no problem with computers that don't have a server for the mailslot running - it appears that the message simply goes into the bit bucket for those computers.

Here are simple scripts for a mailslot server (actually the receiver of messages) and a client.

I'm not generally a big fan of using one line per DLLcall parameter, but it does make adding comments easier. If you haven't used DLLcall before, read all of the AHK Help for DLLcall carefully to learn how to match AHK types like UInt, UIntP, str, etc to parameters specified for Windows function calls.

SERVER script:
;Mailslot Server (server is actually the RECIPIENT of mail messages; client sends them)

;MSDN says Windows functions used all Windows 2K or higher (DLLs in kernel32)
;Tested only under XP Pro with SP3

;This script has no hotkeys or user interface, so it must be closed using Exit in
;menu from right click of its notification area icon
;A proper implementation should use CloseHandle before exiting or when done with the mailslot

/*
USEFUL LINKS:
http://msdn.microsoft.com/en-us/library/aa365147(v=VS.85).aspx	CreateMailslot Function
http://msdn.microsoft.com/en-us/library/aa365467(v=VS.85).aspx	ReadFile Function
http://msdn.microsoft.com/en-us/library/ms681381(v=VS.85).aspx	System Error Codes
http://msdn.microsoft.com/en-us/library/aa365785(v=VS.85).aspx	Using mailslots (example in C/C++)
*/

#NoEnv
;"adding the line #NoEnv anywhere in the script improves DllCall's
; performance when unquoted parameter types are used (e.g. int vs. "int")."

;mailslot name MUST begin with "\\.\mailslot\", since it is created on local machine
;Name can include "pseudopath" e.g. \\.\mailslot\MainPostOffice\FredsBoxes\Box123

SlotName = \\.\mailslot\TestSlot1

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~CREATE MAILSLOT
SlotHandle := DLLCall("CreateMailslot"  ;return is handle (integer) to the mailslot
	,str, SlotName	
	,UInt, 0	;using zero allows max message size
	,UInt, 0	;0 return immediately if no message; otherwise ms to wait, -1 for wait forever
	,UInt, 0)	;security attributes

if errorlevel ;this is an error reported by AHK in attempting the call
{
	MsgBox An error occured in the AHK call to CreatMailslot.`nExiting.
	exitapp
}
else
{
	if (a_lasterror <> 0) ;error reported by the CreateMailslot function itself (not AHK)
	{
		clipboard = http://msdn.microsoft.com/en-us/library/ms681381(v=VS.85).aspx	
		MsgBox CreateMailSlot function returned an error.`nSystem Error Code: %a_lasterror%`n`nLink to error codes is on clipboard.`n`nExiting
		exitapp
	}
	else
		MsgBox Mailslot created with handle %SlotHandle%
}
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

;Mailslot is now ready to receive incoming mail from client application
;Reading from the mailslot is done using Windows ReadFile function

;Note that the mailslot was created with zero for wait time, so an attempted read will return immediately
;even if the mailslot is empty.
;Windows function GetMailslotInfo can be use to check, in advance of reading, how many messages are in
;the slot and how large the next message is

;MSDN doc's are inconsistent with regard to size limit for messages sent between computers on a network.
;One place says 400 for broadcast, another says 424 for messages between computers.
;This server and companion client will work for up to 420 under Windows XP.
;Messages sent from one process to another on the same computer can be much longer, with the limit set
;Max Msg Size at slot creation

VarSetCapacity(ReadBuffer, 512, 0)

loop ;a very simple loop to check the mailslot periodically
{
	BytesRead := MailslotRead(SlotHandle)
	If (BytesRead > 0)
		msgbox A message was found in the mailslot:`n`n%ReadBuffer%
	sleep, 300
}


MailslotRead(SlotHandle) ;reads one message at a time
{
	global ReadBuffer  ;could/should be passed as ByRef parameter

	BytesToRead := 500
	
	DLLCall("ReadFile"
		,UInt, slotHandle	;the handle from CreateMailSlot
		,str , readBuffer	;see AHK DLLCall Help for why str used here
		,UInt, BytesToRead	
		,UIntP, BytesActuallyRead
		,UInt, 0)	;pointer to Overlapped structure, not used, so null
	
	if errorlevel
		Msgbox Error in ReadFile operation`nErrorLevel: %errorlevel%
	else
		return BytesActuallyRead
}
CLIENT script:
;Mailslot Client - the client for a mailslot is the process that SENDS to a mailslot that has been created
;by a mailslot server process
;Error checking pretty minimal - see Mailslot server script for better checking & more details of 
;Windows error messages

;Sending to a mailslot is essentially the same as writing to a file

;SlotName, below, must exactly match the mailslot name created by the server EXCEPT
;if the client is running on a different computer the dot must be replaced by the name
;of the SERVER script's computer e.g. \\LabComputer1\mailslot\TestSlot1
;A 'star' * can be used in place of computer name to broadcast to all computers on domain.

SlotName = \\.\mailslot\TestSlot1

mailslotHandle := DllCall("CreateFile"
	,Str , SlotName		;of form \\HostName\pipe\PipeName
	,UInt, 0x40000000	;Generic_Write access
	,UInt, 3		;0 = no sharing; 3 = read & write sharing
	,UInt, 0		;Security Attributes (a pointer; 0 here actually means NULL)
	,UInt, 3		;Creation Disposition (3 = OPEN_EXISTING)
	,UInt, 0		;Flags And Attributes
	,UInt, 0)		;Template File (no template used; 0 means NULL; ignored for existing file, in any case)

if errorlevel
	MsgBox An error occured in AHK call to DLL CreateFile
else
	If (a_lasterror <> 0) ;error from DLL itself - see Server script for more info on errors
	{
		MsgBox	Last error: %a_lasterror%
		exitapp
	}


;This script just sends a couple of messages, then exits

message = This is a test messasge sent to a mailslot. The last character is a star. *
SendToMailslot(mailslothandle, message)

message =
(
This is
a multiline
message
that was sent
without waiting
for the first one
to be read.
)
SendToMailslot(mailslothandle, message)

return

SendToMailslot(slotHandle, StringToWrite)
{
	DllCall("WriteFile"
	, uint, slotHandle
	, str, StringToWrite
	, uint, StrLen(StringToWrite)+1  ;+1 so terminating NULL is included
	, uintp,0, uint,0)

	If errorlevel
    		MsgBox WriteFile failed.`nError level: %ErrorLevel%`nLast error: %A_LastError%
}

A very simple client in VBScript
A script of this sort makes it extremely simple to communicate from VBScript to an AutoHotkey script.
'An very simple Mailslot client with VBScript
'No error checking
'Just demonstrates sending a single line

Set FSO = CreateObject("Scripting.FileSystemObject")

FileName = "\\.\mailslot\TestSlot1"
set SlotFile = fso.CreateTextFile(FileName)

'use Write, not Writeline
'Null-terminate strings, if that is what mailslot server "expects"

SlotFile.Write("A message from VBScript" & chr(0))

SlotFile.Close
WScript.Quit

Named pipes can be handled with functions of the "same general shape", though they can be more complicated due to their "confirmed delivery" nature (calls to DLLs can be blocking). The do no have the message length limitation of mailslots.

little Fairy
  • Guests
  • Last active:
  • Joined: --

Two AHK scripts demonstate a simple mailslot server and a simple client.

A very simple script demonstates how to send mailslot messages from VBScript to the AHK server.

so, post the scripts!

  • Guests
  • Last active:
  • Joined: --

so, post the scripts!

Check the link he posted. :p

little Fairy
  • Guests
  • Last active:
  • Joined: --

so, post the scripts!

Check the link he posted. :p

i see.
still would be better to have the scripts in the top-post of the thread.

Joy2DWorld
  • Members
  • 562 posts
  • Last active: Jun 30 2014 07:48 PM
  • Joined: 04 Dec 2006
hey, is very cool idea!

very clear explanation & code. Fantastic contribution.
Joyce Jamce

  • Guests
  • Last active:
  • Joined: --
thanks ebpdoug for posting this! :)

Something to remember when a communication is needed between ahk scripts or user.

sumon
  • Moderators
  • 1317 posts
  • Last active: Dec 05 2016 10:14 PM
  • Joined: 18 May 2010
What implications can this have? Can you have spider-scripts that work on several computers? Have a variable entered in one place and show up elsewhere? Remote control?

Script in OP would be nice too ofc :)

OceanMachine
  • Members
  • 790 posts
  • Last active: Aug 23 2013 02:10 PM
  • Joined: 15 Oct 2007
Just so people are aware of an alternative (not to detract from the Mailshot solution, because both of these solutions have their place, depending on what you want to do), but there is also a Sockets based method of allowing several machines with different scripts on them to send messages between each other:

Client & Server Script for TCP/IP Network Communication

[Edit]IPC module[/url] which I didn't see before]

Z_Gecko
  • Guests
  • Last active:
  • Joined: --
Very interesting, i didnĀ“t even know, such a thing existed.

I wonder: do i need to to have the "Messenger service"-service running on my system to use it? (I tend to deactivate this service to avoid the useless Messages my colleagues send from time to time via net send).

And +1 for that

i see.
still would be better to have the scripts in the top-post of the thread.




btw: @OceanMachine, there is a nice wrapper for Socket-communication from The Good:
http://www.autohotke...topic58183.html

OceanMachine
  • Members
  • 790 posts
  • Last active: Aug 23 2013 02:10 PM
  • Joined: 15 Oct 2007
Hi Zed, Thanks, I'll check that out. I believe the Messenger service is an implementation of a Mailslot, but is only one implementation/usage of it, so it shouldn't be required that the service be enabled. It's just a specific named mailslot - see here. I think if you write to MAILSLOT\Messngr, then that is the same as using NET SEND, and the Messenger service on the destination machine just monitors that named mailslot, but you can of course make your own named mailslot. If anyone else is interested, there are some more links to info about mailslots here and here and here.

The most widely known implementation of the MailSlot is the Messenger service that exists in Windows NT-line of products, including Windows XP. The Messenger service is essentially a MailSlot server that waits for a message to arrive. When a message arrives it is displayed in a popup onscreen. The NET SEND command is therefore a type of MailSlot client, because it writes to specified mailslots on a network.

A number of programs also use MailSlots to communicate. Generally these are amateur chat clients and other such programs. Commercial programs usually prefer pipes or sockets. Other MailSlots include:

* MAILSLOT\Messngr - Microsoft NET SEND Protocol
* MAILSLOT\Browse - Microsoft Browser Protocol
* MAILSLOT\Alerter
* MAILSLOT\53cb31a0\UnimodemNotifyTSP
* MAILSLOT\HydraLsServer - Microsoft Terminal Services Licensing
* MAILSLOT\CheyenneDS - CA BrightStor Discovery Service



By the way - nice job ebpdoug, Mailslots can be very useful, and we now have another part of the windows API wrapped nicely for AHK :)

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Very nice. Thx.
Posted Image

ebpdoug
  • Members
  • 24 posts
  • Last active: Oct 19 2013 09:50 PM
  • Joined: 28 Oct 2009
Thanks, all, for the comments.

In no particular order, in reply (words in bold to help people find responses):

1. Scripts have been moved to this thread 2010-07-19

2. I fully agree that TCP with sockets is much better suited for some applications. TCP is more reliable than the UDP used for mailslots. The Good's post on TCP is excellent! One of the nice things about TCP is the WSAAsyncSelect function, which uses Windows messages for notification of events. OnMessage is the closest thing to interrupt service routines that AHK offers, and it eliminates the need for polling.
The MSDN documentation for TCP has a frighteningly long list of functions, but as The Good and others have shown, you can do really useful stuff with a small subset.

So far, a mailslot is the only across-a-network interprocess communication method, other than temporary files, that I can find that will work with VBScript as a client (alas, not as a server). VBScript can deal with COM objects that spit out async events, so it has its merits as an intermediary.

3. As far as Messenger Service goes, I've seen nothing to lead me to believe it is necessary for mailslot operation. I think I have messenger service turned off on my computers, but I'm never really sure that Microsoft stuff isn't hiding out somewhere.

4. I have to do some more testing (set up client-server-client "loop-back" through a second computer) to be able to fully test timing. What I've found so far is that the client script can finish the WriteFile operations for a couple of messages of total length of about 500 characters in about 30 microseconds with client and server on the same computer, and about 300 microseconds (typical, occasionally takes a millisecond or more) from one computer to another (both computers of only moderate speed, on gigabit network, both connected to an unmanaged switch, with DNS server on router connected to switch). What I don't know is when the messages are actually available for reading at the receiving end relative to the time at which the client finishes writing - it may be "immediately".

5. Sorry, I don't know what a "spider script" is, but yes, mailslots would be quite suitable for remote control. I started down the interprocess communications path to learn about methods suitable for comm's with some remote hardware I intend to design. Although it makes more sense to me to do complex stuff in VB or C# or C, I really like AHK, especially for "instant GUIs".

6. Don't overlook PSEXEC from SysInternals/Microsoft as a convenient, if not lightning fast, way of executing something on a remote computer on your network. It is easy to use with Run from AHK - e.g.
runwait, psexec \\asus2 ahcmd sendplc %operation%,, hide
calls ahcmd.exe on computer named asus2, passing sendplc %operation% to ahcmd
It does not rely on any sort of client-server relationship. If you have trouble using it to start an AHK script remotely, try using a compiled script that is in a folder in your path.
Lots of other good stuff in the SysInternals suite, including things helpful in debugging AHK scripts (finding open handles, for example).

~~~~~
There are vast numbers of useful things you can do with AHK using DLLCall. The trick for noobs like me is to even find out the functions exist. It wouldn't surprise me if there were a Windows function to send your great aunt a birthday card. Most of the documentation assumes you are writing in C/C++, so it takes a while to become familiar with how to set up structures, pointers, etc. in AHK, but it is definitely worth it.

Doug

ebpdoug
  • Members
  • 24 posts
  • Last active: Oct 19 2013 09:50 PM
  • Joined: 28 Oct 2009
I finally got around to doing some timing tests.
Configuration:
2 computers running XP Pro SP3, connected to unmanaged switch on gigabit Ethernet.
One computer running an "echo" script - receiving mailslot messages in one slot ("tight" polling of receive) and sending them back out to another slot.
Second computer sends a message to echoing computer's "in" slot and receives the echo in another mailslot, again using tight polling loop for receive; timing with PerformanceCounter
Message length about 100 characters.
Both originating/time script and echoing script running at normal priority.
No other traffic on the network, except about once per second "something" to all computers from router connected to switch.

Typical results of 100 to 1000 iterations:
About 60% of messages traveled the loop in 300 to 600 microseconds
About 10% in 6 to 10 milliseconds
About 10% in 16-20 milliseconds
About 20% in 20 to 25 milliseconds; on some runs, occasional times up to about 30 milliseconds

Ferry
  • Members
  • 37 posts
  • Last active: Mar 21 2014 10:12 AM
  • Joined: 18 May 2008

This will only work correctly when using the ANSI version of Autohotkey. When using the Unicode version only the first part of the message is shown. I tried converting this to Unicode but it did not work. Has anyone tried to convert this script to Unicode?