Проблема с CImageDecoder и RWsSession::EventReady
Здравствуйте. Прошу вашей помощи.
Суть проблемы:
Пишу приложение (без GUI), выводит на рабочий стол небольшое окошко, в котором должна отображаться картинка.
Картинка - статичное gif изображение, конвертирую в битмап с помощью CImageDecoder:
[code]
void CMyServer::LoadImage()
{
iBitmap = new(ELeave) CFbsBitmap();
CleanupStack::PushL(iBitmap);
iDecoder = CImageDecoder::FileNewL(iFs,KFileName);
iFrameInfo = iDecoder->FrameInfo(0);
iRect = iFrameInfo.iFrameCoordsInPixels;
iBitmap->Create(iRect.Size(),EColor16M);
iDecoder->Convert(&iStatus,*iBitmap,0);
iImageLoaded = ETrue;
iIsDraw = ETrue;
SetActive();
}
[/code]
Код работает, картинка отображается нормально. Проблема возникла, когда я стал писать часть кода, отвечающего за отображение картинки в режиме ожидания. Эта часть описана в том же классе, что и CImageDecoder. Вот код -
[code]
void CMyServer::WaitWgEvent()
{
iIsDraw = EFalse;
iGetEvent = ETrue;
__LOGSTR("WaitWgEvent");
iWs.EventReady(&iStatus);
SetActive();
}
[/code]
и
[code]
void CMyServer::GetWgEvent()
{
if(iStatus == KErrNone)
{
TWsEvent e;
iWs.GetEvent(e);
__LOGSTR1("event: %d",e.Type());
}
TInt WgId = iWs.GetFocusWindowGroup();
CApaWindowGroupName* gn = CApaWindowGroupName::NewLC(iWs, WgId);
__LOGSTR1("Uid: 0x%x",gn->AppUid());
if(gn->AppUid() == TUid::Uid(0x101fd64c))
{
Draw(ETrue);
}else{
Draw(EFalse);
}
}
[/code]
и
[code]
void CMyServer::RunL()
{
__LOGSTR("RunL");
if(iIsDraw)
{
Draw(ETrue);
}
if(iWaitEvent)
{
WaitWgEvent();
}
if(iGetEvent)
{
GetWgEvent();
}
}
[/code]
Собственно, проблема вот в чём. Обнаружилось падение приложения с WSERV 8, определил, что по каким-то неведомым мне причинам iStatus вовсе не равняется KErrNone, и поэтому часть кода не выполняется. Подскажите хоть в какую сторону копать, а то что-то совсем мысли кончились
Re: Проблема с CImageDecoder и RWsSession::EventReady
Так чему равнялся iStatus?
Re: Проблема с CImageDecoder и RWsSession::EventReady
[QUOTE=SQR;800650]
[code]
void CMyServer::WaitWgEvent()
{
iIsDraw = EFalse;
iGetEvent = ETrue;
__LOGSTR("WaitWgEvent");
iWs.EventReady(&iStatus);
SetActive();
}
[/code]
[/QUOTE]
нигде не указано событие, наступления которого вы ожидаете
Re: Проблема с CImageDecoder и RWsSession::EventReady
[QUOTE=truf;801380]Так чему равнялся iStatus?[/QUOTE]
[code]void CMyServer::GetWgEvent()
{
__LOGSTR1("iStatus: %d",iStatus.Int());
if(iStatus == KErrNone)
{
TWsEvent e;
iWs.GetEvent(e);
__LOGSTR1("event: %d",e.Type());
}
....[/code]
Лог:
[code]10.12.2010 21.29.19 iStatus: -2147483647[/code]
[QUOTE=popov_andrew_e;801500]нигде не указано событие, наступления которого вы ожидаете[/QUOTE]
Как тогда работает код в другом проекте?
[code]void CFgObserver::Fun()
{
iSession.EventReady(&iStatus);
SetActive();
}[/code]
И всё прекрасно работает. А тут вот косяк
Re: Проблема с CImageDecoder и RWsSession::EventReady
Показывайте код всего класса с хедером.
Я не вижу, где у вас iWaitEvent становится ETrue
Re: Проблема с CImageDecoder и RWsSession::EventReady
А в общем и так понятно,
[QUOTE]EventReady(TRequestStatus *)
IMPORT_C void EventReady(TRequestStatus *aStat);
Description
Requests standard events from the window server.
Standard events include all events except redraws and priority key events.
The client application will typically handle the completed request using the RunL() function of an active object, and in this case the request status aStat should be the iStatus member of that CActive object.
Notes:
The active object runs when an event is waiting. [B][COLOR="Red"]You should call RWsSession::GetEvent(TWsEvent &) in the RunL() function to get the event.
You should not call this function again until you've either called RWsSession::GetEvent(TWsEvent &) or RWsSession::EventReadyCancel().[/COLOR][/B] [/QUOTE]
Когда у вас срабатывает RunL, вы сначала вызываете WaitWgEvent раньше GetWgEvent, а потом тут же GetWgEvent, хотя он должен вызываться в следующем RunL(). Местами их поменять надо. Сначала должен вызываться GetEvent, и только потом - EventReady.
Re: Проблема с CImageDecoder и RWsSession::EventReady
Если окно не должно ловить события, можно воспользоваться RWsSptite из анимационных апи, он полностью синхронный. Т.е там не нужно постоянно получать эвенты от оконного сервера и обрабатывать. Плюс, только спрайты позволяют отобразить картинку с прозрачным фоном на S60 3rd - S60 3rd FP2 (на S60 5th появилась поддержка альфа-каналов в окнах, а в S^3 впрочем опять исчезла). Чтение картинки я бы тоже сихронизировал (не такая там и большая задержка). Прикрепляю пример работы со спрайтом, и сихронного чтения картинки
Чтение картинок
[CODE]
TBuf8<255> type;
GetFileType(path,type);
CImageDecoder* iImage=CImageDecoder::FileNewL(CCoeEnv::Static()->FsSession(),path,type,CImageDecoder::EOptionAlwaysThread);
BitMap = new (ELeave) CFbsBitmap;
TFrameInfo iFrameInfo = iImage->FrameInfo(0);
BitMap->Create(iFrameInfo.iOverallSizeInPixels, iFrameInfo.iFrameDisplayMode );
TRequestStatus ReqStat;
iImage->Convert(&ReqStat,*BitMap);
User::WaitForRequest(ReqStat);
delete iImage;
void CMain::GetFileType(const TDesC& aFileName, TDes8& aFileType)
{
TEntry FileEntry;
if(CCoeEnv::Static()->FsSession().Entry(aFileName,FileEntry) == KErrNone)
{
TBuf8<255> FileBuffer;
if(!FileEntry.IsDir())
{
TInt FileSize = FileEntry.iSize;
if(FileSize > 255){FileSize = 255;}
if(CCoeEnv::Static()->FsSession().ReadFileSection(aFileName,0,FileBuffer,FileSize) == KErrNone)
{
RApaLsSession RSession;
if(RSession.Connect() == KErrNone)
{
TDataRecognitionResult FileDataType;
RSession.RecognizeData(aFileName,FileBuffer,*&FileDataType);
aFileType.Copy(FileDataType.iDataType.Des8());
RSession.Close();
}
}
}
}
}
[/CODE]
Использование RWsSprite
[CODE]
#include "TopInfo.h"
#include <const.h>
#include <eikenv.h>
#include <aknutils.h>
#include <aknsutils.h>
CTopInfo::CTopInfo()
{
}
CTopInfo::~CTopInfo()
{
delete iText;
iFont=NULL;
delete iMaskGc;
delete iMask;
delete iBitGc;
delete iBitmap;
iSprite->Close();
iWinGroup->Close();
}
CTopInfo* CTopInfo::NewLC()
{
CTopInfo* self = new (ELeave) CTopInfo();
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
CTopInfo* CTopInfo::NewL()
{
CTopInfo* self = CTopInfo::NewLC();
CleanupStack::Pop(); // self;
return self;
}
void CTopInfo::ConstructL()
{
// get font name
TTypefaceSupport iTypefaceSupport;
TBuf<KMaxTypefaceNameLength> fontName;
fontName.FillZ(KMaxTypefaceNameLength);
CEikonEnv::Static()->ScreenDevice()->TypefaceSupport(iTypefaceSupport, 0);
fontName = iTypefaceSupport.iTypeface.iName;
// get font
TFontSpec FontSpec(fontName, KFontSize);
FontSpec.iTypeface.SetIsProportional(ETrue);
CEikonEnv::Static()->ScreenDevice()->GetNearestFontInTwips(iFont,FontSpec);
//iFont=CEikonEnv::Static()->NormalFont();
isVisible=EFalse;
//calculate size
TBuf<15> temp;
temp.Fill('P',15);
iSize=TSize(iFont->TextWidthInPixels(temp),iFont->HeightInPixels()*2+3);
iPos=TPoint(5,90);
// create image and it's mask
iBitmap=new(ELeave) CFbsBitmap();
iMask=new (ELeave) CFbsBitmap();
iBitmap->Create(iSize,EColor16M);
iMask->Create(iSize,EColor16M);
CFbsBitmapDevice* BitDevice=CFbsBitmapDevice::NewL(iBitmap);
CFbsBitmapDevice* MaskDevice=CFbsBitmapDevice::NewL(iMask);
BitDevice->CreateContext(iBitGc);
MaskDevice->CreateContext(iMaskGc);
iBitGc->UseFont(iFont);
iMaskGc->UseFont(iFont);
//create window group with high priority (always at front)
iWinGroup=new (ELeave) RWindowGroup(CEikonEnv::Static()->WsSession());
iWinGroup->Construct((TUint32)iWinGroup);
iWinGroup->EnableReceiptOfFocus(EFalse);
iWinGroup->SetOrdinalPosition(0, ECoeWinPriorityAlwaysAtFront);
//create sprite
iSprite= new (ELeave) RWsSprite(CEikonEnv::Static()->WsSession());
iSprite->Construct(*iWinGroup,iPos,0);
iMember.iBitmap=NULL; // no image
iMember.iMaskBitmap=NULL;
iMember.iOffset=TPoint(0,0);
iMember.iInterval=TTimeIntervalMicroSeconds32(0);
iMember.iInvertMask=ETrue; // black - not transparadent, white - transparadent
iSprite->AppendMember(iMember);
iSprite->SetPosition(iPos);
iSprite->Activate();
CEikonEnv::Static()->WsSession().Flush();
iText=HBufC::New(1024);
Hide();
}
void CTopInfo::Show()
{
isVisible=ETrue;
iMember.iBitmap=iBitmap; //bitmap isn't NULL -> sprite is shown
iMember.iMaskBitmap=iMask;
iSprite->UpdateMember(0,iMember);
iSprite->SetPosition(iPos);
CEikonEnv::Static()->WsSession().Flush();
}
void CTopInfo::Hide()
{
isVisible=EFalse;
iMember.iBitmap=NULL; // bitmap is NULL -> sprite is hidden
iMember.iMaskBitmap=NULL;
iSprite->SetPosition(iPos);
iSprite->UpdateMember(0,iMember);
CEikonEnv::Static()->WsSession().Flush();
}
void CTopInfo::Draw()
{ // drawing at bitmap and it's mask
TRgb color;
MAknsSkinInstance* skin = AknsUtils::SkinInstance();
AknsUtils::GetCachedColor(skin,color,KAknsIIDQsnTextColors,EAknsCIQsnTextColorsCG6 );
// split text to lines
CDesCArray* arr = new (ELeave) CDesCArrayFlat(3);
TBuf<3> sep(_L(", "));
while (iText->Des().Find(sep)!=KErrNone)
{
TInt f=iText->Des().Find(sep);
if (f==KErrNotFound){break;}
arr->AppendL(iText->Des().Left(f));
iText->Des().Copy(iText->Des().Right(Abs(f-iText->Des().Length()+sep.Length())));
}
arr->AppendL(iText->Des());
//draw
iBitGc->SetBrushColor(color);
iBitGc->SetBrushStyle(CFbsBitGc::ESolidBrush);
iBitGc->SetPenColor(color);
iBitGc->DrawRect(TRect(-1,-1,iSize.iWidth+1,iSize.iHeight+1));
iBitGc->SetBrushColor(color);
iBitGc->SetBrushStyle(CFbsBitGc::ENullBrush);
iBitGc->SetPenColor(color);
iBitGc->UseFont(iFont);
iBitGc->DrawText(arr->MdcaPoint(0),TRect(0,0,iFont->TextWidthInPixels(arr->MdcaPoint(0)),iFont->HeightInPixels()),iFont->AscentInPixels(),CFbsBitGc::ELeft,0);
iBitGc->DrawText(arr->MdcaPoint(1),TRect(0,3+iFont->HeightInPixels(),iFont->TextWidthInPixels(arr->MdcaPoint(1)),3+2*iFont->HeightInPixels()),iFont->AscentInPixels(),CFbsBitGc::ELeft,0);
TRgb TransColor(0,0,0);
iMaskGc->SetBrushColor(KRgbWhite);
iMaskGc->SetBrushStyle(CFbsBitGc::ESolidBrush);
iMaskGc->SetPenColor(KRgbWhite);
iMaskGc->DrawRect(TRect(-1,-1,iSize.iWidth+1,iSize.iHeight+1));
iMaskGc->SetPenColor(TransColor);
iMaskGc->SetBrushColor(TransColor);
iMaskGc->SetBrushStyle(CFbsBitGc::ENullBrush);
iMaskGc->UseFont(iFont);
iMaskGc->DrawText(arr->MdcaPoint(0),TRect(0,0,iFont->TextWidthInPixels(arr->MdcaPoint(0)),iFont->HeightInPixels()),iFont->AscentInPixels(),CFbsBitGc::ELeft,0);
iMaskGc->DrawText(arr->MdcaPoint(1),TRect(0,3+iFont->HeightInPixels(),iFont->TextWidthInPixels(arr->MdcaPoint(1)),3+2*iFont->HeightInPixels()),iFont->AscentInPixels(),CFbsBitGc::ELeft,0);
CEikonEnv::Static()->InfoMsg(iText->Des());
//update image (if needed)
if (isVisible)
{
iMember.iBitmap=iBitmap;
iMember.iMaskBitmap=iMask;
}
iSprite->UpdateMember(0,iMember);
iSprite->SetPosition(iPos);
CEikonEnv::Static()->WsSession().Flush();
delete arr;
}
void CTopInfo::Update(TPtr8 aText)
{
iText->Des().Copy(aText);
Draw();
}
[/CODE]
Re: Проблема с CImageDecoder и RWsSession::EventReady
[b]truf[/b],
Огромное спасибо за разьяснения!
[b]Kolayuk[/b],
Спасибо, но почему-то User::WaitForRequest(ReqStat) никогда не завершается.
В итоге решил проблему с использованием CActiveSchedulerWait, теперь всё работает как нужно.
За спрайты тоже спасибо, но пока их использовать наверное не буду, т.к. картинка непрозрачная.