Sun Xin teaching video note (17) inter-process communication

Source: Internet
Author: User

Four Methods of inter-process communication
Clipboard
Anonymous Pipeline
Named Pipe
Mail Trough

On the Win32 platform, memory blocks are never moved in the physical memory, but can be moved in the default heap.

Clipboard
Save data to the clipboard:
Void cclipboarddlg: onbnclickedbtnsend ()
{
// Todo: add the control notification handler code here
If (openclipboard ())
{
Cstring STR;
Char * pbuf;
Handle hclip;
Emptyclipboard ();
Getdlgitemtext (idc_edit_send, STR );
Hclip = globalalloc (gmem_moveable, str. getlength () + 1 );
Pbuf = (char *) globallock (hclip );
Strcpy (pbuf, STR );
Globalunlock (hclip );
Setclipboarddata (cf_text, hclip );
Closeclipboard ();
}
}
Function:
1. bool openclipboard (hwnd hwndnewowner );
The
Openclipboard function opens the clipboard for examination and prevents
Other applications from modifying the clipboard content.

2. hglobal globalalloc (
Uint uflags,
Size_t dwbytes );
The
Globalalloc function allocates the specified number of bytes from
Heap. Windows Memory Management does not provide a separate local heap
And global heap.
Note the global functions are slower than other
Memory management functions and do not provide as your features.
Therefore, new applications shocould use the heap functions. However,
Global functions are still used with DDE, the clipboard functions, and
Ole data objects.

3. lpvoid globallock (hglobal hmem );
The globallock function locks a global memory object and returns a pointer to the first byte of the object's memory block.

Note the global functions are slower than other memory management
Functions and do not provide as your features. Therefore, new
Applications shocould use the heap functions. However, the global
Functions are still used with DDE and the clipboard functions.

4. Handle setclipboarddata (
Uint uformat,
Handle hmem );
The
Setclipboarddata function places data on the clipboard in a specified
Clipboard format. The window must be the current clipboard owner, and
The application must have called the openclipboard function. (when
Responding to the wm_renderformat and wm_renderallformats messages,
Clipboard owner must not call openclipboard before calling
Setclipboarddata .)
The wm_renderformat message is sent to
Clipboard owner if it has delayed rendering a specific clipboard format
And if an application has requested data in that format. The clipboard
Owner must render data in the specified format and place it on
Clipboard by calling the setclipboarddata function.

5 bool closeclipboard (void );
The closeclipboard function closes the clipboard.

6 bool emptyclipboard (void );
The emptyclipboard Function
Empties the clipboard and frees handles to data in the clipboard.
Function then assigns ownership of the clipboard to the window that
Currently has the clipboard open.

Check whether the data meets the requirements:
Bool isclipboardformatavailable (uint format );
The isclipboardformatavailable function determines whether the Clipboard contains data in the specified format.

Read data from the clipboard:
Void cclipboarddlg: onbnclickedbtnrecv ()
{
// Todo: add the control notification handler code here
If (openclipboard ())
{
If (isclipboardformatavailable)
{
Char * pbuf;
Handle hclip;
Hclip = getclipboarddata (cf_text );
Pbuf = (char *) globallock (hclip); // convert the data to the character type
Globalunlock (hclip );
Setdlgitemtext (idc_edit_recv, pbuf );
Closeclipboard ();
}
}
}

Anonymous Pipeline
Create an MPS queue:
Bool createpipe (
Phandle hreadpipe,
Phandle hwritepipe,
Lpsecurity_attributes lppipeattributes,
DWORD nsize
);

Start Process:
Bool CreateProcess (
Lptstr lpapplicationname,
Lptstr lpcommandline,
Lpsecurity_attributes lpprocessattributes,
Lpsecurity_attributes lpthreadattributes,
Bool binherithandles,
DWORD dwcreationflags,
Lpvoid lpenvironment,
Maid directory,
Lpstartupinfo,
Lpprocess_information lpprocessinformation
);
The
CreateProcess function creates a new process and its primary thread.
The new process runs the specified executable file in the security
Context of the calling process.
If the calling process is
Impersonating another user, the new process uses the token for
Calling process, not the impersonation token. To run the new process in
The security context of the user represented by the impersonation
Token, use the createprocessasuser or createprocesswithlogonw function.
The startupinfo struct is defined as follows:
Typedef
Struct _ startupinfo {dword cb; lptstr lpreserved; lptstr
Lpdesktop; lptstr lptitle; DWORD dwx; DWORD dwy; DWORD dwxsize;
DWORD dwysize; DWORD dwxcountchars; DWORD dwycountchars; DWORD
Dwfillattriags; DWORD dwflags; Word wshowwindow; Word cbreserved2;
Lpbyte lpreserved2; handle hstdinput; handle hstdoutput; handle
Hstderror;
} Startupinfo, * lpstartupinfo;

You can use the following function to set all the members in the body to zero:
Void zeromemory (pvoid destination, size_t length );

To obtain the standard input output or standard error handle, use the function:
Handle getstdhandle (DWORD nstdhandle );
The result is the standard error handle of the parent process.

Close process and thread object handle
Closehandle (PI. hprocess); // closes the returned sub-Process Handle
Closehandle (PI. hthread); // close the main thread handle in the sub-process
In
When a new process is created, the system creates a main process kernel object and a thread kernel object. The kernel object has a usage count. The system assigns the initial usage count 1 to the kernel object. When
When createprogress opens the kernel object internally, the usage count of each object changes to 2. If we do not need to use these two handles in the parent process, call closehandle
When the two handles are closed, the system will subtract 1 from the process Kernel Object and thread Kernel Object of the sub-process. When the sub-process stops running, the system will then subtract one from the count, at this time, the kernel object utility count is zero, and the process kernel pair
And thread kernel objects can be released. We should use closehandle to close the handle without using the kernel object handle.

The code for creating an anonymous pipeline is as follows:
Void cparentview: onpipecreate ()
{
// Todo: add the command handler code here
Security_attributes SA;
SA. binherithandle = true;
SA. lpsecuritydescriptor = NULL;
SA. nlength = sizeof (security_attributes );

If (! Createpipe (& hread, & hwrite, & SA, 0) // The fourth parameter is zero and uses the default buffer size.
{
MessageBox ("An error occurred while creating the anonymous MPs queue! ");
Return;
}
Startupinfo Sui;
Process_information PI;
Zeromemory (& Sui, sizeof (startupinfo ));
Sui. cb = sizeof (startupinfo );
Sui. dwflags = startf_usestdhandles;
Sui. hstdinput = hread;
Sui. hstdoutput = hwrite;
Sui. hstderror = getstdhandle (std_error_handle );
If (CreateProcess (".. // child // debug // child.exe", null, true,
0, null, null, & Sui, & PI ))
{
Closehandle (hread );
Closehandle (hwrite );
Hread = NULL;
Hwrite = NULL;
MessageBox ("failed to create sub-process! ");
Return;
}
Else
{
Closehandle (PI. hprocess); // closes the returned sub-Process Handle
Closehandle (PI. hthread); // close the main thread handle in the sub-process
}
}

Create an MPS queue in the parent process, return the read/write handle of the MPs queue, call the CreateProcess promoter process, and set the standard input/output handle of the sub-process to the read/write handle of the MPs queue, it is equivalent to marking the read/write handle of the pipeline and passing it to the sub-process. Get your own standard input/output handle in the sub-process, which is equivalent to obtaining the read/write handle of the pipeline.

The anonymous pipeline can only communicate between parent and child processes. Because the anonymous pipeline has no name, we only need to pass the read/write handle of the pipeline to the child process when calling CreateProcess.

Add read/write Functions
Void cparentview: onpiperead ()
{
// Todo: add the command handler code here
Char Buf [100];
DWORD dwread;
If (! Readfile (hread, Buf, 100, & dwread, null ))
{
MessageBox ("failed to read data! ");
Return;
}
Else MessageBox (BUF );
}

Void cparentview: onpipewrite ()
{
// Todo: add the command handler code here
Char Buf [] = "I love you! ";
DWORD dwwrite;
If (! Writefile (hwrite, Buf, strlen (BUF) + 1, & dwwrite, null ))
{
MessageBox ("failed to write data! ");
Return;
}
}

Do you remember to create a sub-process function on the front:
If (CreateProcess (".. // child // debug // child.exe", null, true,
0, null, null, & Sui, & PI ))
Next, create a project named child in the directory with the same name.

Most of the code can be transplanted to the program just now.
To obtain the standard input and standard output handles of sub-processes, You need to obtain them after the View class window is fully created. Add a virtual function oninitialupdate (); this function is the first function called after the window is created successfully.
The Code is as follows:
Void cchildview: oninitialupdate ()
{
Cview: oninitialupdate ();

// Todo: Add dedicated code and/or call the base class here
Hread = getstdhandle (std_input_handle );
Hwrite = getstdhandle (std_output_handle );
}

Handle getstdhandle (
DWORD nstdhandle
);
Std_input_handle handle to the standard input device. Initially, this is a handle to the console input buffer, conin $.
Std_output_handle
Handle to the standard output device. Initially, this is a handle
The active console screen buffer, conout $.
Std_error_handle
Handle to the standard error device. Initially, this is a handle
The active console screen buffer, conout $.
If the Function
Succeeds, the return value is a handle to the specified device, or
Redirected handle set by a previous call to setstdhandle. The handle
Has generic_read and generic_write access rights, unless
Application has used setstdhandle to set a standard handle with lesser
Access.

Named Pipe
A named pipe is used to communicate between processes through a network. It shields the network protocol details of the local name. Without understanding the network protocol, we can also use named pipes to implement inter-process communication.
The naming pipeline fully utilizes the built-in security mechanisms of Windows NT and windows.
When a named pipe is used as a network programming scheme, it establishes a Client/Server Communication System and reliably transmits data in it.
Named Pipe is a mechanism designed around the Windows File System. It adopts the "Named Pipe File System (npfs)" interface. Therefore, the client and server can use the standard Win32 file system kernel (such as readfile and writefile) to send and receive data.
The difference between a named MPs Queue Server and a client is that the server is the only process that has the right to create a named MPs queue and can only accept connection requests from the MPs queue client. The client can only establish a connection with a named pipe server.
Life
The name of the MPs Queue Server can only be used in Windows
Because it is created on NT or Windows2000, we cannot use pipelines to communicate between two windows 95 or Windows 98 computers. However, the client can be
A Windows 95 or Windows 98 computer that communicates with a Windows NT or Windows 2000 computer.
The named pipe provides two basic communication modes: byte mode and message mode. In byte mode, data flows between the client and the server in the form of a continuous byte stream. In message mode, the client and server send and receive data through a series of discontinuous data units. Each time a message is sent in the pipeline, it must be read as a complete message.

Server process usage
Handle createnamedpipe (
Lptstr lpname,
DWORD dwopenmode,
DWORD dwpipemode,
DWORD nmaxinstances,
DWORD noutbuffersize,
DWORD ninbuffersize,
DWORD ndefatimetimeout,
Lpsecurity_attributes lpsecurityattributes
);
Create the first instance of the named pipeline or a new instance of the existing named Pipeline
The
Createnamedpipe function creates an instance of a named pipe and
Returns a handle for subsequent Pipe operations. a named pipe Server
Process uses this function either to create the first instance of
Specific Named Pipe and establish its basic attributes or to create
New instance of an existing named pipe.
Windows ME/98/95: Named Pipes cannot be created.

Call createevent to create an event object that is manually or automatically reset
Handle createevent (
Lpsecurity_attributes lpeventattributes,
Bool bmanualreset,
Bool binitialstate,
Lptstr lpname
);

 

The server waits for the connection request to arrive. Use the function:
Bool connectnamedpipe (
Handle hnamedpipe,
Lpoverlapped );

If connectnamedpipe returns a zero value and error_io_pending = getlasterror () indicates that the operation has not failed, and the operation may be completed later.

If you want to call another executable program in one program, you can use CreateProcess. The Code is as follows:
Startupinfo Sui;
Process_information PI;
Zeromemory (& Sui, sizeof (startupinfo ));
Sui. cb = sizeof (startupinfo );
Sui. dwflags = startf_usestdhandles;
Sui. hstdinput = hpipe;
Sui. hstdoutput = hpipe;
Sui. hstderror = getstdhandle (std_error_handle );
CreateProcess (".. // namedpipeclient // debug // namedpipeclient.exe", null, true, 0, null, null, & Sui, & PI );

Next, create the server of the named pipe. The Code is as follows:

Void cnamepipeview: onpipecreate ()
{
// Todo: add the command handler code here
Hpipe = createnamedpipe ("//. // pipe // mytest ",
Pipe_access_duplex | file_flag_overlapped, 0, null );
If (invalid_handle_value = hpipe)
{
MessageBox ("An error occurred while creating the named pipe! ");
Hpipe = NULL;
Return;
}
Handle hevent;
Hevent = createevent (null, true, false, null );
If (! Hevent)
{
MessageBox ("An error occurred while creating the event object! ");
Closehandle (hpipe );
Hpipe = NULL;
Return;
}
Overlapped LP;
Zeromemory (& LP, sizeof (overlapped ));
LP. hevent = hevent;

If (! Connectnamedpipe (hpipe, & LP ))
{
If (error_io_pending! = Getlasterror ())
// If they are equal, the operation may be completed later.
{
MessageBox ("waiting for client segment connection failed! ");
Closehandle (hpipe );
Closehandle (hevent );
Hpipe = NULL;
Return;
}
}
If (wait_failed = waitforsingleobject (hevent, infinite ))
{
MessageBox ("failed to wait for the object! ");
Closehandle (hpipe );
Closehandle (hevent );
Hpipe = NULL;
Return;
}
Closehandle (hevent );
}

Void cnamepipeview: onpiperead ()
{
// Todo: add the command handler code here
Char Buf [100];
DWORD dwread;
If (! Readfile (hpipe, Buf, 100, & dwread, null ))
{
MessageBox ("failed to read data! ");
Return;
}
Else MessageBox (BUF );
}

Void cnamepipeview: onpipewreie ()
{
// Todo: add the command handler code here
Char Buf [] = "I love you! ";
DWORD dwwrite;
If (! Writefile (hpipe, Buf, strlen (BUF) + 1, & dwwrite, null ))
{
MessageBox ("failed to write data! ");
Return;
}
}

Void cnamepipeview: onpipeopen ()
{
// Todo: add the command handler code here
Startupinfo Sui;
Process_information PI;
Zeromemory (& Sui, sizeof (startupinfo ));
Sui. cb = sizeof (startupinfo );
Sui. dwflags = startf_usestdhandles;
Sui. hstdinput = hpipe;
Sui. hstdoutput = hpipe;
Sui. hstderror = getstdhandle (std_error_handle );
CreateProcess (".. // namedpipeclient // debug // namedpipeclient.exe", null, true,
0, null, null, & Sui, & PI );
}
// Onpipeopen () is added by myself. I have just installed VC ++ 2003.net. I don't know how to start the second program at the same time, you have to use this code to call the client program in the main program.

The client program is relatively simple. You only need to wait for the named pipeline instance on the network.
The Code is as follows:
Void cnamedpipeclientview: onpipeconnect ()
{
// Todo: add the command handler code here
If (! Waitnamedpipe ("//. // pipe // mytest", nmpwait_wait_forever ))
{
MessageBox ("No namepipeline instance is available now! ");
Return;
}
Hpipe = createfile ("//. // pipe // mytest", file_pai_read | file_pai_write,
0, null, open_existing, file_attribute_normal, null );
// Indicates the name of the server and "." indicates the local host. If you want to connect to another host, replace the host name. Note that the backslash in double quotation marks indicates two.
If (invalid_handle_value = hpipe)
{
MessageBox ("opening the namespace failed! ");
Hpipe = NULL;
Return;
}
}

Void cnamedpipeclientview: onpiperead ()
{
// Todo: add the command handler code here
Char Buf [100];
DWORD dwread;
If (! Readfile (hpipe, Buf, 100, & dwread, null ))
{
MessageBox ("failed to read data! ");
Return;
}
Else MessageBox (BUF );
}

Void cnamedpipeclientview: onpipewrite ()
{
// Todo: add the command handler code here
Char Buf [] = "named Pipeline Test Program !! ";
DWORD dwwrite;
If (! Writefile (hpipe, Buf, strlen (BUF) + 1, & dwwrite, null ))
{
MessageBox ("failed to write data! ");
Return;
}
}

Mail Trough
The mail trough is designed based on the broadcast communication system and uses non-connection and unreliable data transmission.
The mail trough is a one-way communication mechanism. The server process that creates the mail trough reads data, and the client process that opens the mail trough writes data. To ensure that the mail trough works normally on various Windows platforms, when we transmit a message, we should limit the message length to less than 424 bytes.
To create a mailbox, you can use the Function
Handle createmailslot (
Lptstr lpname,
DWORD nmaxmessagesize,
DWORD lreadtimeout,
Lpsecurity_attributes lpsecurityattributes
);
Server code:
Void cmailsoltsrvview: onmailrecv ()
{
// Todo: add the command handler code here
// Handle hmail;

Hmail = createmailslot ("//. // Mailslot // mymail", 0, mailslot_wait_forever, null );
If (invalid_handle_value = hmail)
{
MessageBox ("An error occurred while creating the mailbox! ");
Return;
}
Char Buf [100] = "0 ";
DWORD dwread;
If (! Readfile (hmail, Buf, 100, & dwread, null ))
{
MessageBox ("failed to read data! ");
Closehandle (hmail );
Return;
}
MessageBox (BUF );
Closehandle (hmail );
}

Client code:
Void cmailsoltcltview: onmailsend ()
{
// Todo: add the command handler code here
Handle hmail;
Hmail = createfile ("//. // Mailslot // mymail", generic_read, file_assist_read,
Null, open_existing, file_attribute_normal, null );
If (invalid_handle_value = hmail)
{
MessageBox ("failed to open the mailbox! ");
Return;
}
 
Char Buf [] = "mail slot test program! ";
DWORD dwwrite;
If (! Writefile (hmail, Buf, strlen (BUF) + 1, & dwwrite, null ))
{
MessageBox ("failed to write data! ");
Closehandle (hmail );
Return;
}
Closehandle (hmail );
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.