×
Namespaces

Variants
Actions

EXE中的图片

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

文章
hoolee 在 04 Sep 2009 创建
最后由 hamishwillee 在 15 Dec 2011 编辑

原文在此 http://www.pushl.com/developers/exeui.html

一般说来,exe程序用以完成服务(exedll,epocexe目标类型)或简单的控制台程序。可以想象这时exe程序并不需要图片显示特性。但情况并非如此,即使可能需要一些额外工作来建立一个适当的环境,但如下列代码所示也是比较容易的。这样我们就可以在一个简单干净的程序中也能使用图片。

我们的目的是简单的模拟出程序(app)加载时由框架提供的最小设置。作为一个dll,程序需要绑定一个进程。这可以由AppRun.exe提供,它除了提供自己的进程和线程外,还调用 EikDll::RunAppInsideThread(),其一个功能就是生成CONE环境(CCoeEnv)

当一个CONE环境生成后,它建立一个清除栈,活动调度器(CCoeScheduler)以及和文件及Window server的会话(它们可以通过调用CCoeEnv::FsSession()和CCoeEnv::WsSession()获得)然后它生成一个屏幕,一个窗口组和一个graphic context,然后NewApplication()被框架调用,由CCoeAppUi(你的AppUi类就派生于它)生成控件栈,视图管理器等,然后CCoeControl派生类将生成一个窗口(RWindow)用以提供基本视图,正如你所看到的,下列示例代码提供了所有的基本功能,无需那些额外的负担如控件栈等,这个简单示例是不需要,代码没有太多注释,一切请看代码本身所述:)

所需头文件:

#include <w32std.h> //RWsSession, CWsScreenDevice, RWindowGroup, CWindowGc, RWindow
#include <gdi.h> //CFont, TFontSpec

源文件:

LOCAL_C void ExeMainL()
{
RWsSession ws;
User::LeaveIfError(ws.Connect());
CleanupClosePushL(ws);
 
CWsScreenDevice* screen = new(ELeave) CWsScreenDevice(ws);
CleanupStack::PushL(screen);
screen->Construct();
 
RWindowGroup wg(ws);
User::LeaveIfError(wg.Construct(reinterpret_cast<TUint32>(&wg), EFalse));
CleanupClosePushL(wg);
 
wg.SetOrdinalPosition(10, ECoeWinPriorityAlwaysAtFront);
 
CWindowGc* gc;
User::LeaveIfError(screen->CreateContext(gc));
CleanupStack::PushL(gc);
 
RWindow window(ws);
User::LeaveIfError(window.Construct(wg, reinterpret_cast<TUint32>(&wg) + 1));
CleanupClosePushL(window);
window.SetBackgroundColor(TRgb(0x90, 0x90, 0x90));
window.Activate();
window.SetExtent(TPoint(0, 0), TSize(screenWidth, screenHeight));
window.SetVisible(ETrue);
//if you want to receive event on change in focus, use EnableFocusChangeEvents and implement listner.
//particularly helpful when some app goes to background and ur exe came to foreground.
window.EnableFocusChangeEvents();
 
gc->Activate(window);
 
//create font if u want draw text in exe.
CFont* font = NULL;
TFontSpec myFontSpec(_L("Series 60 Sans Regular"), 100);
screen ->GetNearestFontInTwips(font, myFontSpec);
screen->ReleaseFont(font);
// now use this fone.
 
TRect rect = TRect(window.Size());
window.Invalidate(rect);
window.BeginRedraw(rect);
 
gc->SetBrushStyle(CGraphicsContext::ESolidBrush);
gc->Clear();
 
TInt64 seed = User::TickCount();
TRgb color[] = { KRgbRed, KRgbGreen, KRgbBlue, KRgbYellow, KRgbCyan };
 
for (TUint i = 0; i < 10000; ++i)
{
TInt x = Math::Rand(seed) % screenWidth;
TInt y = Math::Rand(seed) % screenHeight;
TInt w = Math::Rand(seed) % 50;
TInt h = Math::Rand(seed) % 25;
 
TRect rect(TPoint(x, y), TSize(w, h));
gc->SetBrushColor(color[i % sizeof color]);
gc->DrawRect(rect);
}
 
window.EndRedraw();
gc->Deactivate();
 
ws.Flush();
 
CleanupStack::PopAndDestroy(5, &ws); // window, gc, wg, screen, ws
}

让我们看看程序的入口是怎样的

GLDEF_C TInt E32Main()
{
__UHEAP_MARK;
CTrapCleanup* cleanup = CTrapCleanup::New();
 
TRAPD(error, ExeMainL());
__ASSERT_ALWAYS(!error, User::Panic(_L("EXEUI"), error));
 
delete cleanup;
__UHEAP_MARKEND;
 
return 0;
}

它只能运行在工作在手机上,在模拟器上你会得到一个异常,因为RWsSession::Connect()将会失败,这是因为当一个exe被执行后,模拟器无法初始化时启动window server,但在手机上此服务一定会被加载。有两个解决办法来完成它,在Series 60 SDK 1.2中,有个未公开的函数可以使用,RegisterWsExe(),它由wserv.lib提供,因此我们的入口函数看起来像:

void RegisterWsExe(const TDesC&);
 
GLDEF_C TInt E32Main()
{
__UHEAP_MARK;
CTrapCleanup* cleanup = CTrapCleanup::New();
 
#if defined(__WINS__)
RegisterWsExe(_L("ExeUI.exe"));
#endif
 
TRAPD(error, ExeMainL());
__ASSERT_ALWAYS(!error, User::Panic(_L("EXEUI"), error));
 
delete cleanup;
__UHEAP_MARKEND;
 
return 0;
}

这个方法对我们来说有点别致陌生,还有另外一个解决方案,但需要多一点的工作,它包含了目标类型exedll或epocexe的转换,这意味着在WINS(模拟器上)我们得到一个dll,而在目标机器上我们得到一个exe。下面是我们新的启动代码,这里exedll类型需要两个函数(epocexe也类似,除了导出函数InitEmulator被WinsMain()所替代)

GLDEF_C TInt E32Main()
{
__UHEAP_MARK;
CTrapCleanup* cleanup = CTrapCleanup::New();
 
TRAPD(error, ExeMainL());
__ASSERT_ALWAYS(!error, User::Panic(_L("EXEUI"), error));
 
delete cleanup;
__UHEAP_MARKEND;
 
return 0;
}
 
// If using exedll target type
#if defined(__WINS__)
EXPORT_C TInt InitEmulator()
{
E32Main();
User::Exit(0);
return KErrNone;
}
 
TInt E32Dll(TDllReason)
{
return KErrNone;
}
#endif

上述方法需要将ExeUI.dll变成ExeUI.app,并将其拷贝到模拟器某个指定目录,使之看起来像原有程序,这样我们需要在Epoc32\Wins\c\system\Apps下生成ExeUI目录(或Epoc32\Release\wins\udeb\z\system\apps目录下)。当你生成一个程序后,我们也同样需要提供合适的UID,所以不要忘记在mmp工程文件中增加相应信息。现在你可以启动模拟器,它将显示ExeUI程序的缺省图标。

Related Links:

This page was last modified on 15 December 2011, at 09:12.
142 page views in the last 30 days.