在Symbian exe 程序中显示图形

来源:互联网 发布:杂志编辑软件 编辑:程序博客网 时间:2024/04/28 09:49
Displaying graphics in Symbian exe programs.在 Symbian exe 程序中显示图形 Generally, exe programs are used to implement servers (exedll, epocexe target type) orsimple console programs. This may lead to believe that graphical features are not availablefor exe programs. This is not the case, and even though it might take some extra work toset up an appropriate environment, this is quite straight forward to achieve, as thefollowing snippet will illustrate. This way, we can make use of graphics without having toresort on a full blown application.通常,通常EXE程序(exedll, epocexe 类型)被用来实现服务器端或者是简单的控制台程序。所以使大家认为图形化的特性对于exe程序是不必要的。事实上并非如此,甚至它需要做一些额外的工作来设置一个适当的环境,就像下面将举例提到的,是十分方便的。Our aim is to simply emulate the minimum set up provided by the framework when anapplication (.app) is loaded. Being a dll, an application needs a process to attach to.This is provided by AppRun.exe, which besides catering its own process and thread, callsEikDll::RunAppInsideThread(), which -among other things- creates a CONE environment(CCoeEnv)我们的目标很简单,就是模拟当应用程序(.app)被加载时框架所提供的最小配置。作为一个DLL,应用程序是需要一个进程去加载它的,AppRun.exe就是用来做这个的。AppRun.exe不仅为自己的进程和线程提高资源,它还调用EikDll::RunAppInsideThread() ,建立一个CONE环境(CCoeEnv) 。When a CONE Environment is created, it sets up a cleanup stack, active scheduler(CCoeScheduler), and sessions to the file and window server (which can be later retrived bycalling CCoeEnv::FsSession() and CCoeEnv::WsSession()). Then it creates a screen, a windowgroup and a graphic context, among other things. Later, after the NewApplication() factoryfunction is called by the framework, the CCoeAppUi (from where the application's AppUiderives) creates the control stack, view manager, etc. and the CCoeControl derived classwill create a window (RWindow) to provide a basic view. As you can see, this snippetprovides all this basic functionality at once, without extra bloat such as a control stack,etc. which aren't needed in this simple case. I haven't included comments, as most of thecode speaks by itself.当CONE环境建立后设置清理栈活动对象规划器(CCoeScheduler),建立和文件,窗口服务器的会话(以后会在调用CCoeEnv::FsSession() 和 CCoeEnv::WsSession()时用到)。接着创建屏幕,窗口组和图形上下文。再下来,在工厂函数NewApplication()被框架调用后,CCoeAppUi (来自应用程序的AppUi驱动)建立控件栈,视图管理器等等。CCoeControl的继承类将建立窗口(RWindow)来提供基本的视图。就像你所看到的,这个程序片断只提供了所以基本的功能,并没有像控件栈等这些多余的东西,它们是这个简单例子程序中所不需要的。我们并没有注释,因为代码本身已经说明问题了。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(&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(&wg) + 1)); CleanupClosePushL(window); window.SetBackgroundColor(TRgb(0x90, 0x90, 0x90)); window.Activate(); window.SetExtent(TPoint(0, 0), TSize(screenWidth, screenHeight)); window.SetVisible(ETrue); gc->Activate(window); 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}Let's see now the entry point of the program. If we tried something like this现在我们来看入口程序。如果我们这样做: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;}it would work on the device only. On the emulator, you'd get a panic, asRWsSession::Connect() would fail. The reason for this is that when an exe is executed, theemulator doesn't launch the window server as part of its initialization, whereas on thedevice the server is already loaded.它只能在真机(手机)上运行。在模拟器上你会得到一个严重错误,因为RWsSession::Connect() 会失败。原因是当一个exe程序在模拟器上运行的时候,它(模拟器)是不会启动窗口服务器作为其初始化的一部分的。但是在手机上窗口服务器总是运行着的。There're a couple of ways to solve this. On Series 60 SDK v1.2, there's an undocumentedfunction which does exactly this for us. RegisterWsExe() is provided by wserv.lib. So nowour entry point function is:有许多方法解决这个问题。在Series 60 SDK v1.2,有一个未公开的函数为我们解决了这个问题。wserv.lib提供了RegisterWsExe()这个函数。现在我们的入口函数: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;}The problem with this solution is that it's not as generic as we might want. There'sanother way, which requires some more bit of work, that consists of changing the targettype to exedll or epocexe. This means that on WINS (emulator) we get a .dll, and on MARM(target) we get the .exe as usual. Note that all changes will be made to the startup code,that is, no changes are made to ExeMainL() code.这个解决方案并不是我们所通常所希望的。有另外一种方式,只需要多做一点儿工作,包括把目标类型改为exedll 或 epocexe。这意味着在模拟器上我们得到的是 .dll,在ARM(手机)上是通常的.exe。要注意所需要修改的仅仅是启动代码上,ExeMainL()使没有变化的。This is how our new startup code looks, with the two functions required by the exedll type(epocexe is analogous, except the exported function InitEmulator() is replaced by WinsMain()):我们的启动代码看起来是这样的,下面是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;}#endifNow the idea is renaming ExeUI.dll to ExeUI.app, and copying it to an application directoryon the emulator tree to make it look like an ordinary application. So we create the ExeUIdirectory in Epoc32/Wins/c/system/Apps (or Epoc32/Release/wins/udeb/z/system/apps if youwish). As we're creating an application, we also need to provide it of a proper UID, sodon't forget to add the corresponding line in the .mmpNow you may launch the emulator, that will show the ExeUI program's default icon.现在所要做的工作就是把把ExeUI.dll改名为ExeUI.app,并拷贝到模拟器的一个应用程序目录下。我们建立ExeUI目录Epoc32/Wins/c/system/Apps (或 Epoc32/Release/wins/udeb/z/system/apps只要你愿意)我们这不是建立了一个应用程序吗,所以我们还要提供一个合适的UID,别忘了在.mmp文件相应的地方添加它。好了,你启动模拟器,它会显示ExeUI程序的默认图标了。
原创粉丝点击