×
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.
123 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×