Per poter fare Inter-Process Communication tra processi Win32, storicamente, sono disponibili i seguenti strumenti:

  • Clipboard
  • COM
  • Data Copy
  • DDE
  • File Mapping
  • Mailslots
  • Pipes
  • RPC
  • Windows Sockets

Ognuno di essi ha dei pro, dei contro e delle applicazioni specifiche:

Clipboard

Probabilmente si tratta del meccanismo meno idoneo per scambiare dati tra processi. La clipboard è condivisa da tutta la sessione Windows corrente e soprattutto l'utente ne ha accesso trasparente quando fa copia ed incolla da un semplice textbox, per esempio.

Inoltre manca la possibilità di specificare criteri di sicurezza associati al canale e/o ai dati trasferiti.

COM

OLE (basato su COM) supporta i "compound documents", dove è possibile edittare parti di documenti provenienti e associati ad applicazioni (processi) Win32 differenti.

DCOM

DCOM permette di avere client e server distribuiti su processi Win32/64 diversi, ed anche su macchine diverse.

Il vantaggio (trasparente) del Marshalling di parametri tra processi diversi rispetto al COM tradizionale permette di oltrepassare i "limiti" del processo corrente.

Inoltre, il sofisticato modello di sicurezza implementato permette che solamente parti autorizzate possano connettersi ad un server DCOM.

Data Copy

Si tratta di un sistema di comunicazione basato sul messaggio Windows "WM_COPYDATA".

Il problema principale con questo sistema è la sicurezza: non è possibile (in modo semplice) determinare l'identità di chi sta tendando di inviare messaggi ad un recipient WM_COPYDATA.

Un mio articolo (in inglese) su una classe che implementa questo meccanismo di IPC è reperibile qui:

https://www.vitoplantamura.com/wmcopydata

DDE

DDE è di solito utilizzato per supportare vecchie applicazioni legacy che possono farne uso.

In soluzioni di nuova implementazione si preferisce usare uno degli altri meccanismi di IPC disponibili.

Mailslots

Nella mia esperienza di sviluppatore, ho avuto (veramente) poco a che fare con le Mailslot.

Solitamente vengono utilizzate per fare "broadcast" di piccoli messaggi tra computer nel contesto di un dominio di rete.

Pipes

Tra gli strumenti ed il software Microsoft (per Windows NT e superiori), le Named Pipe sono il secondo meccanismo di elezione per realizzare infrastrutture di Interprocess Communication tra processi Win32/64 (dopo i File Mapping, come detto sopra).

Una mia classe (e relativo articoletto in inglese) che utilizza le Named Pipe per fare Interprocess Communication è presente negli Archivi del mio sito qui:

https://www.vitoplantamura.com/namedpipes

RPC

RPC permette di chiamare funzioni remote, in maniera estremamente performante (in un altro processo sullo stesso computer o anche in un'altra macchina nella rete locale)

Per queste caratteristiche di velocità, l'RPC è utilizzato estensivamente a livello di sistema su piattaforma Windows NT e superiori.

Windows Sockets

I Windows Sockets sono lo strumento di elezione per l'IPC tra computer in una stessa rete (LAN, WAN o Internet), ma raramente sono utilizzati come meccanismo unico di comunicazione tra 2 o più processi sulla stessa macchina.

File Mapping, e la classe C++ qui presentata:

Il File Mapping è uno dei meccanismi più utilizzati per scambiare dati tra processi sulla stessa macchina, e, sicuramente, uno dei preferiti nelle stesse applicazioni sviluppate da Microsoft.

In sostanza, il File Mapping permette di trattare un file come se fosse una regione di memoria virtuale mappata nello spazio di indirizzamento del processo corrente. L'opportunità di IPC si presenta quando un secondo processo apre un oggetto di File Mapping oppure quando lo eredita dal processo padre, come accade nella classe associata a questo post.

Windows, internamente, mappa la regione di memoria virtuale associata al File Mapping nel primo processo alla stessa memoria fisica (o posizione nel Paging File) anche nel secondo processo: il risultato è che quando si scrive o legge da tale memoria (sia nel primo che nel secondo processo) internamente si sta accedendo alla stessa memoria fisica della macchina.

E' possibile associare delle informazioni di sicurezza all'oggetto di File Mapping tramite la struttura SECURITY_ATTRIBUTES, così come accade quando si crea un file, per esempio.

Nel caso specifico della classe qui presentata, l'handle all'oggetto di File Mapping viene passato al secondo processo tramite command line dal primo processo (ossia il processo "padre", tramite una chiamata a CreateProcess). Per rendere ciò possibile è necessario specificare esplicitamente che gli oggetti kernel che si stanno creando (nel primo processo) possono essere ereditati da tutti i processi "figli". Questo impostando un bit nella struttura SECURITY_ATTRIBUTES, passata poi alle funzioni "CreateFileMapping" e "CreateEvent":

  SECURITY_ATTRIBUTES sa;

  ::memset( & sa, 0, sizeof( sa ) );

  sa.bInheritHandle = TRUE;

 

  m_hDataAvailEvent = ::CreateEvent( & sa, FALSE, FALSE, NULL );

  m_hDataReceivedEvent = ::CreateEvent( & sa, FALSE, FALSE, NULL );

  m_hFileMapping = ::CreateFileMapping( INVALID_HANDLE_VALUE, & sa, PAGE_READWRITE, 0, m_dwFileMappingDim, NULL );

La classe ha due costruttori, a seconda se si è nel primo o nel secondo processo:

  CSharedMemoryChannel( DWORD dwFileMappingDim )

 

  CSharedMemoryChannel( charstring& csInitParams )

Il primo processo chiama il primo costruttore, specificando semplicemente la dimensione della Shared Section da creare.

Il secondo processo, invece, passa una stringa (eventualmente estratta dalla propria Command Line) con un formato di questo tipo:

  handle al File Mapping [PIPE] dimensione del File Mapping [PIPE] handle al primo Evento (DataAvailEvent) [PIPE] handle al secondo Evento (DataReceivedEvent)

L'applicazione può chiamare il metodo "GetSharedMemoryDataString" per ottenere in automatico questa stringa.

Come per le altre classi di IPC simili presenti nella sezione Archivi del mio sito, due tipi di puntatore a funzione sono definiti per permettere al consumer della mia classe di ricevere notifica quando nuovi dati sono presenti oppure quando l'altra parte si è "disconnessa":

  typedef VOID ( __cdecl * PFNSMCRECV )( IN DWORD dwParam, IN LPVOID pvBuffer, IN LONG lBufferSize );

  typedef VOID ( __cdecl * PFNSMCDISCONNECT )( IN DWORD dwParam );

 

Tali puntatori vengono specificati chiamando l'API "SetRecvFunction":

 

  BOOL SetRecvFunction ( PFNSMCRECV pfnRecv, PFNSMCDISCONNECT pfnDisconnect, DWORD dwRecvParam )

 

La classe è scaricabile qui: SharedMemoryChannel.h (10,19 KB).