sl@0
|
1 |
// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
2 |
// All rights reserved.
|
sl@0
|
3 |
// This component and the accompanying materials are made available
|
sl@0
|
4 |
// under the terms of "Eclipse Public License v1.0"
|
sl@0
|
5 |
// which accompanies this distribution, and is available
|
sl@0
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
7 |
//
|
sl@0
|
8 |
// Initial Contributors:
|
sl@0
|
9 |
// Nokia Corporation - initial contribution.
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Contributors:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// Description:
|
sl@0
|
14 |
//
|
sl@0
|
15 |
|
sl@0
|
16 |
|
sl@0
|
17 |
#include <e32std.h>
|
sl@0
|
18 |
#if defined(_UNICODE)
|
sl@0
|
19 |
#if !defined(UNICODE)
|
sl@0
|
20 |
#define UNICODE
|
sl@0
|
21 |
#endif
|
sl@0
|
22 |
#endif
|
sl@0
|
23 |
#define WIN32_LEAN_AND_MEAN
|
sl@0
|
24 |
#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
|
sl@0
|
25 |
#include <windows.h>
|
sl@0
|
26 |
#include <winbase.h>
|
sl@0
|
27 |
#include <TCHAR.H>
|
sl@0
|
28 |
#pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
|
sl@0
|
29 |
|
sl@0
|
30 |
#include "ESTW32SV.H"
|
sl@0
|
31 |
|
sl@0
|
32 |
#ifndef EKA2
|
sl@0
|
33 |
GLDEF_C TInt E32Dll(TDllReason)
|
sl@0
|
34 |
{
|
sl@0
|
35 |
return KErrNone;
|
sl@0
|
36 |
}
|
sl@0
|
37 |
#endif
|
sl@0
|
38 |
|
sl@0
|
39 |
// -------------- CLIENT IMPLEMENTATION -----------------------------
|
sl@0
|
40 |
|
sl@0
|
41 |
EXPORT_C void RWin32Stream::StartServer()
|
sl@0
|
42 |
//
|
sl@0
|
43 |
// Static function which spawns the three servers
|
sl@0
|
44 |
//
|
sl@0
|
45 |
{
|
sl@0
|
46 |
CWin32Stream::StartServer(Kstdin);
|
sl@0
|
47 |
CWin32Stream::StartServer(Kstdout);
|
sl@0
|
48 |
CWin32Stream::StartServer(Kstderr);
|
sl@0
|
49 |
}
|
sl@0
|
50 |
|
sl@0
|
51 |
EXPORT_C TInt RWin32Stream::Open(TInt aStream)
|
sl@0
|
52 |
{
|
sl@0
|
53 |
TBuf<8> stream;
|
sl@0
|
54 |
if (CWin32Stream::StreamName(aStream,stream)!=KErrNone)
|
sl@0
|
55 |
return KErrArgument;
|
sl@0
|
56 |
TVersion version(1,0,0);
|
sl@0
|
57 |
return CreateSession(stream,version,1); // only one message allowed - no concurrency
|
sl@0
|
58 |
}
|
sl@0
|
59 |
|
sl@0
|
60 |
TInt RWin32Stream::CheckEOF(TRequestStatus& aStatus)
|
sl@0
|
61 |
{
|
sl@0
|
62 |
if (Handle()!=0)
|
sl@0
|
63 |
return KErrNone;
|
sl@0
|
64 |
TRequestStatus* aStatusPtr=&aStatus;
|
sl@0
|
65 |
User::RequestComplete(aStatusPtr,KErrEof);
|
sl@0
|
66 |
return KErrEof;
|
sl@0
|
67 |
}
|
sl@0
|
68 |
|
sl@0
|
69 |
EXPORT_C void RWin32Stream::Read(TRequestStatus& aStatus, TDes8& aDes)
|
sl@0
|
70 |
{
|
sl@0
|
71 |
Read(aStatus, aDes, aDes.MaxLength());
|
sl@0
|
72 |
}
|
sl@0
|
73 |
|
sl@0
|
74 |
EXPORT_C void RWin32Stream::Read(TRequestStatus& aStatus, TDes8& aDes, TInt aLength)
|
sl@0
|
75 |
{
|
sl@0
|
76 |
if (CheckEOF(aStatus))
|
sl@0
|
77 |
return;
|
sl@0
|
78 |
SendReceive(EWin32Read,TIpcArgs(&aDes,aLength),aStatus);
|
sl@0
|
79 |
}
|
sl@0
|
80 |
|
sl@0
|
81 |
EXPORT_C void RWin32Stream::Write(TRequestStatus& aStatus, const TDesC8& aDes)
|
sl@0
|
82 |
{
|
sl@0
|
83 |
Write(aStatus, aDes, aDes.Length());
|
sl@0
|
84 |
}
|
sl@0
|
85 |
|
sl@0
|
86 |
EXPORT_C void RWin32Stream::Write(TRequestStatus& aStatus, const TDesC8& aDes, TInt aLength)
|
sl@0
|
87 |
//
|
sl@0
|
88 |
// Write aLength bytes
|
sl@0
|
89 |
//
|
sl@0
|
90 |
{
|
sl@0
|
91 |
if (CheckEOF(aStatus))
|
sl@0
|
92 |
return;
|
sl@0
|
93 |
SendReceive(EWin32Write,TIpcArgs(&aDes,aLength),aStatus);
|
sl@0
|
94 |
}
|
sl@0
|
95 |
|
sl@0
|
96 |
EXPORT_C void RWin32Stream::Flush(TRequestStatus& aStatus)
|
sl@0
|
97 |
//
|
sl@0
|
98 |
// Flush output
|
sl@0
|
99 |
//
|
sl@0
|
100 |
{
|
sl@0
|
101 |
if (CheckEOF(aStatus))
|
sl@0
|
102 |
return;
|
sl@0
|
103 |
SendReceive(EWin32Flush,aStatus);
|
sl@0
|
104 |
}
|
sl@0
|
105 |
|
sl@0
|
106 |
// -------------- SERVER IMPLEMENTATION -----------------------------
|
sl@0
|
107 |
//
|
sl@0
|
108 |
// This is only relevant to WINS, so we know that in truth it's all a single address space
|
sl@0
|
109 |
// and we can just operate on the descriptors directly.
|
sl@0
|
110 |
|
sl@0
|
111 |
//#define ESTW32_LOGGING // log the stream output into a file
|
sl@0
|
112 |
|
sl@0
|
113 |
TInt CWin32Stream::StreamName(TInt aStream, TDes& aBuf)
|
sl@0
|
114 |
{
|
sl@0
|
115 |
switch (aStream)
|
sl@0
|
116 |
{
|
sl@0
|
117 |
case Kstdin:
|
sl@0
|
118 |
aBuf=_L("stdin"); break;
|
sl@0
|
119 |
case Kstdout:
|
sl@0
|
120 |
aBuf=_L("stdout"); break;
|
sl@0
|
121 |
case Kstderr:
|
sl@0
|
122 |
aBuf=_L("stderr"); break;
|
sl@0
|
123 |
default:
|
sl@0
|
124 |
return KErrArgument;
|
sl@0
|
125 |
}
|
sl@0
|
126 |
return KErrNone;
|
sl@0
|
127 |
}
|
sl@0
|
128 |
|
sl@0
|
129 |
struct rendezvous
|
sl@0
|
130 |
{
|
sl@0
|
131 |
TRequestStatus* iStatus;
|
sl@0
|
132 |
TInt iStream;
|
sl@0
|
133 |
RThread iCaller;
|
sl@0
|
134 |
TBuf<8> iStreamName;
|
sl@0
|
135 |
};
|
sl@0
|
136 |
|
sl@0
|
137 |
void CWin32Stream::StartServer(TInt aStream)
|
sl@0
|
138 |
//
|
sl@0
|
139 |
// Static function which spawns a server thread
|
sl@0
|
140 |
//
|
sl@0
|
141 |
{
|
sl@0
|
142 |
TRequestStatus status(KRequestPending);
|
sl@0
|
143 |
struct rendezvous rv;
|
sl@0
|
144 |
rv.iStatus=&status;
|
sl@0
|
145 |
rv.iStream=aStream;
|
sl@0
|
146 |
TInt err=StreamName(aStream,rv.iStreamName);
|
sl@0
|
147 |
if (err!=KErrNone)
|
sl@0
|
148 |
return;
|
sl@0
|
149 |
err=rv.iCaller.Duplicate(RThread(),EOwnerProcess);
|
sl@0
|
150 |
if (err!=KErrNone)
|
sl@0
|
151 |
return;
|
sl@0
|
152 |
RThread server;
|
sl@0
|
153 |
err=server.Create(rv.iStreamName,ThreadFunction,2048,4096,65536,(TAny*)&rv,EOwnerProcess);
|
sl@0
|
154 |
if (err==KErrNone)
|
sl@0
|
155 |
{
|
sl@0
|
156 |
server.Resume();
|
sl@0
|
157 |
User::WaitForRequest(status);
|
sl@0
|
158 |
server.Close();
|
sl@0
|
159 |
}
|
sl@0
|
160 |
rv.iCaller.Close();
|
sl@0
|
161 |
}
|
sl@0
|
162 |
|
sl@0
|
163 |
TInt CWin32Stream::ThreadFunction(TAny* aPtr)
|
sl@0
|
164 |
{
|
sl@0
|
165 |
struct rendezvous* rvp=(struct rendezvous*)aPtr;
|
sl@0
|
166 |
TInt err=KErrNoMemory;
|
sl@0
|
167 |
CWin32Stream* stream = new CWin32Stream();
|
sl@0
|
168 |
if (stream!=0)
|
sl@0
|
169 |
err=stream->Init(rvp->iStream, rvp->iStreamName);
|
sl@0
|
170 |
rvp->iCaller.RequestComplete(rvp->iStatus,err); // let the caller continue
|
sl@0
|
171 |
if (err==KErrNone)
|
sl@0
|
172 |
{
|
sl@0
|
173 |
FOREVER
|
sl@0
|
174 |
stream->HandleMessage();
|
sl@0
|
175 |
}
|
sl@0
|
176 |
else
|
sl@0
|
177 |
{
|
sl@0
|
178 |
delete stream;
|
sl@0
|
179 |
}
|
sl@0
|
180 |
return err;
|
sl@0
|
181 |
}
|
sl@0
|
182 |
|
sl@0
|
183 |
TInt CWin32Stream::Init(TInt aStream, const TDesC& aStreamName)
|
sl@0
|
184 |
{
|
sl@0
|
185 |
iHandle = GetStdHandle((STD_INPUT_HANDLE)-(int)aStream);
|
sl@0
|
186 |
if (iHandle==INVALID_HANDLE_VALUE)
|
sl@0
|
187 |
return KErrNotFound;
|
sl@0
|
188 |
|
sl@0
|
189 |
#ifdef ESTW32_LOGGING
|
sl@0
|
190 |
static char* logs[3]={ "x:\\stdin.log", "x:\\stdout.log", "x:\\stderr.log"};
|
sl@0
|
191 |
iLogHandle=CreateFile(logs[aStream], GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
sl@0
|
192 |
#else
|
sl@0
|
193 |
iLogHandle=INVALID_HANDLE_VALUE;
|
sl@0
|
194 |
#endif
|
sl@0
|
195 |
|
sl@0
|
196 |
return iServer.CreateGlobal(aStreamName);
|
sl@0
|
197 |
}
|
sl@0
|
198 |
|
sl@0
|
199 |
void CWin32Stream::HandleMessage()
|
sl@0
|
200 |
{
|
sl@0
|
201 |
iServer.Receive(iMessage);
|
sl@0
|
202 |
TInt err=KErrNone;
|
sl@0
|
203 |
TInt f=iMessage.Function();
|
sl@0
|
204 |
switch (f)
|
sl@0
|
205 |
{
|
sl@0
|
206 |
case RMessage2::EConnect:
|
sl@0
|
207 |
case RMessage2::EDisConnect:
|
sl@0
|
208 |
// RServer2 connection management - nothing interesting to be done
|
sl@0
|
209 |
break;
|
sl@0
|
210 |
|
sl@0
|
211 |
case EWin32Read:
|
sl@0
|
212 |
err=ReadStream(iMessage);
|
sl@0
|
213 |
break;
|
sl@0
|
214 |
case EWin32Write:
|
sl@0
|
215 |
err=WriteStream(iMessage);
|
sl@0
|
216 |
break;
|
sl@0
|
217 |
case EWin32Flush:
|
sl@0
|
218 |
FlushStream();
|
sl@0
|
219 |
break;
|
sl@0
|
220 |
|
sl@0
|
221 |
default:
|
sl@0
|
222 |
err=KErrNotSupported;
|
sl@0
|
223 |
break;
|
sl@0
|
224 |
}
|
sl@0
|
225 |
iMessage.Complete(err);
|
sl@0
|
226 |
}
|
sl@0
|
227 |
|
sl@0
|
228 |
TInt CWin32Stream::ReadStream(RMessage2& aMessage)
|
sl@0
|
229 |
{
|
sl@0
|
230 |
TDes8* bufDes = (TDes8*)(aMessage.Ptr0());
|
sl@0
|
231 |
int length = aMessage.Int1();
|
sl@0
|
232 |
unsigned long nbytes;
|
sl@0
|
233 |
|
sl@0
|
234 |
if (ReadFile(iHandle, (TAny*)(bufDes->Ptr()), length, &nbytes, 0) && nbytes>0)
|
sl@0
|
235 |
{
|
sl@0
|
236 |
bufDes->SetLength(nbytes);
|
sl@0
|
237 |
return KErrNone;
|
sl@0
|
238 |
}
|
sl@0
|
239 |
return MapWin32Error(KErrEof);
|
sl@0
|
240 |
}
|
sl@0
|
241 |
|
sl@0
|
242 |
TInt CWin32Stream::WriteStream(RMessage2& aMessage)
|
sl@0
|
243 |
{
|
sl@0
|
244 |
TDesC8* bufDes = (TDesC8*)(aMessage.Ptr0());
|
sl@0
|
245 |
int length = aMessage.Int1();
|
sl@0
|
246 |
int offset = 0;
|
sl@0
|
247 |
unsigned long nbytes;
|
sl@0
|
248 |
|
sl@0
|
249 |
#ifdef ESTW32_LOGGING
|
sl@0
|
250 |
WriteFile(iLogHandle, bufDes->Ptr(), length, &nbytes, 0);
|
sl@0
|
251 |
FlushFileBuffers(iLogHandle);
|
sl@0
|
252 |
#endif
|
sl@0
|
253 |
|
sl@0
|
254 |
while (length>offset)
|
sl@0
|
255 |
{
|
sl@0
|
256 |
if (!WriteFile(iHandle, bufDes->Ptr()+offset, length-offset, &nbytes, 0))
|
sl@0
|
257 |
return MapWin32Error(KErrEof);
|
sl@0
|
258 |
offset+=nbytes;
|
sl@0
|
259 |
}
|
sl@0
|
260 |
return KErrNone;
|
sl@0
|
261 |
}
|
sl@0
|
262 |
|
sl@0
|
263 |
void CWin32Stream::FlushStream()
|
sl@0
|
264 |
{
|
sl@0
|
265 |
FlushFileBuffers(iHandle); // don't care if it works or not
|
sl@0
|
266 |
}
|
sl@0
|
267 |
|
sl@0
|
268 |
#include <winerror.h>
|
sl@0
|
269 |
|
sl@0
|
270 |
TInt CWin32Stream::MapWin32Error(TInt aDefault)
|
sl@0
|
271 |
{
|
sl@0
|
272 |
switch (GetLastError())
|
sl@0
|
273 |
{
|
sl@0
|
274 |
case ERROR_INVALID_HANDLE:
|
sl@0
|
275 |
return KErrBadHandle;
|
sl@0
|
276 |
case ERROR_HANDLE_EOF:
|
sl@0
|
277 |
return KErrEof;
|
sl@0
|
278 |
}
|
sl@0
|
279 |
return aDefault;
|
sl@0
|
280 |
}
|