Friday, September 30, 2005

Writing a Home Screen plugin

Writing a Home Screen plugin

In my last blog I promised you guys a blog about Home Screen plugin development. Well Jason on Virtueoffice wrote a pretty good Home Screen tutorial for you already, and I feel no need to repeat what he already have written. Check out his series of home screen tutorials Home Screen Plugin Tutorial - Part 1: The Basics.

Now there were many things that Jason just showed the code for, whilst not explaining what the code actually does. So I think that perhaps I could shed some light on those parts that was a little bit hard to understand.

COM

If you don’t know what COM is yet, then you have saved your self loads of headaches. It is true, almost everyone hates COM, but it is here and we have learned to accept it. So what do we do?

We start out by fetching our self a brand new GUID. What is a GUID you may ask? Well GUID is short for Global Unique Identifier. What is that then? It is a ship load of numbers that end up being a unique id. Ok, so we have this unique id stored in our brand new COM DLL, and we ship that DLL to a device and when it is there it will have to be registered in Windows. The registration progress goes something like this. Windows loads your DLL and executes the DllRegisterServer() method that you declared in your code. If you for some reason want to unregister your DLL then Windows would execute DllUnregisterServer() in your code. Basically all these two methods actually do is writing/deleting some information about your DLL in the registry so that Windows has some background information about them.

This is not a bad or unnecessary thing, because your GUID will be written together with the path to the DLL and other interesting stuff. This means that if you for some reason are about to use a COM object in your code, you could just referee to the GUID and let Windows take care of finding it for you. Now, if that was the only smart thing about COM then we might as well just use the good‘ol way, giving the frikkin path and roll with it. But oh no, this is where the magic starts to sparkling and go all wild. Because you would referee to the GUID instead of the path to the DLL, thus making these calls go thru some sort of COM DLL manager in the OS that acts like much like a proxy, the DLL only needs to be loaded once. Now all applications that are using this COM DLL are using the very same copy of the DLL in RAM rather then keeping their own copy of the DLL. This also allows the applications to communicate with each other thru the COM DLL memory space. I think that another intension was to save some RAM too.

Now that you understand that, you could probably muster up the imagination of one thing that gives us a shit load of security holes in Windows. You could also imagine what would happen to the three applications that depend on a certain COM DLL, if it was updated by its developer and the old GUID was kept from the old version for some reason. You are probably right, (let’s take a wild guess) many of these applications would start behaving very strange.

So how do they work? Well a COM DLL implements something called a Class Factory or an implementation of interface IClassFactory to be sure. This is a class that hands out new instances of your main class (in the Jason Home Screen example it would be the PluginBase class), keeps track of how many objects that is out there and other cool stuff that a factory needs to do. Now that we have this factory available, Windows could just go there and ask for another COM Object and our factory would produce it for Windows. Now Windows may ask if it could unload our COM DLL from RAM, then our factory manager could say something like “Oh no, that wouldn’t do! I still have objects out there!” or it could just return FALSE. This entire infrastructure is cool and all, but yes it presents a lot of potential security risks and memory leaks if the COM DLL coder doesn’t do his job well and write a lot of code that is just boring code that have to be written. And that is probably one reason why many coders don’t like ‘em.

Now you see that I haven’t even touched actual code regarding COM and I have written too much about the subject just to cover up some background info for you. I suggest that you sit down with the source from the Home Screen plugin and check it out on your own with this background info fresh on your mind.

The Plugin

Your actual plugin class for the Home Screen need to implement two interfaces, IHomePlugin and IPersistStream.

IHomePlugin gives you four important methods that you need to implement in your class. Initialize(), GetHeight(), GetSelectability() and OnEvent().

IPersistStream gives you four other important methods that you need to implement. IsDirty(), Load(), Save() and GetSizeMax(). Where I think that you will use only Load() and Save().

Now let’s look at the scenario where you have a finished Home Screen plugin and you have added it to your myhome.home.xml file with the <plugin> tag. You go into your SmartPhone settings and chose Home screen and chose your custom XML and you return back to your home screen to see what it looks like. What will happen in your code now?

  1. The home.exe process will read the custom XML, and find your <plugin> tag with the GUID of your COM DLL attached to it. So it will ask Windows for an object of this type.

  2. Windows will load the DLL (if it wasn’t loaded already) into RAM and initialize the Class Factory in the DLL. Then Windows will ask the newly born factory for a new Object, which Windows hopefully receives and then pass it on to the home.exe process.

  3. The home.exe will then take the new object and execute the Initialize() method implemented from the IHomePlugin interface, and pass everything that is within the <plugin> and </plugin> tags of your custom myhome.home.xml file.

  4. Now it’s up to your plugin to parse whatever it needs out of that XML node and store it in local variables.

  5. The home.exe will call the Save() method that is implemented with the IPersistStream interface, and pass a IStream object with it.

  6. Your plugin have to store the values of all the variables that it loaded with the Initialize() method on this stream using the IStream interface method Write(). This is a piece of cake. But why would I need to do that you may ask?

  7. Your plugin object (note the ‘plugin object’ referees to PluginBase class instance only, not the factory or any other code that might be instantiated in the DLL) will be destroyed by the home.exe process.

  8. The home.exe process will ask Windows for a new object, which Windows will retrieve from the factory of course.

  9. The home.exe will execute Load() implemented from the IStream interface in the new object and pass another IStream object from which you can read your earlier Written variables.

  10. Your plugin must read the values that were stored in the Save() method and return them to their rightful home.

  11. The home.exe process will execute the GetHeight() method and you need to return the height your plugin intends to have on the screen (in pixels).

  12. The home.exe process will execute the GetSelectability() method and you are supposed to return a TRUE or a FALSE weather your plugin should be selectable or not.

  13. From now and on the home.exe process OnEvent() method will be called whenever something interesting is happening to your plugin.

Could some one explain to me why step 6 to 10 is necessary? I’ve read explanations that it would solve eventual memory leaks that could occur in the initialization process of a plugin, but I can’t figure out the logic in that. Because once the DLL is loaded, it will not be unloaded, so eventual memory leaks will not be released after all. Or is there something in COM architecture that I am missing here?

The OnEvent

The OnEvent() method is executed whenever your plugin needs to do something in particular.

If your plugin is selected and the user presses a direction key, the PE_KEYDOWN message is sent with the OnEvent() method. Now you need to figure out what key was pressed and take action accordingly. If your plugin is selected and the user presses the action key (on most SmartPhone devices it would be the joystick, not in any direction but strait down into the device) you will receive the PE_ACTION message. Whenever your plugin is invalidated you will receive a PE_PAINT. And so it goes on. It’s not that hard to figure out what they all do.

One good thing about the Home Screen plugins, is that they doesn’t suffer from the same update problematics that the Today Screen does. In my MobiDock plugin I use the same code for rendering the Today Screen as the Home Screen. Actually I reuse all code that is not Today Screen API specific in the Home Screen plugin. But the Today Screen flickered, which the Home Screen did not even when I wasn’t using the double buffer technique. I think this is because each plugin is painted on the actual Home Screen window, whilst a Today Screen plugin has it’s own window that is on top of the Today Screen window.

To sum everything up

Once you’ve got code that handles all the COM specific functionality up and running, I think that the Home Screen API is nicer then the Today Screen API, with the IHomePlugin interface and all. But in the end, it’s all ruined by the COM thingy. I don’t know if you’re even supposed to be able to load more the one instance of each plugin. Or if your supposed to be able communicate with your plugin from another process using the COM techniques available? If so I think it’s an atom bomb to kill a bee solution.

Anyway, next blog will probably be about CAB files on your smart devices. How you can write a smart setup.dll that is executed by the CAB installer and other neat stuff.

I started writing this because I couldn’t sleep. Now I think I will drop dead when I reach my bed.

1 comment:

Anonymous said...

For me, a Java developer, who are assigned to write code to change home screen of smartphone device, this is definitely a great help to me. I have no idea of what COM, ActiveX, Ole ....