|
1 /** |
|
2 * Copyright (c) 2010 Sasken Communication Technologies Ltd. |
|
3 * 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 * Chandradeep Gandhi, Sasken Communication Technologies Ltd - Initial contribution |
|
11 * |
|
12 * Contributors: |
|
13 * Manasij Roy, Nalina Hariharan |
|
14 */ |
|
15 |
|
16 |
|
17 #include <e32cmn.h> |
|
18 #include <QtGlobal> |
|
19 #include <e32svr.h> |
|
20 #include <e32base.h> |
|
21 #include <QByteArray> |
|
22 #include <qdebug.h> |
|
23 |
|
24 #include "smfclientsymbian.h" |
|
25 |
|
26 // Function Declaration - For starting the server process |
|
27 static TInt StartServerL(); |
|
28 static TInt CreateServerProcessL(); |
|
29 |
|
30 |
|
31 CSmfClientSymbian* CSmfClientSymbian::NewL(smfObserver* aObserver ) |
|
32 { |
|
33 CSmfClientSymbian* self = NewLC( aObserver ); |
|
34 CleanupStack::Pop( self ); |
|
35 return( self ) ; |
|
36 } |
|
37 |
|
38 CSmfClientSymbian* CSmfClientSymbian::NewLC(smfObserver* aObserver ) |
|
39 { |
|
40 CSmfClientSymbian* self = new ( ELeave ) CSmfClientSymbian( aObserver ); |
|
41 CleanupStack::PushL( self ); |
|
42 self->ConstructL(); |
|
43 return self; |
|
44 } |
|
45 |
|
46 CSmfClientSymbian::CSmfClientSymbian(smfObserver* aObserver) |
|
47 : iObserver(aObserver), |
|
48 CActive( EPriorityStandard ), |
|
49 iDataPtr(NULL, 0, 0) |
|
50 { |
|
51 CActiveScheduler::Add(this); |
|
52 } |
|
53 |
|
54 void CSmfClientSymbian::ConstructL() |
|
55 { |
|
56 qDebug()<<"Inside CSmfClientSymbian::ConstructL()"; |
|
57 User::LeaveIfError(iSession.connectToServer()); |
|
58 } |
|
59 |
|
60 CSmfClientSymbian::~CSmfClientSymbian() |
|
61 { |
|
62 qDebug()<<"~CSmfClientSymbian"; |
|
63 Cancel(); // Causes call to DoCancel() |
|
64 iSession.Close(); |
|
65 } |
|
66 |
|
67 void CSmfClientSymbian::DoCancel() |
|
68 { |
|
69 Cancel(); |
|
70 } |
|
71 |
|
72 TInt CSmfClientSymbian::RunError(TInt aError) |
|
73 { |
|
74 qDebug()<<"Inside CSmfClientSymbian::RunError(), error = "<<aError; |
|
75 return KErrNone; |
|
76 } |
|
77 |
|
78 void CSmfClientSymbian::RunL() |
|
79 { |
|
80 qDebug()<<"Inside CSmfClientSymbian::RunL()"; |
|
81 qDebug()<<"iStatus = "<<iStatus.Int(); |
|
82 |
|
83 switch ( iStatus.Int() ) |
|
84 { |
|
85 case KErrCancel: |
|
86 // The request was canceled |
|
87 qDebug()<<"KErrCancel"; |
|
88 break ; |
|
89 |
|
90 case KErrNotReady: |
|
91 qDebug()<<"KErrNotReady"; |
|
92 break; |
|
93 |
|
94 default: |
|
95 { |
|
96 qDebug()<<"RunL :- default"; |
|
97 //This contains error followed by actual data |
|
98 QByteArray receivedData(reinterpret_cast<const char*>(iSession.iDataPtr8.Ptr()),iSession.iDataPtr8.Length()); |
|
99 qDebug()<<"receivedData size = "<<receivedData.size(); |
|
100 |
|
101 SmfError errVal; |
|
102 int errInt; |
|
103 QByteArray data; |
|
104 QDataStream reader(&receivedData,QIODevice::ReadOnly); |
|
105 reader>>errInt; |
|
106 qDebug()<<"errInt = "<<errInt; |
|
107 |
|
108 errVal = (SmfError)errInt; |
|
109 reader>>data; |
|
110 qDebug()<<"data size = "<<data.size(); |
|
111 |
|
112 SmfRequestTypeID opcode = (SmfRequestTypeID)iSession.getLastRequest(); |
|
113 if(iObserver) |
|
114 { |
|
115 iObserver->resultsAvailable(data,opcode,errVal); |
|
116 } |
|
117 } |
|
118 break; |
|
119 } |
|
120 } |
|
121 |
|
122 // Sync request for server other than getservices |
|
123 QByteArray CSmfClientSymbian::sendRequest(QString aInterfaceName, |
|
124 SmfRequestTypeID requestType, |
|
125 TInt aMaxAllocation, |
|
126 QByteArray& aSerializedData) |
|
127 { |
|
128 qDebug()<<"Inside CSmfClientSymbian::sendRequest() for intf = "<<aInterfaceName; |
|
129 |
|
130 //Gets data synchronously from the server |
|
131 TPtr8 symbianBuf(iSession.sendSyncRequest(aInterfaceName,requestType, aMaxAllocation, aSerializedData)); |
|
132 //convert this into bytearray |
|
133 QByteArray receivedData(reinterpret_cast<const char*>(symbianBuf.Ptr()),symbianBuf.Length()); |
|
134 return receivedData; |
|
135 } |
|
136 |
|
137 QByteArray CSmfClientSymbian::sendSyncRequest(QString aInterfaceName, |
|
138 SmfRequestTypeID requestType,TInt maxSize, |
|
139 QByteArray& aSerializedData ) |
|
140 { |
|
141 //This will be a synchronous request |
|
142 //note session is opened in ctor and closed in dtor |
|
143 qDebug()<<"Inside CSmfClientSymbian::sendSyncRequest()"; |
|
144 qDebug()<<"Interface name = "<<aInterfaceName; |
|
145 |
|
146 //Gets data synchronously from the server |
|
147 TPtr8 symbianBuf(iSession.sendSyncRequest(aInterfaceName,requestType,maxSize, aSerializedData)); |
|
148 //convert this into bytearray |
|
149 QByteArray receivedData(reinterpret_cast<const char*>(symbianBuf.Ptr()),symbianBuf.Length()); |
|
150 return receivedData; |
|
151 } |
|
152 |
|
153 QByteArray CSmfClientSymbian::sendDSMSyncRequest(SmfRequestTypeID requestType,QByteArray& aSerializedData,SmfError& aErr,TInt maxSize) |
|
154 { |
|
155 Q_UNUSED(aErr) |
|
156 |
|
157 qDebug()<<"CSmfClientSymbian::sendDSMSyncRequest for : "<<requestType; |
|
158 SmfError err = SmfNoError; |
|
159 //Gets data synchronously from the server |
|
160 TPtr8 symbianBuf(iSession.sendDSMSyncRequest(requestType,aSerializedData,err,maxSize)); |
|
161 //convert this into bytearray |
|
162 QByteArray receivedData(reinterpret_cast<const char*>(symbianBuf.Ptr()),symbianBuf.Length()); |
|
163 qDebug()<<"receivedData size="<<receivedData.size(); |
|
164 return receivedData; |
|
165 } |
|
166 |
|
167 TInt CSmfClientSymbian::sendRequest( QByteArray& aSerializedData, QString aInterfaceName, |
|
168 SmfRequestTypeID requestType, TInt aMaxAllocation) |
|
169 { |
|
170 //RSessionBase objects sendreceive is called |
|
171 iSession.sendAsyncRequest(aSerializedData,aInterfaceName,requestType,iStatus,aMaxAllocation); |
|
172 SetActive(); |
|
173 |
|
174 return KErrNone; |
|
175 } |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 RSmfClientSymbianSession::RSmfClientSymbianSession() |
|
181 :iDataPtr8(NULL, 0, 0),iDataPtr16(NULL,0), |
|
182 iIntfNamePtr(NULL,0),iIntfNamePtr8(NULL,0), |
|
183 iPtrProvider(NULL,0),iPtrProvider8(NULL,0), |
|
184 iPtrToXtraInfo8(NULL,0),iPtrToXtraInfo(NULL, 0), |
|
185 iPtr8ToSlot0(NULL,0) |
|
186 { |
|
187 // No implementation required |
|
188 } |
|
189 |
|
190 TInt RSmfClientSymbianSession::connectToServer() |
|
191 { |
|
192 qDebug()<<"Inside RSmfClientSymbianSession::connectToServer()"; |
|
193 |
|
194 TInt error = ::StartServerL(); |
|
195 qDebug()<<"StartServerL = "<<error; |
|
196 |
|
197 if ( KErrNone == error ) |
|
198 { |
|
199 error = CreateSession(KSmfServerName, |
|
200 Version(), |
|
201 4 ); // 4 slots used |
|
202 qDebug()<<"CreateSession = "<<error; |
|
203 } |
|
204 return error; |
|
205 } |
|
206 |
|
207 TPtr8 RSmfClientSymbianSession::sendSyncRequest(QByteArray& aSerializedData, |
|
208 QString aInterfaceName, SmfRequestTypeID aRequestType, TInt maxSize) |
|
209 { |
|
210 qDebug()<<"Inside RSmfClientSymbianSession::sendSyncRequest() for plugins"; |
|
211 qDebug()<<"iInterfaceName = "<<aInterfaceName; |
|
212 iLastRequest = aRequestType; |
|
213 /** |
|
214 * The message body consists of.- |
|
215 * 1. Serialized data to server SmfProvider+page information+extra information |
|
216 * 2. Interface name as string ("org.symbian.smf.client.gallery") |
|
217 * 3. Data pointer to be filled by serialized data(QList<smfProvider>) |
|
218 * 4. Xtra information if any |
|
219 */ |
|
220 if(iProviderBuf8) |
|
221 { |
|
222 delete iProviderBuf8; |
|
223 iProviderBuf8 = NULL; |
|
224 } |
|
225 iProviderBuf8 = HBufC8::NewL(aSerializedData.size()); |
|
226 iPtrProvider8.Set(iProviderBuf8->Des()); |
|
227 iPtrProvider8.Copy(reinterpret_cast<const TText8*>(aSerializedData.constData()),aSerializedData.length()); |
|
228 |
|
229 //convert the QByteArray into TPtr |
|
230 TPtrC8 ptrSlot0(reinterpret_cast<const TText8*>(aSerializedData.constData()),aSerializedData.length()); |
|
231 qDebug()<<"ptrSlot0 size = "<<ptrSlot0.Size(); |
|
232 |
|
233 |
|
234 iInterfaceNamebyte.clear(); |
|
235 //Pass serialized QString for interface name |
|
236 QDataStream intfNameStream(&iInterfaceNamebyte,QIODevice::WriteOnly); |
|
237 intfNameStream<<aInterfaceName; |
|
238 qDebug()<<"iInterfaceNamebyte size = "<<iInterfaceNamebyte.size(); |
|
239 if(iIntfNameBuffer8) |
|
240 { |
|
241 delete iIntfNameBuffer8; |
|
242 iIntfNameBuffer8 = NULL; |
|
243 } |
|
244 iIntfNameBuffer8 = HBufC8::NewL(iInterfaceNamebyte.size()); |
|
245 iIntfNamePtr8.Set(iIntfNameBuffer8->Des()); |
|
246 iIntfNamePtr8.Copy(reinterpret_cast<const TText8*>(iInterfaceNamebyte.constData()),iInterfaceNamebyte.length()); |
|
247 qDebug()<<"After iIntfNamePtr8.Copy"; |
|
248 |
|
249 if(iBuffer8) |
|
250 { |
|
251 delete iBuffer8; |
|
252 iBuffer8 = NULL; |
|
253 } |
|
254 iBuffer8 = HBufC8::NewL(maxSize); |
|
255 iDataPtr8.Set(iBuffer8->Des()); |
|
256 qDebug()<<"After iDataPtr8.Set"; |
|
257 |
|
258 TIpcArgs args; |
|
259 |
|
260 //filling the slots |
|
261 args.Set(0, &iPtrProvider8); |
|
262 args.Set(1, &iIntfNamePtr8); |
|
263 args.Set(2, &iDataPtr8); |
|
264 qDebug()<<"After setting 0,1,2 slots"; |
|
265 |
|
266 TInt err(KErrBadHandle); |
|
267 qDebug()<<"Before handle"; |
|
268 if (Handle()) |
|
269 { |
|
270 err = KErrNone; |
|
271 qDebug()<<"Before sendreceive"; |
|
272 //synchronous request |
|
273 TInt sendErr = SendReceive(aRequestType, args); |
|
274 if(sendErr) |
|
275 qDebug()<<"SendReceive error = "<<sendErr; |
|
276 } |
|
277 return iDataPtr8; |
|
278 } |
|
279 |
|
280 |
|
281 |
|
282 TPtr8 RSmfClientSymbianSession::sendSyncRequest(QString aInterfaceName, |
|
283 SmfRequestTypeID aRequestType, |
|
284 TInt maxSize, |
|
285 QByteArray& aSerializedData) |
|
286 { |
|
287 qDebug()<<"Inside RSmfClientSymbianSession::sendSyncRequest()"; |
|
288 qDebug()<<"aInterfaceName = "<<aInterfaceName; |
|
289 |
|
290 iLastRequest = aRequestType; |
|
291 /** |
|
292 * The message body consists of.- |
|
293 * slot 0 = SmfProvider + argument flag + argument + etc |
|
294 * slot 1 = Interface name serialized |
|
295 * slot 2 = Data pointer to be filled by server |
|
296 * slot 3 = not used now |
|
297 */ |
|
298 |
|
299 //Convert the interface name into TPtr |
|
300 //lets pass serialized QString |
|
301 iInterfaceNamebyte.clear(); |
|
302 QDataStream intfNameStream(&iInterfaceNamebyte,QIODevice::WriteOnly); |
|
303 intfNameStream<<aInterfaceName; |
|
304 qDebug()<<"iInterfaceNamebyte size = "<<iInterfaceNamebyte.size(); |
|
305 if(iIntfNameBuffer8) |
|
306 { |
|
307 delete iIntfNameBuffer8; |
|
308 iIntfNameBuffer8 = NULL; |
|
309 } |
|
310 iIntfNameBuffer8 = HBufC8::NewL(iInterfaceNamebyte.size()); |
|
311 iIntfNamePtr8.Set(iIntfNameBuffer8->Des()); |
|
312 iIntfNamePtr8.Copy(reinterpret_cast<TUint8*>(iInterfaceNamebyte.data()),iInterfaceNamebyte.length()); |
|
313 qDebug()<<"iIntfNamePtr8 size = "<<iIntfNamePtr8.Size(); |
|
314 |
|
315 if(iBuffer8) |
|
316 { |
|
317 delete iBuffer8; |
|
318 iBuffer8 = NULL; |
|
319 } |
|
320 qDebug()<<"Allocated for output = "<<maxSize; |
|
321 iBuffer8 = HBufC8::NewL(maxSize); |
|
322 iDataPtr8.Set(iBuffer8->Des()); |
|
323 qDebug()<<"After iDataPtr8.Set"; |
|
324 |
|
325 if(iProviderBuf8) |
|
326 { |
|
327 delete iProviderBuf8; |
|
328 iProviderBuf8 = NULL; |
|
329 } |
|
330 iProviderBuf8 = HBufC8::NewL(aSerializedData.size()); |
|
331 iPtrProvider8.Set(iProviderBuf8->Des()); |
|
332 iPtrProvider8.Copy(reinterpret_cast<const TText8*>(aSerializedData.constData()),aSerializedData.length()); |
|
333 |
|
334 //convert the QByteArray into TPtr |
|
335 TPtrC8 ptrSlot0(reinterpret_cast<const TText8*>(aSerializedData.constData()),aSerializedData.length()); |
|
336 qDebug()<<"ptrSlot0 size = "<<ptrSlot0.Size(); |
|
337 |
|
338 TIpcArgs args; |
|
339 args.Set(0, &iPtrProvider8); |
|
340 args.Set(1, &iIntfNamePtr8); |
|
341 args.Set(2, &iDataPtr8); |
|
342 |
|
343 TInt err(KErrBadHandle); |
|
344 qDebug()<<"Before handle"; |
|
345 if (Handle()) |
|
346 { |
|
347 err = KErrNone; |
|
348 qDebug()<<"Before sendreceive"; |
|
349 TInt sendErr = SendReceive(aRequestType, args); |
|
350 if(sendErr) |
|
351 qDebug()<<"SendReceive error = "<<sendErr; |
|
352 } |
|
353 return iDataPtr8; |
|
354 } |
|
355 |
|
356 /** |
|
357 * Sends sync DSM request to the Smf server |
|
358 */ |
|
359 TPtr8 RSmfClientSymbianSession::sendDSMSyncRequest(SmfRequestTypeID aRequestType, |
|
360 QByteArray& aSerializedData, SmfError aErr, TInt maxSize) |
|
361 { |
|
362 /** |
|
363 * Slot 0:- Data to be passed to DSM |
|
364 * Slot 1:- Data returned from DSM |
|
365 * Slot 2:- Error |
|
366 */ |
|
367 qDebug()<<"Inside RSmfClientSymbianSession::sendDSMSyncRequest()"; |
|
368 iLastRequest = aRequestType; |
|
369 if(iSlot0Buffer8) |
|
370 { |
|
371 delete iSlot0Buffer8; |
|
372 iSlot0Buffer8 = NULL; |
|
373 } |
|
374 iSlot0Buffer8 = HBufC8::NewL(aSerializedData.size()); |
|
375 iPtr8ToSlot0.Set(iSlot0Buffer8->Des()); |
|
376 |
|
377 if(iBuffer8) |
|
378 { |
|
379 delete iBuffer8; |
|
380 iBuffer8 = NULL; |
|
381 } |
|
382 iBuffer8 = HBufC8::NewL(maxSize); |
|
383 iDataPtr8.Set(iBuffer8->Des()); |
|
384 |
|
385 TIpcArgs args; |
|
386 args.Set(0, &iPtr8ToSlot0); |
|
387 args.Set(1, &iDataPtr8); |
|
388 iDSMErr.Zero(); |
|
389 args.Set(2,&iDSMErr); |
|
390 |
|
391 TInt sendErr = SendReceive(aRequestType,args); |
|
392 qDebug()<<"DSM SendReceive = "<<sendErr; |
|
393 TInt numIndex; |
|
394 TLex iLex(iDSMErr); |
|
395 |
|
396 iLex.Val(numIndex); |
|
397 aErr = (SmfError)numIndex; |
|
398 return iDataPtr8; |
|
399 } |
|
400 |
|
401 /** |
|
402 * sendAsyncRequest() |
|
403 * Calls SendReceive() after converting into symbian descriptors |
|
404 */ |
|
405 void RSmfClientSymbianSession::sendAsyncRequest(QByteArray& aSerializedData, |
|
406 QString aInterfaceName, |
|
407 SmfRequestTypeID aRequestType, |
|
408 TRequestStatus& aStatus, |
|
409 TInt aMaxAllocation ) |
|
410 { |
|
411 /** |
|
412 * The message body consists of.- |
|
413 * slot 0 = SmfProvider + argument flag + argument + etc |
|
414 * slot 1 = Interface name serialized |
|
415 * slot 2 = Data pointer to be filled by server |
|
416 * slot 3 = not used now |
|
417 */ |
|
418 qDebug()<<"Inside RSmfClientSymbianSession::sendAsyncRequest()"; |
|
419 qDebug()<<"iInterfaceName = "<<aInterfaceName; |
|
420 iLastRequest = aRequestType; |
|
421 |
|
422 if(iProviderBuf8) |
|
423 { |
|
424 delete iProviderBuf8; |
|
425 iProviderBuf8 = NULL; |
|
426 } |
|
427 iProviderBuf8 = HBufC8::NewL(aSerializedData.size()); |
|
428 iPtrProvider8.Set(iProviderBuf8->Des()); |
|
429 iPtrProvider8.Copy(reinterpret_cast<const TText8*>(aSerializedData.constData()),aSerializedData.length()); |
|
430 |
|
431 //convert the QByteArray into TPtr |
|
432 TPtrC8 ptrSlot0(reinterpret_cast<const TText8*>(aSerializedData.constData()),aSerializedData.length()); |
|
433 qDebug()<<"ptrSlot0 size = "<<ptrSlot0.Size(); |
|
434 |
|
435 //Convert the interface name into TPtr |
|
436 //Pass serialized QString for interface name |
|
437 iInterfaceNamebyte.clear(); |
|
438 QDataStream intfNameStream(&iInterfaceNamebyte,QIODevice::WriteOnly); |
|
439 intfNameStream<<aInterfaceName; |
|
440 qDebug()<<"iInterfaceNamebyte size = "<<iInterfaceNamebyte.size(); |
|
441 if(iIntfNameBuffer8) |
|
442 { |
|
443 delete iIntfNameBuffer8; |
|
444 iIntfNameBuffer8 = NULL; |
|
445 } |
|
446 iIntfNameBuffer8 = HBufC8::NewL(iInterfaceNamebyte.size()); |
|
447 iIntfNamePtr8.Set(iIntfNameBuffer8->Des()); |
|
448 iIntfNamePtr8.Copy(reinterpret_cast<const TText8*>(iInterfaceNamebyte.constData()),iInterfaceNamebyte.length()); |
|
449 qDebug()<<"After iIntfNamePtr8.Copy"; |
|
450 |
|
451 if(iBuffer8) |
|
452 { |
|
453 delete iBuffer8; |
|
454 iBuffer8 = NULL; |
|
455 } |
|
456 iBuffer8 = HBufC8::NewL(aMaxAllocation); |
|
457 iDataPtr8.Set(iBuffer8->Des()); |
|
458 qDebug()<<"After iDataPtr.Set"; |
|
459 |
|
460 |
|
461 TIpcArgs args; |
|
462 |
|
463 //filling the slots |
|
464 args.Set(0, &iPtrProvider8); |
|
465 args.Set(1, &iIntfNamePtr8); |
|
466 args.Set(2, &iDataPtr8); |
|
467 qDebug()<<"After setting 0,1,2 slots"; |
|
468 |
|
469 TInt err(KErrBadHandle); |
|
470 qDebug()<<"Before Handle()"; |
|
471 if (Handle()) |
|
472 { |
|
473 err = KErrNone; |
|
474 qDebug()<<"Before sendreceive"; |
|
475 SendReceive(aRequestType, args, aStatus); |
|
476 } |
|
477 } |
|
478 |
|
479 // ----------------------------------------------------------------------------- |
|
480 // CreateServerProcessL() |
|
481 // Creates a server process |
|
482 // ----------------------------------------------------------------------------- |
|
483 // |
|
484 static TInt CreateServerProcessL() |
|
485 { |
|
486 TInt result; |
|
487 TUid KSmfServerUID3 = { 0xE5027327 }; |
|
488 const TUidType serverUid( KNullUid, KNullUid, KSmfServerUID3 ); |
|
489 |
|
490 RProcess server; |
|
491 |
|
492 result = server.Create( KSmfServerFilename, KNullDesC, serverUid ); |
|
493 if ( result != KErrNone ) |
|
494 { |
|
495 return result; |
|
496 } |
|
497 |
|
498 server.Resume(); |
|
499 server.Close(); |
|
500 return KErrNone; |
|
501 } |
|
502 |
|
503 // ----------------------------------------------------------------------------- |
|
504 // StartServerL() |
|
505 // Starts the server - Internally creates a server process |
|
506 // ----------------------------------------------------------------------------- |
|
507 // |
|
508 static TInt StartServerL() |
|
509 { |
|
510 TInt result; |
|
511 |
|
512 TFindServer findSmfServer( KSmfServerFilename ); |
|
513 TFullName name; |
|
514 |
|
515 result = findSmfServer.Next( name ); |
|
516 |
|
517 if ( result == KErrNone ) |
|
518 { |
|
519 // Server already running |
|
520 return KErrNone; |
|
521 } |
|
522 |
|
523 RSemaphore semaphore; |
|
524 result = semaphore.CreateGlobal( KSmfServerSemaphoreName, 0 ); |
|
525 |
|
526 if ( result != KErrNone ) |
|
527 { |
|
528 return result; |
|
529 } |
|
530 |
|
531 result = CreateServerProcessL(); |
|
532 qDebug()<<"CreateServerProcessL = "<<result; |
|
533 |
|
534 if ( result != KErrNone ) |
|
535 { |
|
536 return result; |
|
537 } |
|
538 |
|
539 semaphore.Wait(); |
|
540 semaphore.Close(); |
|
541 |
|
542 return KErrNone; |
|
543 } |