Windows Programming _ sun Xin C ++ lesson17 inter-process communication
Highlights of this section:
This section describes four inter-process communication technologies, including clipboard, anonymous pipeline, named pipeline, and oil tank.
//************************************** **************************************** **************
1. Communication operation on the clipboard
Communication between processes using Windows clipboard
(1) Open the clipboard openclipboard. The current window is only after the clipboard is opened
The clipboard is available only after emptyclipboard () function is called.
(2) set the setclipboarddata function of the Clipboard data. The prototype of the function is handle setclipboarddata (
Uint uformat, // the data format includes the standard and registered format
Handle hmem // data handle
);
You can use the clipboard when submitting data in a delayed manner to improve resource utilization.
Delayed submission: a data-providing process creates a clipboard until other processes obtain data. If too much data is placed on the clipboard,
To avoid wasting resources, a data provider provides a process with an empty data handle in the specified format (the second parameter is null ),
Data is not actually submitted until another process or itself ends.
The operating system sends the wm_renderformat and wm_renderallformats messages to the process for data retrieval,
In this case, the data provider process can use the setclipboarddata function to place the actual data on the clipboard. After the setclipboarddata function is called,
The system has the object specified by the hmem parameter. The application can read data but cannot release the handle or lock it. It knows that the closeclipboard function is called,
After closeclipboard is called, the application can access the data. If the hmem parameter specifies a memory object,
Therefore, this memory object must be allocated by the globalalloc function marked with gmem_moveable.
(3) The globalalloc function allocates specified bytes from the heap. When gmem_moveable is used for allocation, the returned handle of the memory object instead of the actual pointer,
To obtain the actual memory block pointer, you must use the globallock function to replace the handle.
The data structure of a memory object contains a lock count, which is initialized as 0. For removable memory objects,
During initialization, globallock adds 1 to the lock count and globalunlock minus 1. note that a locked memory object will be locked all the time and can be moved or released only when the lock count is reduced to 0.
(3) getclipboarddata obtains data from the clipboard and works with the isclipboardformatavailable function,
This function determines whether the data in the specified format is available currently (whether the data in this format is available on the clipboard ).
(4) The closeclipboard function closes the clipboard. When the application detects or changes the clipboard, close the clipboard so that other programs can access the clipboard.
After the clipboard is disabled, the application can access the Clipboard data.
(5) The experiment code is as follows:
//************************************** **************************************** **************
// Clipboarddlg. CPP // send data void cclipboarddlg: onbtnsend () {// todo: add your control notification handler code herecstring strsend; If (openclipboard () {emptyclipboard (); handle hclipmem; char * pbuf; getdlgitemtext (idc_edit_send, strsend); hclipmem = globalalloc (gmem_moveable, strsend. getlength () + 1); // allocate the Memory Object pbuf = (char *) globallock (hclipmem); // convert the handle to the actually referencing pointer strcpy (pbuf, strsend ); // load data to the memory object globalunlock (hclipmem); // unlock setclipboarddata (cf_text, hclipmem); // set the Clipboard data in the specified format to cf_textcloseclipboard (); // close the clipboard closehandle (hclipmem); // release handle} // obtain data from the clipboard void cclipboarddlg: onbtnrecv () {// todo: add your control notification handler code hereif (openclipboard () {If (isclipboardformatavailable (cf_text) {handle hclipmem; char * pbuf; // handle returned by getclipboarddata () is controlled by the clipboard, instead of applications, the application should immediately copy data. // the application cannot be released or the handle hclipmem = getclipboarddata (cf_text); pbuf = (char *) globallock (hclipmem ); globalunlock (hclipmem); setdlgitemtext (idc_edit_recv, pbuf); closeclipboard ();}}}
//************************************** **************************************** **************
When the program is running, the following data is sent to the clipboard:
When the program is running, the data obtained from the clipboard is as follows:
//************************************** **************************************** **************
2. The anonymous pipeline (anonymous pipes) implements parent-child process Communication for local machines
(1) The createpipe function creates an anonymous pipeline and returns the read/write handle of the pipeline. Function prototype:
Bool createpipe (
Phandle hreadpipe, // get the pipeline read handle
Phandle hwritepipe, // get the pipeline write handle
Lpsecurity_attributes lppipeattributes, // Security Attribute pointer, pointing to the structure of security_attributes
// This parameter determines whether the returned handle can be inherited by the quilt process. If it is null, it cannot be inherited.
DWORD nsize // MPs queue buffer size
);
(2) CreateProcess is used to create a process. It is mainly used to create a sub-process. Note that the execution module name in the lpapplicationname parameter of the process is correct.
(3) readfile and writefile are used to read and write pipeline files.
(4) Note that the parent and child processes are not started at the same time, but are started by the parent process after the parent process is started. Anonymous pipelines are only suitable for communication between parent and child processes,
Of course, the parent process can read data from the MPs queue after writing data to the MPs queue. The implementation of the anonymous pipeline is essentially that the parent process passes a read/write handle to the child process.
(5) The main code of the anonymous pipeline experiment is as follows:
//************************************** **************************************** **************
// Parentview. CPP // cparentview construction/destruction // process cparentview: cparentview () {// todo: Add construction code here hread = NULL; // handle hreadhwrite = NULL; // handle hwrite} cparentview ::~ Cparentview () {If (hread! = NULL) closehandle (hread); If (hwrite! = NULL) closehandle (hwrite);} // cparentview message handlers // The parent process creates a pipe void cparentview: onpipecreate () {// todo: add your command handler code heresecurity_attributes SA; SA. binherithandle = true; // set it to sa. lpsecuritydescriptor = NULL; // default security descriptor SA. nlength = sizeof (security_attributes); If (! Createpipe (& hread, & hwrite, & SA, 0) {afxmessagebox ("failed to create an anonymous pipeline! "); Return;} process_information PI; // startupinfo Sui; // The initial information structure of the main process window: zeromemory (& Sui, sizeof (startupinfo )); // set all to zero sui. CB = sizeof (startupinfo); sui. dwflags = startf_usestdhandles; sui. hstdinput = hread; sui. hstdoutput = hwrite; // specifies the Sui. hstderror = getstdhandle (std_error_handle ); // get the standard error handle of the parent process // specify the pipeline parameters for transmitting the promoter process. specify the method for filling in the first parameter. // set the fifth parameter to true to allow the child process to inherit the pipeline handle that was just created. If (! CreateProcess (".. \ child \ debug \ child.exe ", null, true, 0, null, null, & Sui, & PI) {closehandle (hread ); hread = NULL; closehandle (hwrite); hwrite = NULL; afxmessagebox ("failed to create sub-process! "); Return;} else {closehandle (Pi. hprocess); closehandle (Pi. hthread); // reduce the use count of the sub-process by 1} // The parent process reads data from the pipeline void cparentview: onpiperead () {// todo: add your command handler code herechar chread [100]; DWORD dwread; If (! Readfile (hread, chread, 100, & dwread, null) {afxmessagebox ("An error occurred while reading the MPs queue! "); Return;} elseafxmessagebox (chread);} // The parent process writes data to the MPs queue void cparentview: onpipewrite () {// todo: add your command handler code herechar chwrtie [] = "pipe info from parent \ n"; DWORD dwwrite; If (! Writefile (hwrite, chwrtie, strlen (chwrtie) + 1, & dwwrite, null) {afxmessagebox ("pipeline writing failed! "); Return ;}} //************************************** **************************************** * ************* // childview. CPP // cchildview construction/destruction // process cchildview: cchildview () {// todo: Add construction code here hread = NULL; // handle hreadhwrite = NULL; // handle hwrite} cchildview ::~ Cchildview () {If (hread! = NULL) closehandle (hread); If (hwrite! = NULL) closehandle (hwrite );} // cchildview message handlers // The sub-process obtains the standard input and output handle because the Read and Write handle void cchildview: oninitialupdate () of the parent process is set in the parent process () {cview: oninitialupdate (); // todo: add your specialized code here and/or call the base classhread = getstdhandle (std_input_handle); hwrite = getstdhandle (std_output_handle );} // The sub-process reads the void cchildview: onpiperead () {// todo: add your command handler code herechar chread [10 0]; DWORD dwread; If (! Readfile (hread, chread, 100, & dwread, null) {afxmessagebox ("An error occurred while reading the MPs queue! "); Return;} elseafxmessagebox (chread);} // The Void cchildview: onpipewrite () {// todo: add your command handler code herechar chwrtie [] = "pipe info from child \ n"; DWORD dwwrite; If (! Writefile (hwrite, chwrtie, strlen (chwrtie) + 1, & dwwrite, null) {afxmessagebox ("pipeline writing failed! "); Return ;}}
//************************************** **************************************** **************
When the program is running, the parent process obtains data from the child process, as shown in:
When the program is running, the sub-process obtains data from the parent process, as shown in:
//************************************** **************************************** **************
3. Named pipeline named pipes.
Not only can two processes communicate with the local machine, but also two processes communicate with each other across the network. Shows an introduction to named pipelines:
(1) Naming pipeline Working Process: Create a pipeline on the server end ---- connect the client to the pipeline ---- read and write data on the server end and client side (the read/write mode is specified when the pipeline is created)
(2) createnamedpipe creates an instance named pipeline.
The function is prototype:
Handle createnamedpipe (
Lptstr lpname, // pipe name
DWORD dwopenmode, // pipe open mode
DWORD dwpipemode, // pipe-specific modes
DWORD nmaxinstances, // maximum number of instances
DWORD noutbuffersize, // output buffer size
DWORD ninbuffersize, // input buffer size
DWORD ndefatimetimeout, // time-out interval
Lpsecurity_attributes lpsecurityattributes // SD
);
Function parameter description:
Parameter 1: MPS queue name, which uniquely identifies the MPs queue.
Parameter 2: three main access modes: two-way read/write mode, client write server read mode, and server write client read mode
Overlapping operations are relative to synchronization operations. The file_flag_overlapped overlaps. The specified read/write operation function can return immediately, while the actual time-consuming read/write operations are performed in the background. The function returns only after the time-consuming read/write operation is completed.
Parameter 3: read/write mode of the MPs queue. The same type must be used for the same MPs queue. Message mode write is compatible with byte mode read and message mode read;
The write in byte mode cannot be compatible with the read in message mode. Because the delimiters are written in message mode,
When reading in message mode, the complete information is read through the delimiters. When reading in byte mode, the delimiters are ignored to read the complete information;
If the message read mode (pipe_readmode_message) is adopted after the byte write mode (pipe_type_byte ),
Because the byte mode ignores the delimiters, the message read mode cannot know how many bytes to read, so the two cannot match.
Parameter 4: specify the maximum number of examples that can be created for this pipeline. For instances created in the same MPs queue, the same number must be specified.
Note that this number refers to the number of instances that can be created for the same name pipeline. To Connect Five client requests, you must call 5 createnamedpipe.
Parameter 5: Specify the output buffer size of the MPs queue.
Parameter 6: Specify the input buffer size for the MPs queue.
Parameter 7: If the waitnamedpipe function specifies the nmpwait_use_default_wait parameter, this parameter is used to specify the connection timeout value. No instance of a named pipeline must have the same value.
Parameter 8: Security Attribute pointer
If the function is successfully executed, return the handle of the named pipe instance on the server side. Otherwise, return invalid_handle_value.
(3) The connectnamedpipe function allows the server to wait for the client process to connect to an instance named pipe. Note that this function is not used for the client to connect to the server, the client to connect to the server, using the createfile or callnamedpipe function.
The connectnamedpipe function is prototype:
Bool connectnamedpipe (
Handle hnamedpipe, // handle to Named Pipe
Lpoverlapped // overlapped Structure
);
Parameter 1: Pipeline handle returned by the createnamedpipe function.
Parameter 2: If the file_flag_overlapped flag is specified when the hnamedpipe MPs queue handle is created,
This parameter cannot be blank, otherwise it will not work properly.
This parameter points to an overlapped structure, which must contain a valid manual reset event object handle (created by the createevent function ). if the hnamedpipe pipeline is not opened with the file_flag_overlapped flag, this function will only return if it knows a client connection or an error occurs. If the function is successfully called, a non-zero value is returned. If the function fails, 0 is returned;
You can use the getlaterror function to obtain more information.
(4) connect to the server pipeline and use the waitnamedpipe function. The function prototype is:
Bool waitnamedpipe (
Lptstr lpnamedpipename, // pipe name
DWORD ntimeout // time-out interval
);
Parameter 1: lpnamedpipename, which specifies the name of the named MPs queue. The name includes the server name and MPs queue name.
Format: \ servername \ PIPE \ pipename.
Parameter 2: ntimeout, waiting for the timeout value of an available named pipe. When nmpwait_use_default_wait is specified,
The timeout value is the default value set when the createnamedpipe function is created on the server. If this parameter is set to nmpwait_wait_forever, wait until an available Named Pipe exists.
The function returns immediately when no pipe is specified. When the function is successful, use the createfile function to open a named pipe.
(5) Open the pipeline and use the createfile function. Its prototype is:
Handle createfile (
Lptstr lpfilename, // MPs queue name
DWORD dwdesiredaccess, // access mode such as generic_read
DWORD dw1_mode, // share mode
Lpsecurity_attributes lpsecurityattributes, // Security Attribute
DWORD dwcreationdisposition, // how to open open_existing
DWORD dwflagsandattributes, // file attributes such as file_attribute_normal
Handle htemplatefile // template file handle
);
After the MPs queue is opened, the server and the client can communicate with each other.
(6) The main code of the named pipeline experiment is as follows:
//************************************** **************************************** **************
// Namedpipeview. cpp // cnamedpipeview construction/Direction: cnamedpipeview () {// todo: Add construction code here hpipe = NULL; // handle hpipe} cnamedpipeview ::~ Cnamedpipeview () {If (hpipe! = NULL) closehandle (hpipe);} // cnamedpipeview message handlers // The server creates a pipeline and waits for the client to connect to void cnamedpipeview: onpipecreate () {// todo: add your command handler code here // create a named pipeline to obtain its handle hpipe = createnamedpipe ("\\\\. \ PIPE \ pipeex ", pipe_access_duplex | file_flag_overlapped, 0, null); If (hpipe = invalid_handle_value) {afxmessagebox (" pipeline creation failed! "); Hpipe = NULL; return;} // specify the file_flag_overlapped flag when creating the pipeline. Prepare the event object handle hevent for connectnamedpipe; hevent = createevent (0, true, false, null); If (! Hevent) {afxmessagebox ("An error occurred while creating the event object! "); Closehandle (hpipe); hpipe = NULL; return;} overlapped ovlap; zeromemory (& ovlap, sizeof (overlapped); ovlap. hevent = hevent; // manually reset the event object // wait for the client request. Note that this is not the client connection request if (! Connectnamedpipe (hpipe, & ovlap) {// if the function fails, 0 is returned, but error_io_pending is returned when getlasterror fails. If (error_io_pending! = Getlasterror () {afxmessagebox ("Wait for the client connection to fail! "); Closehandle (hpipe); closehandle (hevent); hpipe = NULL; return ;}// wait for the event object to change to a signal state if (wait_failed = waitforsingleobject (hevent, infinite) {afxmessagebox ("An error occurred while waiting for the object! "); Closehandle (hpipe); closehandle (hevent); hpipe = NULL; return ;} // when the event object changes to a signal, the client has been connected to the server. Close the event object handle closehandle (hevent);} // The server reads the named pipe void cnamedpipeview: onpiperead () {// todo: add your command handler code herechar chread [100]; DWORD dwread; If (! Readfile (hpipe, chread, 100, & dwread, null) {afxmessagebox ("An error occurred while reading the MPs queue! "); Return;} elseafxmessagebox (chread);} // The server writes the named pipe void cnamedpipeview: onpipewrite () {// todo: add your command handler code herechar chwrtie [] = "pipe info from SRV \ n"; DWORD dwwrite; If (! Writefile (hpipe, chwrtie, strlen (chwrtie) + 1, & dwwrite, null) {afxmessagebox ("pipeline writing failed! "); Return ;}} //************************************** **************************************** * ************* // namedpipecltview. CPP // cnamedpipecltview construction/destructioncnamedpipecltview: cnamedpipecltview () {// todo: Add construction code here hpipe = NULL; // handle hpipe;} cnamedpipecltview ::~ Cnamedpipecltview () {If (hpipe! = NULL) closehandle (hpipe);} // cnamedpipecltview message handlers // client connection pipe void cnamedpipecltview: onconn () {// todo: add your command handler code here // wait for the server pipe and Connect if (! Waitnamedpipe ("\\\\\\\ PIPE \ pipeex", nmpwait_use_default_wait) {afxmessagebox ("there are currently no named pipeline instances available! "); Hpipe = NULL; return;} // when an available Named Pipe exists, open the pipe hpipe = createfile ("\\\\. \ PIPE \ pipeex ", generic_read | generic_write, 0, null, open_existing, file_attribute_normal, null); If (invalid_handle_value = hpipe) {afxmessagebox (" failed! "); Hpipe = NULL; return ;}// the client reads the named pipe void cnamedpipecltview: onpiperead () {// todo: add your command handler code herechar chread [100]; DWORD dwread; If (! Readfile (hpipe, chread, 100, & dwread, null) {afxmessagebox ("An error occurred while reading the MPs queue! "); Return;} elseafxmessagebox (chread);} // The Void cnamedpipecltview: onpipewrite () {// todo: add your command handler code herechar chwrtie [] = "namedpipe info from CLT \ n"; DWORD dwwrite; If (! Writefile (hpipe, chwrtie, strlen (chwrtie) + 1, & dwwrite, null) {afxmessagebox ("pipeline writing failed! "); Return ;}}
//************************************** **************************************** **************
When the program is running, the server obtains data from the client, as shown in:
When the program is running, the client obtains data from the server, as shown in:
//************************************** **************************************** **************
4. Groove Mailslot
(1) features of oil tanks:
The oil slot is designed based on the broadcast communication system and adopts non-connection and unreliable data transmission;
The slot is a simple communication mechanism. The process that creates a slot reads data and the client process that opens the slot to write data;
To ensure the normal operation of the oil tanks on various Windows platforms, when we transmit information,
The length of the information should be limited to less than 424 bytes.
(2) create a slot and use the createmailslot function. The prototype of this function is:
Handle createmailslot (
Lptstr lpname, // The name of the oil tank is in the \. \ Mailslot \ [path] Name format
DWORD nmaxmessagesize, // the maximum amount of information that can be written into the slot in bytes
DWORD lreadtimeout, // timeout value when reading the Oil Tank
Lpsecurity_attributes lpsecurityattributes // Security Attribute security_attributes
// In this structure, binherithandle determines the sub-process inheritance right of the tank handle.
);
(3) for two-way communication, you must write a client and a server in the same program, use the client to send data, and use the server to read data.
Using the broadcast features of the oil tanks, It is very convenient to compile the Conference notification program. Disadvantage: the amount of data sent is small.
(4) The main code of the tank experiment is as follows:
//************************************** **************************************** **************
// Mailslotsrvview. CPP // the oil tank server can only read data void cmailslotsrvview: onmailslotrecv () {// todo: add your command handler code here // create the oil tank mailslot_wait_forever parameter to specify the read wait time to keep waiting hmailslot = createmailslot ("\\\\. \ Mailslot ", 0, mailslot_wait_forever, null); If (invalid_handle_value = hmailslot) {afxmessagebox (" tank creation failed! "); Hmailslot = NULL; return;} // read the oil tank data char chread [100]; DWORD dwread; If (! Readfile (hmailslot, chread, 100, & dwread, null) {afxmessagebox ("An error occurred while reading the slot! "); Return;} elseafxmessagebox (chread );} //************************************** **************************************** * ************* // mailslotcltview. CPP // The Groove client can only send data to open the groove and write the data into the void cmailslotcltview: onmailslotsend () {// todo: add your command handler code here // open the oil tank and set file_assist_read to share read data. If not on the local machine, set the server name hmailslot = createfile ("\\\\. \ Mailslot ", generic_write, file_assist_read, null, open_ex Isting, file_attribute_normal, null); If (invalid_handle_value = hmailslot) {afxmessagebox ("failed to open the slot! "); Hmailslot = NULL; return;} DWORD dwwrite; If (! Writefile (hmailslot, "this is from liming! ", Strlen (" this is from liming! ") + 1, & dwwrite, null) {afxmessagebox (" failed to write to the slot! "); Return ;}}
// Shows the experiment running effect:
//************************************** **************************************** **************
Summary:
The four communication technologies described in this section have their own characteristics and are selected as needed.
Clipboard communication uses the clipboard provided by the Windows operating system to implement simple inter-process communication, but only on local machines;
Anonymous pipelines are only suitable for communications between parent and child processes on local machines. They do not support cross-network communications between two processes. Note that they are communications between parent and child processes;
The naming pipeline has the most powerful functions. In server and client mode, process communication between local machines and cross-network process communication can be realized;
The oil tank communication mechanism is a one-way read/write mechanism that sends and receives data in the form of broadcast. Its form is very simple, but the data flow is not bidirectional,
To achieve two-way communication, you also need to add a complete set of client and server programs.
Note that when naming pipelines or tanks, you must enter the correct host name or domain name for cross-network communication.