|
1 // iocons.cpp |
|
2 // |
|
3 // Copyright (c) 2006 - 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 |
|
13 #include <fshell/iocli.h> |
|
14 #include <fshell/consoleextensions.h> |
|
15 #include "iocons.h" |
|
16 #include <fshell/ioutils.h> |
|
17 #include <fshell/common.mmh> |
|
18 #ifdef FSHELL_MEMORY_ACCESS_SUPPORT |
|
19 #include <fshell/memoryaccess.h> |
|
20 #endif |
|
21 |
|
22 // This constant is used to find the PIPS Stdio Server CServer2 object in the situation |
|
23 // where iocons in running in the stdioserver.exe process. Normally, when iocons calls |
|
24 // RIo(Read|Write)Handle::Open(RIoSession&), iosrv looks to see if it hand any read or |
|
25 // write objects that belong to the calling thread. Note, when fshell creates a new process |
|
26 // it creates a set of read and write objects inside iosrv, and assigns them as being owned |
|
27 // by the main thread of the new process. However, in the case of PIPS, the main thread |
|
28 // of the process that fshell creates isn't the one that opens the console. This is done |
|
29 // from the context of the sdioserver.exe process. To cater for this, iocons has a special |
|
30 // behaviour when its running in the context of sdioserver.exe. This involves finding the |
|
31 // server's CServer2 sub-class object, and using this to retrieve the current RMessage2 |
|
32 // object. From this, the client's thread id can be found. This is passed into a different |
|
33 // RIo(Read|Write)Handle::Open overload that attempt to open a handle using the specified |
|
34 // thread id (not that which iocons is currently running in). If fshell created the process |
|
35 // this should return without error, in which case the PIPS process will be able to share |
|
36 // fshell's console (or take part in a pipe-line that it created). If not, then the old |
|
37 // behaviour of creating a new console will proceed. |
|
38 const TInt KPipsStdioServerAllocPos = 5; |
|
39 |
|
40 |
|
41 CIoConsole::CIoConsole() |
|
42 { |
|
43 } |
|
44 |
|
45 CIoConsole::CIoConsole(RIoConsoleReadHandle& aReadHandle, RIoConsoleWriteHandle& aWriteHandle) |
|
46 { |
|
47 iReadHandle = aReadHandle; |
|
48 iWriteHandle = aWriteHandle; |
|
49 } |
|
50 |
|
51 CIoConsole::~CIoConsole() |
|
52 { |
|
53 if (iIoSession.Handle()) |
|
54 { |
|
55 // If the handle isn't set it means we don't own iReadHandle/iWriteHandle (or they haven't been constructed and we needn't close them anyway) |
|
56 iReadHandle.Close(); |
|
57 iWriteHandle.Close(); |
|
58 iConsole.Close(); |
|
59 iIoSession.Close(); |
|
60 } |
|
61 } |
|
62 |
|
63 TInt CIoConsole::Create(const TDesC& aTitle, TSize aSize) |
|
64 { |
|
65 // This should only be called via iocons, ie when the zero arguments constructor was used. |
|
66 // When the 2-arg constructor is used, the console is fully constructed and Create should not be called |
|
67 TInt err = iIoSession.Connect(); |
|
68 if (err == KErrNone) |
|
69 { |
|
70 // See if iosrv has any handles ready for us |
|
71 err = iReadHandle.Open(iIoSession); |
|
72 if (err) |
|
73 { |
|
74 // If not, check if we're being opened from the stdioserver on behalf of the client PIPS exe |
|
75 TThreadId clientThreadId; |
|
76 if (FindClientThreadId(clientThreadId) == KErrNone) |
|
77 { |
|
78 err = iReadHandle.Open(iIoSession, clientThreadId); |
|
79 if (err == KErrNone) |
|
80 { |
|
81 err = iWriteHandle.Open(iIoSession, clientThreadId); |
|
82 if (err != KErrNone) |
|
83 { |
|
84 iReadHandle.Close(); |
|
85 } |
|
86 } |
|
87 } |
|
88 |
|
89 #ifdef FSHELL_MEMORY_ACCESS_SUPPORT |
|
90 if (err) |
|
91 { |
|
92 // Try and see if the thread that created us has some handles we can use, and if not, the thread that created it etc until we find one or lose track |
|
93 RMemoryAccess::LoadDriver(); |
|
94 RMemoryAccess memAccess; |
|
95 err = memAccess.Open(); |
|
96 if (!err) err = iReadHandle.Create(iIoSession); |
|
97 if (!err) iWriteHandle.Create(iIoSession); |
|
98 if (!err) |
|
99 { |
|
100 TUint creator = RThread().Id(); |
|
101 while (creator != 0) |
|
102 { |
|
103 creator = memAccess.GetThreadCreatorId(creator); |
|
104 err = iReadHandle.DuplicateHandleFromThread(TThreadId(creator)); |
|
105 if (err == KErrNone) |
|
106 { |
|
107 // Found one - open the writer too... |
|
108 err = iWriteHandle.DuplicateHandleFromThread(TThreadId(creator)); |
|
109 break; // Stop looking if we found one |
|
110 } |
|
111 } |
|
112 memAccess.Close(); |
|
113 } |
|
114 if (err) |
|
115 { |
|
116 iReadHandle.Close(); |
|
117 iWriteHandle.Close(); |
|
118 } |
|
119 } |
|
120 #endif |
|
121 |
|
122 if (err) |
|
123 { |
|
124 // If all else fails, create a new console |
|
125 err = CreateNewConsole(aTitle, aSize); |
|
126 } |
|
127 } |
|
128 else |
|
129 { |
|
130 err = iWriteHandle.Open(iIoSession); |
|
131 } |
|
132 } |
|
133 if (err) |
|
134 { |
|
135 iReadHandle.Close(); |
|
136 iWriteHandle.Close(); |
|
137 iConsole.Close(); |
|
138 iIoSession.Close(); |
|
139 } |
|
140 return err; |
|
141 } |
|
142 |
|
143 TInt CIoConsole::CreateNewConsole(const TDesC& aTitle, TSize aSize) |
|
144 { |
|
145 TInt err = iConsole.Create(iIoSession, aTitle, aSize); |
|
146 if (err) return err; |
|
147 err = iReadHandle.Create(iIoSession); |
|
148 if (err) return err; |
|
149 err = iWriteHandle.Create(iIoSession); |
|
150 if (err) return err; |
|
151 err = iConsole.Attach(iReadHandle, RIoEndPoint::EForeground); |
|
152 if (err) return err; |
|
153 err = iConsole.Attach(iWriteHandle); |
|
154 if (err) return err; |
|
155 |
|
156 err = iReadHandle.SetOwner(RThread().Id()); |
|
157 if (err) return err; |
|
158 err = iWriteHandle.SetOwner(RThread().Id()); |
|
159 |
|
160 return err; |
|
161 } |
|
162 |
|
163 TBool CIoConsole::HeapWalk(TAny* aSelf, RAllocatorHelper::TCellType aCellType, TLinAddr aCellPtr, TInt) |
|
164 { |
|
165 CIoConsole* self = (CIoConsole*)aSelf; |
|
166 if (aCellType == RAllocatorHelper::EAllocation) |
|
167 { |
|
168 if (++(self->iHeapCellCount) == KPipsStdioServerAllocPos) |
|
169 { |
|
170 self->iServerAddress = (TAny*)aCellPtr; |
|
171 return EFalse; // To indicate we're finished |
|
172 } |
|
173 } |
|
174 return ETrue; // keep going |
|
175 } |
|
176 |
|
177 class CHackedServer : public CServer2 |
|
178 { |
|
179 public: |
|
180 inline CHackedServer() : CServer2(CActive::EPriorityStandard) {} // needed to shut up gcce |
|
181 inline const RMessage2& Msg() const { return Message(); } |
|
182 }; |
|
183 |
|
184 TInt CIoConsole::FindClientThreadId(TThreadId& aThreadId) |
|
185 { |
|
186 TInt err = KErrNotFound; |
|
187 _LIT(KPipsStdioServer, "stdioserver.exe*"); |
|
188 TName processName(RProcess().Name()); |
|
189 if (processName.MatchF(KPipsStdioServer) == 0) |
|
190 { |
|
191 LtkUtils::RAllocatorHelper allocHelper; |
|
192 TInt err = allocHelper.Open(&User::Allocator()); |
|
193 if (!err) err = allocHelper.Walk(&HeapWalk, this); |
|
194 allocHelper.Close(); |
|
195 if (err == KErrNone && iServerAddress) |
|
196 { |
|
197 // This means that we found the server's address (possibly). |
|
198 CHackedServer* server = (CHackedServer*)iServerAddress; |
|
199 RThread client; |
|
200 if (server->Msg().Client(client) == KErrNone) |
|
201 { |
|
202 err = KErrNone; |
|
203 aThreadId = client.Id(); |
|
204 client.Close(); |
|
205 } |
|
206 } |
|
207 } |
|
208 return err; |
|
209 } |
|
210 |
|
211 void CIoConsole::Read(TRequestStatus& aStatus) |
|
212 { |
|
213 iReadHandle.WaitForKey(aStatus); |
|
214 } |
|
215 |
|
216 void CIoConsole::ReadCancel() |
|
217 { |
|
218 iReadHandle.WaitForKeyCancel(); |
|
219 } |
|
220 |
|
221 void CIoConsole::Write(const TDesC& aDes) |
|
222 { |
|
223 iWriteHandle.Write(aDes); |
|
224 } |
|
225 |
|
226 TPoint CIoConsole::CursorPos() const |
|
227 { |
|
228 TPoint pos; |
|
229 iWriteHandle.GetCursorPos(pos); |
|
230 return pos; |
|
231 } |
|
232 |
|
233 void CIoConsole::SetCursorPosAbs(const TPoint& aPoint) |
|
234 { |
|
235 iWriteHandle.SetCursorPosAbs(aPoint); |
|
236 } |
|
237 |
|
238 void CIoConsole::SetCursorPosRel(const TPoint& aPoint) |
|
239 { |
|
240 iWriteHandle.SetCursorPosRel(aPoint); |
|
241 } |
|
242 |
|
243 void CIoConsole::SetCursorHeight(TInt aPercentage) |
|
244 { |
|
245 iWriteHandle.SetCursorHeight(aPercentage); |
|
246 } |
|
247 |
|
248 void CIoConsole::SetTitle(const TDesC& aTitle) |
|
249 { |
|
250 iWriteHandle.SetTitle(aTitle); |
|
251 } |
|
252 |
|
253 void CIoConsole::ClearScreen() |
|
254 { |
|
255 iWriteHandle.ClearScreen(); |
|
256 } |
|
257 |
|
258 void CIoConsole::ClearToEndOfLine() |
|
259 { |
|
260 iWriteHandle.ClearToEndOfLine(); |
|
261 } |
|
262 |
|
263 TSize CIoConsole::ScreenSize() const |
|
264 { |
|
265 TSize size; |
|
266 iWriteHandle.GetScreenSize(size); |
|
267 return size; |
|
268 } |
|
269 |
|
270 TKeyCode CIoConsole::KeyCode() const |
|
271 { |
|
272 return (TKeyCode)iReadHandle.KeyCode(); |
|
273 } |
|
274 |
|
275 TUint CIoConsole::KeyModifiers() const |
|
276 { |
|
277 return iReadHandle.KeyModifiers(); |
|
278 } |
|
279 |
|
280 TInt CIoConsole::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1) |
|
281 { |
|
282 return CConsoleBase::Extension_(aExtensionId, a0, a1); |
|
283 } |
|
284 |
|
285 EXPORT_C CConsoleBase* IoUtils::NewConsole() |
|
286 { |
|
287 return new CIoConsole; |
|
288 } |
|
289 |
|
290 // This is horrible, but only way to satisfy WINSCW compiler. If we define it always, we end up re-exporting typeinfo for CColorConsoleBase in armv5 which we don't want to be doing |
|
291 #ifdef __WINS__ |
|
292 void CColorConsoleBase::SetTextAttribute(TTextAttribute) |
|
293 { |
|
294 } |
|
295 #endif |
|
296 |
|
297 void CIoConsole::SetTextAttribute(TTextAttribute aAttribute) |
|
298 { |
|
299 TUint attrib = 0; |
|
300 switch (aAttribute) |
|
301 { |
|
302 case ETextAttributeNormal: |
|
303 attrib = ConsoleAttributes::ENone; |
|
304 break; |
|
305 case ETextAttributeBold: |
|
306 attrib = ConsoleAttributes::EBold; |
|
307 break; |
|
308 case ETextAttributeInverse: |
|
309 attrib = ConsoleAttributes::EInverse; |
|
310 break; |
|
311 case ETextAttributeHighlight: |
|
312 // Should highlight map to inverse? Seems slightly better than bold |
|
313 attrib = ConsoleAttributes::EInverse; |
|
314 break; |
|
315 default: |
|
316 break; |
|
317 } |
|
318 iWriteHandle.SetAttributes(attrib); // Can't do anything with the error |
|
319 } |