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