xref: /trunk/main/sal/osl/os2/pipeimpl.cxx (revision cdf0e10c)
1 #	include "pipeimpl.h"
2 
3 #ifndef _INC_MALLOC
4 #	include <malloc.h>
5 #endif
6 
7 #ifndef _INC_TCHAR
8 #	ifdef UNICODE
9 #		define _UNICODE
10 #	endif
11 #	include <tchar.h>
12 #endif
13 
14 const TCHAR PIPE_NAME_PREFIX_MAPPING[] = TEXT("PIPE_FILE_MAPPING_");
15 const TCHAR PIPE_NAME_PREFIX_SYNCHRONIZE[] = TEXT("PIPE_SYNCHRONIZE_MUTEX_");
16 const TCHAR PIPE_NAME_PREFIX_CONNECTION[] = TEXT("PIPE_CONNECTION_SEMAPHORE_");
17 
18 const DWORD PIPE_BUFFER_SIZE = 4096;
19 
20 
21 //============================================================================
22 //	PipeData
23 //============================================================================
24 
25 struct PipeData
26 {
27 	DWORD	dwProcessId;
28 	HANDLE	hReadPipe;
29 	HANDLE	hWritePipe;
30 };
31 
32 //============================================================================
33 //	Pipe
34 //============================================================================
35 
36 #ifdef UNICODE
37 #define Pipe		PipeW
38 #define ClientPipe	ClientPipeW
39 #define ServerPipe	ServerPipeW
40 #else
41 #define Pipe		PipeA
42 #define ClientPipe	ClientPipeA
43 #define ServerPipe	ServerPipeA
44 #endif
45 
46 class Pipe
47 {
48 protected:
49 	HANDLE	m_hReadPipe;	// Handle to use for reading
50 	HANDLE	m_hWritePipe;	// Handle to use for writing
51 
52 	Pipe( HANDLE hReadPipe, HANDLE hWritePipe );
53 
54 	static HANDLE CreatePipeDataMutex( LPCTSTR lpName, BOOL bInitialOwner );
55 	static HANDLE CreatePipeDataMapping( LPCTSTR lpName );
56 	static HANDLE OpenPipeDataMapping( LPCTSTR lpName );
57 	static HANDLE CreatePipeConnectionSemaphore( LPCTSTR lpName, LONG lInitialCount, LONG lMaximumcount );
58 
59 public:
60 	Pipe( const Pipe& );
61 	const Pipe& operator = ( const Pipe& );
62 	virtual ~Pipe();
63 
64 	virtual bool Close();
65 	virtual bool Write( LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, bool bWait = true );
66 	virtual bool Read( LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, bool bWait = true );
67 
68 	virtual Pipe *AcceptConnection()
69 	{
70 		SetLastError( ERROR_INVALID_HANDLE );
71 		return NULL;
72 	}
73 
74 	void * operator new( size_t nBytes )
75 	{
76 		return HeapAlloc( GetProcessHeap(), 0, nBytes );
77 	}
78 
79 	void operator delete( void *ptr )
80 	{
81 		HeapFree( GetProcessHeap(), 0, ptr );
82 	}
83 
84 	bool is() const
85 	{
86 		return (FALSE != HeapValidate( GetProcessHeap(), 0, this ));
87 	}
88 
89 };
90 
91 //============================================================================
92 //	ClientPipe
93 //============================================================================
94 
95 class ClientPipe : public Pipe
96 {
97 protected:
98 	ClientPipe( HANDLE hReadPipe, HANDLE hWritePipe );
99 public:
100 	static ClientPipe* Create( LPCTSTR lpName );
101 };
102 
103 //============================================================================
104 //	ServerPipe
105 //============================================================================
106 
107 class ServerPipe : public Pipe
108 {
109 protected:
110 	HANDLE	m_hMapping;
111 	HANDLE	m_hSynchronize;
112 	LPTSTR	m_lpName;
113 
114 	ServerPipe( LPCTSTR lpName, HANDLE hMapping, HANDLE hSynchronize, HANDLE hReadPipe, HANDLE hWritePipe );
115 public:
116 	virtual ~ServerPipe();
117 
118 	static ServerPipe *Create( LPCTSTR lpName );
119 
120 	virtual Pipe *AcceptConnection();
121 };
122 
123 //----------------------------------------------------------------------------
124 //
125 //----------------------------------------------------------------------------
126 
127 HANDLE	Pipe::CreatePipeDataMapping( LPCTSTR lpName )
128 {
129 	HANDLE	hMapping = NULL;
130 	LPTSTR	lpMappingName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_MAPPING) );
131 
132 	if ( lpMappingName )
133 	{
134 		_tcscpy( lpMappingName, PIPE_NAME_PREFIX_MAPPING );
135 		_tcscat( lpMappingName, lpName );
136 
137 		LPTSTR	lpMappingFileName = (LPTSTR)alloca( MAX_PATH * sizeof(TCHAR) );
138 
139 		if ( lpMappingFileName )
140 		{
141 			DWORD	nChars = GetTempPath( MAX_PATH, lpMappingFileName );
142 
143 			if ( MAX_PATH + _tcslen(lpName) < nChars + 1 )
144 			{
145 				lpMappingFileName = (LPTSTR)alloca( (nChars + 1 + _tcslen(lpName)) * sizeof(TCHAR) );
146 				if ( lpMappingFileName )
147 					nChars = GetTempPath( nChars, lpMappingFileName );
148 				else
149 				{
150 					nChars = 0;
151 					SetLastError( ERROR_NOT_ENOUGH_MEMORY );
152 				}
153 			}
154 
155 			if ( nChars )
156 			{
157 				_tcscat( lpMappingFileName, lpMappingName );
158 
159 				HANDLE hFile = CreateFile(
160 					lpMappingFileName,
161 					GENERIC_READ | GENERIC_WRITE,
162 					FILE_SHARE_READ | FILE_SHARE_WRITE,
163 					NULL,
164 					OPEN_ALWAYS,
165 					FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
166 					NULL );
167 
168 				if ( IsValidHandle(hFile) )
169 				{
170 					hMapping = CreateFileMapping(
171 						(HANDLE)hFile,
172 						(LPSECURITY_ATTRIBUTES)NULL,
173 						PAGE_READWRITE,
174 						0,
175 						sizeof(PipeData),
176 						lpMappingName );
177 
178 					CloseHandle( hFile );
179 				}
180 			}
181 		}
182 		else
183 			SetLastError( ERROR_NOT_ENOUGH_MEMORY );
184 	}
185 
186 	return hMapping;
187 }
188 
189 //----------------------------------------------------------------------------
190 //
191 //----------------------------------------------------------------------------
192 
193 HANDLE	Pipe::OpenPipeDataMapping( LPCTSTR lpName )
194 {
195 	HANDLE	hMapping = NULL;
196 	LPTSTR	lpMappingName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_MAPPING) );
197 
198 	if ( lpMappingName )
199 	{
200 		_tcscpy( lpMappingName, PIPE_NAME_PREFIX_MAPPING );
201 		_tcscat( lpMappingName, lpName );
202 
203 		hMapping = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, lpMappingName );
204 	}
205 
206 	return hMapping;
207 }
208 
209 //----------------------------------------------------------------------------
210 //
211 //----------------------------------------------------------------------------
212 
213 HANDLE	Pipe::CreatePipeDataMutex( LPCTSTR lpName, BOOL bInitialOwner )
214 {
215 	HANDLE	hMutex = NULL;
216 	LPTSTR	lpMutexName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_SYNCHRONIZE) );
217 
218 	if ( lpMutexName )
219 	{
220 		_tcscpy( lpMutexName, PIPE_NAME_PREFIX_SYNCHRONIZE );
221 		_tcscat( lpMutexName, lpName );
222 
223 		hMutex = CreateMutex( NULL, bInitialOwner, lpMutexName );
224 	}
225 
226 	return hMutex;
227 }
228 
229 //----------------------------------------------------------------------------
230 //
231 //----------------------------------------------------------------------------
232 
233 HANDLE Pipe::CreatePipeConnectionSemaphore( LPCTSTR lpName, LONG lInitialCount, LONG lMaximumCount )
234 {
235 	HANDLE	hSemaphore = NULL;
236 	LPTSTR	lpSemaphoreName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_CONNECTION) );
237 
238 	if ( lpSemaphoreName )
239 	{
240 		_tcscpy( lpSemaphoreName, PIPE_NAME_PREFIX_CONNECTION );
241 		_tcscat( lpSemaphoreName, lpName );
242 
243 		hSemaphore = CreateSemaphore( NULL, lInitialCount, lMaximumCount, lpSemaphoreName );
244 	}
245 
246 	return hSemaphore;
247 }
248 
249 
250 //----------------------------------------------------------------------------
251 //	Pipe copy ctor
252 //----------------------------------------------------------------------------
253 
254 Pipe::Pipe( const Pipe& rPipe ) :
255 m_hReadPipe( INVALID_HANDLE_VALUE ),
256 m_hWritePipe( INVALID_HANDLE_VALUE )
257 {
258 	DuplicateHandle(
259 		GetCurrentProcess(),
260 		rPipe.m_hReadPipe,
261 		GetCurrentProcess(),
262 		&m_hReadPipe,
263 		0,
264 		FALSE,
265 		DUPLICATE_SAME_ACCESS );
266 
267 	DuplicateHandle(
268 		GetCurrentProcess(),
269 		rPipe.m_hWritePipe,
270 		GetCurrentProcess(),
271 		&m_hWritePipe,
272 		0,
273 		FALSE,
274 		DUPLICATE_SAME_ACCESS );
275 }
276 
277 //----------------------------------------------------------------------------
278 //	Pipe assignment operator
279 //----------------------------------------------------------------------------
280 
281 const Pipe& Pipe::operator = ( const Pipe& rPipe )
282 {
283 	Close();
284 
285 	DuplicateHandle(
286 		GetCurrentProcess(),
287 		rPipe.m_hReadPipe,
288 		GetCurrentProcess(),
289 		&m_hReadPipe,
290 		0,
291 		FALSE,
292 		DUPLICATE_SAME_ACCESS );
293 
294 	DuplicateHandle(
295 		GetCurrentProcess(),
296 		rPipe.m_hWritePipe,
297 		GetCurrentProcess(),
298 		&m_hWritePipe,
299 		0,
300 		FALSE,
301 		DUPLICATE_SAME_ACCESS );
302 
303 	return *this;
304 }
305 
306 //----------------------------------------------------------------------------
307 //	Pipe ctor
308 //----------------------------------------------------------------------------
309 
310 Pipe::Pipe( HANDLE hReadPipe, HANDLE hWritePipe ) :
311 m_hReadPipe( INVALID_HANDLE_VALUE ),
312 m_hWritePipe( INVALID_HANDLE_VALUE )
313 {
314 	DuplicateHandle(
315 		GetCurrentProcess(),
316 		hReadPipe,
317 		GetCurrentProcess(),
318 		&m_hReadPipe,
319 		0,
320 		FALSE,
321 		DUPLICATE_SAME_ACCESS );
322 
323 	DuplicateHandle(
324 		GetCurrentProcess(),
325 		hWritePipe,
326 		GetCurrentProcess(),
327 		&m_hWritePipe,
328 		0,
329 		FALSE,
330 		DUPLICATE_SAME_ACCESS );
331 }
332 
333 //----------------------------------------------------------------------------
334 //	Pipe dtor
335 //----------------------------------------------------------------------------
336 
337 Pipe::~Pipe()
338 {
339 	Close();
340 }
341 
342 //----------------------------------------------------------------------------
343 //	Pipe Close
344 //----------------------------------------------------------------------------
345 
346 bool Pipe::Close()
347 {
348 	bool	fSuccess = false;	// Assume failure
349 
350 	if ( IsValidHandle(m_hReadPipe) )
351 	{
352 		CloseHandle( m_hReadPipe );
353 		m_hReadPipe = INVALID_HANDLE_VALUE;
354 	}
355 
356 	if ( IsValidHandle(m_hWritePipe) )
357 	{
358 		CloseHandle( m_hWritePipe );
359 		m_hWritePipe = INVALID_HANDLE_VALUE;
360 	}
361 
362 	return fSuccess;
363 }
364 
365 //----------------------------------------------------------------------------
366 //	Pipe Write
367 //----------------------------------------------------------------------------
368 
369 bool Pipe::Write( LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, bool bWait )
370 {
371 	DWORD	dwBytesAvailable = 0;
372 	BOOL	fSuccess = TRUE;
373 
374 	if ( !bWait )
375 		fSuccess = PeekNamedPipe( m_hReadPipe, NULL, 0, NULL, &dwBytesAvailable, NULL );
376 
377 	if ( fSuccess )
378 	{
379 		if ( !bWait && dwBytesToWrite > PIPE_BUFFER_SIZE - dwBytesAvailable )
380 			dwBytesToWrite = PIPE_BUFFER_SIZE - dwBytesAvailable ;
381 
382 		return !!WriteFile( m_hWritePipe, lpBuffer, dwBytesToWrite, lpBytesWritten, NULL );
383 	}
384 
385 	return false;
386 }
387 
388 //----------------------------------------------------------------------------
389 //	Pipe Read
390 //----------------------------------------------------------------------------
391 
392 bool Pipe::Read( LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, bool bWait )
393 {
394 	DWORD	dwBytesAvailable = 0;
395 	BOOL	fSuccess = TRUE;
396 
397 	if ( !bWait )
398 		fSuccess = PeekNamedPipe( m_hReadPipe, NULL, 0, NULL, &dwBytesAvailable, NULL );
399 
400 	if ( fSuccess )
401 	{
402 		if ( bWait || dwBytesAvailable )
403 			return !!ReadFile( m_hReadPipe, lpBuffer, dwBytesToRead, lpBytesRead, NULL );
404 		else
405 		{
406 			*lpBytesRead = 0;
407 			return true;
408 		}
409 	}
410 
411 	return false;
412 }
413 
414 
415 
416 //----------------------------------------------------------------------------
417 //	Client pipe dtor
418 //----------------------------------------------------------------------------
419 
420 ClientPipe::ClientPipe( HANDLE hReadPipe, HANDLE hWritePipe ) : Pipe( hReadPipe, hWritePipe )
421 {
422 }
423 
424 //----------------------------------------------------------------------------
425 //	Client pipe creation
426 //----------------------------------------------------------------------------
427 
428 ClientPipe *ClientPipe::Create( LPCTSTR lpName )
429 {
430 	ClientPipe	*pPipe = NULL;	// Assume failure
431 
432 	HANDLE	hMapping = OpenPipeDataMapping( lpName );
433 
434 	if ( IsValidHandle(hMapping) )
435 	{
436 		PipeData	*pData = (PipeData*)MapViewOfFile( hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
437 
438 		if ( pData )
439 		{
440 			HANDLE	hSourceProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, pData->dwProcessId );
441 
442 			if ( IsValidHandle(hSourceProcess) )
443 			{
444 				BOOL fSuccess;
445 				HANDLE	hReadPipe = INVALID_HANDLE_VALUE, hWritePipe = INVALID_HANDLE_VALUE;
446 
447 				fSuccess = DuplicateHandle(
448 					hSourceProcess,
449 					pData->hReadPipe,
450 					GetCurrentProcess(),
451 					&hReadPipe,
452 					0,
453 					FALSE,
454 					DUPLICATE_SAME_ACCESS );
455 
456 				fSuccess = fSuccess && DuplicateHandle(
457 					hSourceProcess,
458 					pData->hWritePipe,
459 					GetCurrentProcess(),
460 					&hWritePipe,
461 					0,
462 					FALSE,
463 					DUPLICATE_SAME_ACCESS );
464 
465 				if ( fSuccess )
466 					pPipe = new ClientPipe( hReadPipe, hWritePipe );
467 
468 				if ( IsValidHandle(hWritePipe) )
469 					CloseHandle( hWritePipe );
470 
471 				if ( IsValidHandle(hReadPipe) )
472 					CloseHandle( hReadPipe );
473 
474 				HANDLE	hConnectionRequest = CreatePipeConnectionSemaphore( lpName, 0, 1 );
475 
476 				ReleaseSemaphore( hConnectionRequest, 1, NULL );
477 
478 				CloseHandle( hConnectionRequest );
479 
480 				CloseHandle( hSourceProcess );
481 			}
482 
483 			UnmapViewOfFile( pData );
484 		}
485 
486 		CloseHandle( hMapping );
487 	}
488 
489 	return pPipe;
490 }
491 
492 
493 
494 //----------------------------------------------------------------------------
495 //	ServerPipe ctor
496 //----------------------------------------------------------------------------
497 
498 ServerPipe::ServerPipe( LPCTSTR	lpName, HANDLE hMapping, HANDLE hSynchronize, HANDLE hReadPipe, HANDLE hWritePipe ) : Pipe( hReadPipe, hWritePipe ),
499 m_hMapping( NULL ),
500 m_hSynchronize( NULL ),
501 m_lpName( NULL )
502 {
503 	DuplicateHandle(
504 		GetCurrentProcess(),
505 		hMapping,
506 		GetCurrentProcess(),
507 		&m_hMapping,
508 		0,
509 		FALSE,
510 		DUPLICATE_SAME_ACCESS );
511 
512 	DuplicateHandle(
513 		GetCurrentProcess(),
514 		hSynchronize,
515 		GetCurrentProcess(),
516 		&m_hSynchronize,
517 		0,
518 		FALSE,
519 		DUPLICATE_SAME_ACCESS
520 		);
521 	m_lpName = new TCHAR[_tcslen(lpName) + 1];
522 	if ( m_lpName )
523 		_tcscpy( m_lpName, lpName );
524 }
525 
526 //----------------------------------------------------------------------------
527 //	ServerPipe dtor
528 //----------------------------------------------------------------------------
529 
530 ServerPipe::~ServerPipe()
531 {
532 	if ( IsValidHandle(m_hMapping) )
533 		CloseHandle( m_hMapping );
534 	if ( m_lpName )
535 		delete[]m_lpName;
536 }
537 
538 //----------------------------------------------------------------------------
539 //	ServerPipe AcceptConnection
540 //----------------------------------------------------------------------------
541 
542 Pipe *ServerPipe::AcceptConnection()
543 {
544 	Pipe	*pPipe = NULL;	// Assume failure;
545 
546 	HANDLE	hConnectionRequest = CreatePipeConnectionSemaphore( m_lpName, 0, 1 );
547 
548 	if ( WAIT_OBJECT_0 == WaitForSingleObject( hConnectionRequest, INFINITE ) )
549 	{
550 		pPipe = new Pipe( *this );
551 		Close();
552 
553 		// Create new inbound Pipe
554 
555 		HANDLE	hClientWritePipe = NULL, hServerReadPipe = NULL;
556 
557 		BOOL	fSuccess = CreatePipe( &hServerReadPipe, &hClientWritePipe, NULL, PIPE_BUFFER_SIZE );
558 
559 
560 		if ( fSuccess )
561 		{
562 			// Create outbound pipe
563 
564 			HANDLE	hClientReadPipe = NULL, hServerWritePipe = NULL;
565 
566 			if ( CreatePipe( &hClientReadPipe, &hServerWritePipe, NULL, PIPE_BUFFER_SIZE ) )
567 			{
568 				m_hReadPipe = hServerReadPipe;
569 				m_hWritePipe = hServerWritePipe;
570 
571 				PipeData	*pData = (PipeData *)MapViewOfFile( m_hMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(PipeData) );
572 
573 				HANDLE	hSynchronize = CreatePipeDataMutex( m_lpName, TRUE );
574 
575 				CloseHandle( pData->hReadPipe );
576 				CloseHandle( pData->hWritePipe );
577 
578 				pData->hReadPipe = hClientReadPipe;
579 				pData->hWritePipe = hClientWritePipe;
580 
581 				ReleaseMutex( hSynchronize );
582 
583 				CloseHandle( hSynchronize );
584 
585 			}
586 			else
587 			{
588 				CloseHandle( hClientWritePipe );
589 				CloseHandle( hServerWritePipe );
590 			}
591 		}
592 
593 		ReleaseMutex( hConnectionRequest );
594 	}
595 
596 	CloseHandle( hConnectionRequest );
597 
598 	return pPipe;
599 }
600 
601 //----------------------------------------------------------------------------
602 //	Pipe creation
603 //----------------------------------------------------------------------------
604 
605 ServerPipe *ServerPipe::Create( LPCTSTR lpName )
606 {
607 	ServerPipe	*pPipe = NULL;
608 
609 	HANDLE	hMapping = CreatePipeDataMapping( lpName );
610 
611 	if ( IsValidHandle(hMapping) )
612 	{
613 		if ( ERROR_FILE_EXISTS != GetLastError() )
614 		{
615 			HANDLE	hSynchronize = CreatePipeDataMutex( lpName, FALSE);
616 
617 			WaitForSingleObject( hSynchronize, INFINITE );
618 
619 			PipeData	*pData = (PipeData*)MapViewOfFile( hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
620 
621 			if ( pData )
622 			{
623 
624 				// Initialize pipe data
625 
626 				pData->dwProcessId = 0;
627 				pData->hReadPipe = NULL;
628 				pData->hWritePipe = NULL;
629 
630 				// Create inbound pipe
631 
632 				HANDLE	hServerReadPipe = NULL, hClientWritePipe = NULL;
633 
634 				BOOL	fSuccess = CreatePipe( &hServerReadPipe, &hClientWritePipe, NULL, PIPE_BUFFER_SIZE );
635 
636 				if ( fSuccess )
637 				{
638 					// Create outbound pipe
639 
640 					HANDLE	hServerWritePipe = NULL, hClientReadPipe = NULL;
641 
642 					fSuccess = CreatePipe( &hClientReadPipe, &hServerWritePipe, NULL, PIPE_BUFFER_SIZE );
643 
644 					if ( fSuccess )
645 					{
646 						pData->dwProcessId = GetCurrentProcessId();
647 						pData->hReadPipe = hClientReadPipe;
648 						pData->hWritePipe = hClientWritePipe;
649 						pPipe = new ServerPipe( lpName, hMapping, hSynchronize, hServerReadPipe, hServerWritePipe );
650 
651 						CloseHandle( hServerWritePipe );
652 						CloseHandle( hServerReadPipe );
653 					}
654 					else
655 					{
656 						CloseHandle( hServerReadPipe );
657 						CloseHandle( hClientWritePipe );
658 					}
659 				}
660 
661 				UnmapViewOfFile( pData );
662 			}
663 
664 			ReleaseMutex( hSynchronize );
665 			CloseHandle( hSynchronize );
666 		}
667 
668 		CloseHandle( hMapping );
669 	}
670 
671 	return pPipe;
672 }
673 
674 
675 //----------------------------------------------------------------------------
676 //	C style API
677 //----------------------------------------------------------------------------
678 
679 const TCHAR	LOCAL_PIPE_PREFIX[] = TEXT("\\\\.\\PIPE\\" );
680 
681 extern "C" HANDLE WINAPI CreateSimplePipe( LPCTSTR lpName )
682 {
683 	int	nPrefixLen = _tcslen( LOCAL_PIPE_PREFIX );
684 	if ( 0 == _tcsnicmp( lpName, LOCAL_PIPE_PREFIX, nPrefixLen ) )
685 		lpName += nPrefixLen;
686 	return (HANDLE)ServerPipe::Create( lpName );
687 }
688 
689 extern "C" HANDLE WINAPI OpenSimplePipe( LPCTSTR lpName )
690 {
691 	int	nPrefixLen = _tcslen( LOCAL_PIPE_PREFIX );
692 	if ( 0 == _tcsnicmp( lpName, LOCAL_PIPE_PREFIX, nPrefixLen ) )
693 		lpName += nPrefixLen;
694 	return (HANDLE)ClientPipe::Create( lpName );
695 }
696 
697 extern "C" HANDLE WINAPI AcceptSimplePipeConnection( HANDLE hPipe )
698 {
699 	Pipe	*pPipe = (Pipe *)hPipe;
700 
701 	if ( pPipe->is() )
702 		return (HANDLE)pPipe->AcceptConnection();
703 	else
704 	{
705 		SetLastError( ERROR_INVALID_HANDLE );
706 		return NULL;
707 	}
708 }
709 
710 extern "C" BOOL WINAPI WaitForSimplePipe( LPCTSTR /*lpName*/, DWORD /*dwTimeOut*/ )
711 {
712 	return FALSE;
713 }
714 
715 extern "C" BOOL WINAPI WriteSimplePipe( HANDLE hPipe, LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, BOOL bWait )
716 {
717 	Pipe	*pPipe = (Pipe *)hPipe;
718 
719 	if ( pPipe->is() )
720 		return pPipe->Write( lpBuffer, dwBytesToWrite, lpBytesWritten, bWait );
721 	else
722 	{
723 		SetLastError( ERROR_INVALID_HANDLE );
724 		return FALSE;
725 	}
726 }
727 
728 extern "C" BOOL WINAPI ReadSimplePipe( HANDLE hPipe, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, BOOL bWait )
729 {
730 	Pipe	*pPipe = (Pipe *)hPipe;
731 
732 	if ( pPipe->is() )
733 		return pPipe->Read( lpBuffer, dwBytesToRead, lpBytesRead, bWait );
734 	else
735 	{
736 		SetLastError( ERROR_INVALID_HANDLE );
737 		return FALSE;
738 	}
739 }
740 
741 extern "C" BOOL WINAPI CloseSimplePipe( HANDLE hPipe )
742 {
743 	Pipe	*pPipe = (Pipe *)hPipe;
744 
745 	if ( pPipe->is() )
746 	{
747 		delete pPipe;
748 		return TRUE;
749 	}
750 	else
751 	{
752 		SetLastError( ERROR_INVALID_HANDLE );
753 		return FALSE;
754 	}
755 }
756