Windows系统编程之进程间通信
作者:北极星2003
来源:看雪论坛(www.pediy.com)
Windows 的IPC(进程间通信)机制主要是异步管道和命名管道。(至于其他的IPC方式,例如内存映射、邮槽等这里就不介绍了)
管道(pipe)是用于进程间通信的共享内存区域。创建管道的进程称为管道服务器,而连接到这个管道的进程称为管道客户端。一个进程向管道写入信息,而另外一个进程从管道读取信息。
异步管道是基于字符和半双工的(即单向),一般用于程序输入输出的重定向;命名管道则强大地多,它们是面向消息和全双工的,同时还允许网络通信,用于创建客户端/服务器系统。
一、异步管道(实现比较简单,直接通过实例来讲解)
实验目标:当前有sample.cpp, sample.exe, sample.in这三个文件,sample.exe为sample.cpp的执行程序,sample.cpp只是一个简单的程序示例(简单求和),如下:
#include <iostream.h>
int main()
{
int a, b ;
while ( cin >> a >> b && ( a || b ) )
cout << a + b << endl ;
return 0;
}
#include <windows.h>
#include <iostream.h>
const int BUFSIZE = 4096 ;
HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
hChildStdoutRd,hChildStdoutWr,hChildStdoutRdDup,
hSaveStdin, hSaveStdout;
BOOL CreateChildProcess(LPTSTR);
VOID WriteToPipe(LPTSTR);
VOID ReadFromPipe(LPTSTR);
VOID ErrorExit(LPTSTR);
VOID ErrMsg(LPTSTR, BOOL);
void main( int argc, char *argv[] )
{
// 处理输入参数
if ( argc != 4 )
return ;
// 分别用来保存命令行,输入文件名(CPP/C),输出文件名(保存编译信息)
LPTSTR lpProgram = new char[ strlen(argv[1]) ] ;
strcpy ( lpProgram, argv[1] ) ;
LPTSTR lpInputFile = new char[ strlen(argv[2]) ];
strcpy ( lpInputFile, argv[2] ) ;
LPTSTR lpOutputFile = new char[ strlen(argv[3]) ] ;
strcpy ( lpOutputFile, argv[3] ) ;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
/************************************************
* redirecting child process's STDOUT *
************************************************/
hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
ErrorExit("Stdout pipe creation failed\n");
if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
ErrorExit("Redirecting STDOUT failed");
BOOL fSuccess = DuplicateHandle(
GetCurrentProcess(),
hChildStdoutRd,
GetCurrentProcess(),
&hChildStdoutRdDup ,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if( !fSuccess )
ErrorExit("DuplicateHandle failed");
CloseHandle(hChildStdoutRd);
/************************************************
* redirecting child process's STDIN *
************************************************/
hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);
if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
ErrorExit("Stdin pipe creation failed\n");
if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))
ErrorExit("Redirecting Stdin failed");
fSuccess = DuplicateHandle(
GetCurrentProcess(),
hChildStdinWr,
GetCurrentProcess(),
&hChildStdinWrDup,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (! fSuccess)
ErrorExit("DuplicateHandle failed");
CloseHandle(hChildStdinWr);
/************************************************
* 创建子进程(即启动SAMPLE.EXE) *
************************************************/
fSuccess = CreateChildProcess( lpProgram );
if ( !fSuccess )
ErrorExit("Create process failed");
// 父进程输入输出流的还原设置
if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))
ErrorExit("Re-redirecting Stdin failed\n");
if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
ErrorExit("Re-redirecting Stdout failed\n");
WriteToPipe( lpInputFile ) ;
ReadFromPipe( lpOutputFile );
delete lpProgram ;
delete lpInputFile ;
delete lpOutputFile ;
}
BOOL CreateChildProcess( LPTSTR lpProgram )
{
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bFuncRetn = FALSE;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
bFuncRetn = CreateProcess ( NULL, lpProgram, NULL, NULL, TRUE, \
0, NULL, NULL, &siStartInfo, &piProcInfo);
if (bFuncRetn == 0)
{
ErrorExit("CreateProcess failed\n");
return 0;
}
else
{
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return bFuncRetn;
}
}
VOID WriteToPipe( LPTSTR lpInputFile )
{
HANDLE hInputFile = CreateFile(lpInputFile, GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if (hInputFile == INVALID_HANDLE_VALUE)
return ;
BOOL fSuccess ;
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE] = {0} ;
for (;;)
{
fSuccess = ReadFile( hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ;
if ( !fSuccess || dwRead == 0)
break;
fSuccess = WriteFile( hChildStdinWrDup, chBuf, dwRead, &dwWritten, NULL) ;
if ( !fSuccess )
break;
}
if (! CloseHandle(hChildStdinWrDup))
ErrorExit("Close pipe failed\n");
CloseHandle ( hInputFile ) ;
}
VOID ReadFromPipe( LPTSTR lpOutputFile )
{
HANDLE hOutputFile = CreateFile( lpOutputFile, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hOutputFile == INVALID_HANDLE_VALUE)
return ;
BOOL fSuccess ;
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE] = { 0 };
if (!CloseHandle(hChildStdoutWr))
ErrorExit("Closing handle failed");
for (;;)
{
fSuccess = ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, NULL) ;
if( !fSuccess || dwRead == 0)
{
break;
}
fSuccess = WriteFile( hOutputFile, chBuf, dwRead, &dwWritten, NULL) ;
if ( !fSuccess )
break;
}
CloseHandle ( hOutputFile ) ;
}
VOID ErrorExit (LPTSTR lpszMessage)
{
MessageBox( 0, lpszMessage, 0, 0 );
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)