sl@0: // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: sl@0: #include sl@0: #if defined(_UNICODE) sl@0: #if !defined(UNICODE) sl@0: #define UNICODE sl@0: #endif sl@0: #endif sl@0: #define WIN32_LEAN_AND_MEAN sl@0: #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union sl@0: #include sl@0: #include sl@0: #include sl@0: #pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union sl@0: sl@0: #include "ESTW32SV.H" sl@0: sl@0: #ifndef EKA2 sl@0: GLDEF_C TInt E32Dll(TDllReason) sl@0: { sl@0: return KErrNone; sl@0: } sl@0: #endif sl@0: sl@0: // -------------- CLIENT IMPLEMENTATION ----------------------------- sl@0: sl@0: EXPORT_C void RWin32Stream::StartServer() sl@0: // sl@0: // Static function which spawns the three servers sl@0: // sl@0: { sl@0: CWin32Stream::StartServer(Kstdin); sl@0: CWin32Stream::StartServer(Kstdout); sl@0: CWin32Stream::StartServer(Kstderr); sl@0: } sl@0: sl@0: EXPORT_C TInt RWin32Stream::Open(TInt aStream) sl@0: { sl@0: TBuf<8> stream; sl@0: if (CWin32Stream::StreamName(aStream,stream)!=KErrNone) sl@0: return KErrArgument; sl@0: TVersion version(1,0,0); sl@0: return CreateSession(stream,version,1); // only one message allowed - no concurrency sl@0: } sl@0: sl@0: TInt RWin32Stream::CheckEOF(TRequestStatus& aStatus) sl@0: { sl@0: if (Handle()!=0) sl@0: return KErrNone; sl@0: TRequestStatus* aStatusPtr=&aStatus; sl@0: User::RequestComplete(aStatusPtr,KErrEof); sl@0: return KErrEof; sl@0: } sl@0: sl@0: EXPORT_C void RWin32Stream::Read(TRequestStatus& aStatus, TDes8& aDes) sl@0: { sl@0: Read(aStatus, aDes, aDes.MaxLength()); sl@0: } sl@0: sl@0: EXPORT_C void RWin32Stream::Read(TRequestStatus& aStatus, TDes8& aDes, TInt aLength) sl@0: { sl@0: if (CheckEOF(aStatus)) sl@0: return; sl@0: SendReceive(EWin32Read,TIpcArgs(&aDes,aLength),aStatus); sl@0: } sl@0: sl@0: EXPORT_C void RWin32Stream::Write(TRequestStatus& aStatus, const TDesC8& aDes) sl@0: { sl@0: Write(aStatus, aDes, aDes.Length()); sl@0: } sl@0: sl@0: EXPORT_C void RWin32Stream::Write(TRequestStatus& aStatus, const TDesC8& aDes, TInt aLength) sl@0: // sl@0: // Write aLength bytes sl@0: // sl@0: { sl@0: if (CheckEOF(aStatus)) sl@0: return; sl@0: SendReceive(EWin32Write,TIpcArgs(&aDes,aLength),aStatus); sl@0: } sl@0: sl@0: EXPORT_C void RWin32Stream::Flush(TRequestStatus& aStatus) sl@0: // sl@0: // Flush output sl@0: // sl@0: { sl@0: if (CheckEOF(aStatus)) sl@0: return; sl@0: SendReceive(EWin32Flush,aStatus); sl@0: } sl@0: sl@0: // -------------- SERVER IMPLEMENTATION ----------------------------- sl@0: // sl@0: // This is only relevant to WINS, so we know that in truth it's all a single address space sl@0: // and we can just operate on the descriptors directly. sl@0: sl@0: //#define ESTW32_LOGGING // log the stream output into a file sl@0: sl@0: TInt CWin32Stream::StreamName(TInt aStream, TDes& aBuf) sl@0: { sl@0: switch (aStream) sl@0: { sl@0: case Kstdin: sl@0: aBuf=_L("stdin"); break; sl@0: case Kstdout: sl@0: aBuf=_L("stdout"); break; sl@0: case Kstderr: sl@0: aBuf=_L("stderr"); break; sl@0: default: sl@0: return KErrArgument; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: struct rendezvous sl@0: { sl@0: TRequestStatus* iStatus; sl@0: TInt iStream; sl@0: RThread iCaller; sl@0: TBuf<8> iStreamName; sl@0: }; sl@0: sl@0: void CWin32Stream::StartServer(TInt aStream) sl@0: // sl@0: // Static function which spawns a server thread sl@0: // sl@0: { sl@0: TRequestStatus status(KRequestPending); sl@0: struct rendezvous rv; sl@0: rv.iStatus=&status; sl@0: rv.iStream=aStream; sl@0: TInt err=StreamName(aStream,rv.iStreamName); sl@0: if (err!=KErrNone) sl@0: return; sl@0: err=rv.iCaller.Duplicate(RThread(),EOwnerProcess); sl@0: if (err!=KErrNone) sl@0: return; sl@0: RThread server; sl@0: err=server.Create(rv.iStreamName,ThreadFunction,2048,4096,65536,(TAny*)&rv,EOwnerProcess); sl@0: if (err==KErrNone) sl@0: { sl@0: server.Resume(); sl@0: User::WaitForRequest(status); sl@0: server.Close(); sl@0: } sl@0: rv.iCaller.Close(); sl@0: } sl@0: sl@0: TInt CWin32Stream::ThreadFunction(TAny* aPtr) sl@0: { sl@0: struct rendezvous* rvp=(struct rendezvous*)aPtr; sl@0: TInt err=KErrNoMemory; sl@0: CWin32Stream* stream = new CWin32Stream(); sl@0: if (stream!=0) sl@0: err=stream->Init(rvp->iStream, rvp->iStreamName); sl@0: rvp->iCaller.RequestComplete(rvp->iStatus,err); // let the caller continue sl@0: if (err==KErrNone) sl@0: { sl@0: FOREVER sl@0: stream->HandleMessage(); sl@0: } sl@0: else sl@0: { sl@0: delete stream; sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: TInt CWin32Stream::Init(TInt aStream, const TDesC& aStreamName) sl@0: { sl@0: iHandle = GetStdHandle((STD_INPUT_HANDLE)-(int)aStream); sl@0: if (iHandle==INVALID_HANDLE_VALUE) sl@0: return KErrNotFound; sl@0: sl@0: #ifdef ESTW32_LOGGING sl@0: static char* logs[3]={ "x:\\stdin.log", "x:\\stdout.log", "x:\\stderr.log"}; sl@0: iLogHandle=CreateFile(logs[aStream], GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); sl@0: #else sl@0: iLogHandle=INVALID_HANDLE_VALUE; sl@0: #endif sl@0: sl@0: return iServer.CreateGlobal(aStreamName); sl@0: } sl@0: sl@0: void CWin32Stream::HandleMessage() sl@0: { sl@0: iServer.Receive(iMessage); sl@0: TInt err=KErrNone; sl@0: TInt f=iMessage.Function(); sl@0: switch (f) sl@0: { sl@0: case RMessage2::EConnect: sl@0: case RMessage2::EDisConnect: sl@0: // RServer2 connection management - nothing interesting to be done sl@0: break; sl@0: sl@0: case EWin32Read: sl@0: err=ReadStream(iMessage); sl@0: break; sl@0: case EWin32Write: sl@0: err=WriteStream(iMessage); sl@0: break; sl@0: case EWin32Flush: sl@0: FlushStream(); sl@0: break; sl@0: sl@0: default: sl@0: err=KErrNotSupported; sl@0: break; sl@0: } sl@0: iMessage.Complete(err); sl@0: } sl@0: sl@0: TInt CWin32Stream::ReadStream(RMessage2& aMessage) sl@0: { sl@0: TDes8* bufDes = (TDes8*)(aMessage.Ptr0()); sl@0: int length = aMessage.Int1(); sl@0: unsigned long nbytes; sl@0: sl@0: if (ReadFile(iHandle, (TAny*)(bufDes->Ptr()), length, &nbytes, 0) && nbytes>0) sl@0: { sl@0: bufDes->SetLength(nbytes); sl@0: return KErrNone; sl@0: } sl@0: return MapWin32Error(KErrEof); sl@0: } sl@0: sl@0: TInt CWin32Stream::WriteStream(RMessage2& aMessage) sl@0: { sl@0: TDesC8* bufDes = (TDesC8*)(aMessage.Ptr0()); sl@0: int length = aMessage.Int1(); sl@0: int offset = 0; sl@0: unsigned long nbytes; sl@0: sl@0: #ifdef ESTW32_LOGGING sl@0: WriteFile(iLogHandle, bufDes->Ptr(), length, &nbytes, 0); sl@0: FlushFileBuffers(iLogHandle); sl@0: #endif sl@0: sl@0: while (length>offset) sl@0: { sl@0: if (!WriteFile(iHandle, bufDes->Ptr()+offset, length-offset, &nbytes, 0)) sl@0: return MapWin32Error(KErrEof); sl@0: offset+=nbytes; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: void CWin32Stream::FlushStream() sl@0: { sl@0: FlushFileBuffers(iHandle); // don't care if it works or not sl@0: } sl@0: sl@0: #include sl@0: sl@0: TInt CWin32Stream::MapWin32Error(TInt aDefault) sl@0: { sl@0: switch (GetLastError()) sl@0: { sl@0: case ERROR_INVALID_HANDLE: sl@0: return KErrBadHandle; sl@0: case ERROR_HANDLE_EOF: sl@0: return KErrEof; sl@0: } sl@0: return aDefault; sl@0: }