xref: /trunk/main/sal/osl/os2/pipeimpl.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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