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