Jump to content

Using the Windows Timer in plugins


Guest moo_ski_doo

Recommended Posts

Guest moo_ski_doo

I've been writing a plugin in Embedded Visual C++ and have most of the code working now but have come accross a problem trying to use the Windows Timer. Although I can set a timer up (using SetTimer), because I don't have a window handle I never get any WM_TIMER messages posted to my app. Using timers in normal Windows programs has never caused a problem for me in the past because I DO have a handle to a Window.

Does anyone know how to use timers like this in plugins?

Thanks in advance,

-Mark.

Link to comment
Share on other sites

Guest rcraswell

Even though you don't have a window, you still have to process a message loop to get Windows timers to work.

So, while you'd think something like this would work:

hevent = CreateEvent(NULL, FALSE, FALSE, NULL);

ntimer = SetTimer(NULL, 0, dwInterval, MyTimerProc);



WaitForSingleObject(hevent, INFINITE);[/code] it won't. Your little TimerProc will never see a timer message and you'll be a sad panda. Instead, you have to process messages for your thread like so:
[code]ntimer = SetTimer(NULL, 0, dwInterval, MyTimerProc);



for (;;)

{

  MSG msg;



  GetMessage(&msg, NULL, 0, 0);

  DispatchMessage(&msg);

}

(of course, you'll need to have some sort of way to exit out of that loop, but that's an exercise left to the reader.)

The Remarks section of SetTimer tries to explain this:

An application can process WM_TIMER messages by including a WM_TIMER case statement in the window procedure or by specifying a TimerProc callback function when creating the timer. When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.  

Good luck!

Link to comment
Share on other sites

Guest moo_ski_doo

Cheers for the advice. Still can't get it working tho. I've tried creating a thread (using CreateThread) to put a message loop in but it doesn't seem to work. The first time I ran it, the thread ran as expected but I can't get it to work anymore despite the fact that the code hasn't changed!

I'm getting pretty close to giving up now, I've spent four days trying to figure this out! I'm surprised that no-one else seems to be having these problems, it seems like quite a basic (although essential) thing I'm trying to do.

Any idea how other plugins update themselves (they all must do it somehow)? If only I could find some source code...

Link to comment
Share on other sites

Guest rcraswell

Well, here's code for a fully functioning program (the lines above plus a WinMain to wrap it) that makes my phone beep merrily away.

Alternatively, there's no reason you can't create a little (hidden) window to be a message receptacle -- that's a perfectly reasonable and valid Windows programming technique.

timerproc.cpp

Link to comment
Share on other sites

  • 3 weeks later...
Guest danm_cool
Well, here's code for a fully functioning program (the lines above plus a WinMain to wrap it) that makes my phone beep merrily away.

Alternatively, there's no reason you can't create a little (hidden) window to be a message receptacle -- that's a perfectly reasonable and valid Windows programming technique.

I have already done that for ppc, you can create a hidden window, save its handle in a static variable or function, and use it anytime you need in your application.

DM

Link to comment
Share on other sites

Guest moo_ski_doo

Cheers for the advice, I've now managed to do it in a similar way by creating a thread shortly after initialising my DLL, which handles my messages for me - works a treat ;) I actually tried using this approach a while ago but couldn't get it working - after hours of playing around with it I figured out that you can't create a thread from a dll's initialise function which is what I was trying to do - weird :shock:

Thanks again,

-Mark.

Link to comment
Share on other sites

  • 3 weeks later...
Guest statscat

oh theres a better way with plugins, they follow there own unique architecture.

Theres a function called setSingleShotTimer (in IHomePluginEnvironment), anyway in general timers are really bad in plugins as they eat at the battery life. Neil Enns and MS did a web cast thingy ma-bob.

Anyway if you are checking to see if data has changed somewhere else there is a much easier way to do it. Get the app to tell the plugin when its changed by sending a

SHonPluginDataChante (const CLSID * pclsidPlugin);

#include

(aygshell.lib too in your settings).

If you have # defined your GUID the you can just pass it the address of the plugin.

Your plugin then needs to handle datachange by invalidating itself so it repaints. Its sadly not documented in the 02 SDK but it was covered in the MS webcast. Its well worth watching.

Link to comment
Share on other sites

Guest moo_ski_doo

Thanks for that, interesting function name, wonder what that means... Strange this stuff isn't documented, makes it tricky to find out about it really! Anyway, like I say I've done it a different way now (as a thread) which I really like cus it keeps it all very tidy in a single application :) but this is something to think about in the future, especially if I do ever need an app and plugin running side by side.

Incidentally, people keep telling me that timers kill the battery (I'm not saying they're wrong, it even says it in the documentation so there's presumably some truth in it), but does anybody know why? My current plugin has a 5 second timer and it seems to make no difference to battery life at all - it's still as bad as it ever was! All my plugin does when it gets a timer event is check for changes - it only actually invalidates the plugin if a change has occured - probably about every 15 mins or so. How can performing such a tiny set of instructions with such a powerful but efficient processor cause extra energy consumption? A bit off topic but I'd still be very interested to know :wink:

Anyway, thanks again.

Link to comment
Share on other sites

Guest maxh2003

I have a question I think you guys could help me with. You might have seen my pitiful efforts at plug-in writing elsewhere on this forum :lol:

Anyway, I've got Initialize code to parse the XML parameters receieved from the home XML file, but I can't seem to store these values. It looks something like this:

#plugin.cpp

int value = 10;

HRESULT Plugin::OnEvent(PluginEvent){

...

CASE WM_ACTION:

print(value); // pseudocode

}

HRESULT Plugin:Initialize(HPLUGIN, IXMLDOMNODE*,IXMLDOMNODE*)

{

value = 5;

print(value); // pseudocode

}

I know that the Initialize code is being called, because my print(value) command returns 5. But when I click the plugin, print(value) still returns 10.

Can anyone offer any suggestions as to why this is, and what I should be doing? I assume it's something to do with my use of a global variable... maybe...?

Link to comment
Share on other sites

Guest moo_ski_doo

Ahh, the old Initialize function! I never tire of trying to figure this one out! I think I know what the problem is, but unfortunately, I don't have a solution :lol:

Firstly, your code looks right to me, and if plugins worked in the way you'd expect then I'd expect your code to work. However, unfortunately plugins seem to work in rather more mysterious ways:

As far as I can tell, Windows treats the initialize function as a static function which it calls purely to initialize the plugin. Once this has been called, it ceases to use this instance of the plugin and creates a new instance which is the one you actually see on your screen (and the best part is that for this new instance, the initialize function does not get called again!) Verify this by outputting the value of 'this' - first from Initialize(), and then from any other function; it will be a different value. The effect of this is that if you're using global variables in the way you described, when you print the value of your variable from Initialize(), it will be using a different instance of the variable to the other functions in your class.

Normally this isn't a problem because you can do any initialization elsewhere; I usually create an m_bInitialized flag which is set to false in the constructor, then initialization is done at the start of the OnEvent function since this will be reached before anything else, then the flag is set to true so the plugin doesn't get initialized again.

My problem is, and going on what you said about parsing XML, I suspect you're having the same problem, the only place you can get at your XML is in the Initialize function. Like I say tho, at this point I'm afraid I don't have a solution!

Anyway, hopefully this post will help explain the problem (assuming that I'm right about this of course,) so in light of this you might be able to think of a solution. The best idea I've come up with so far is to store the information you need from Initialize in some sort of persistent memory store - if worst comes to worst it could be stored in the registry or in a file which both parts of the plugin can get at, but this is a bit of a dirty hack!

If you think of a solution to this, please let me know because I'm trying to solve this problem too.

Hope this helps and, more importantly, makes some sense (it was a struggle to try to put this in to plain English!)

Link to comment
Share on other sites

Guest statscat

ok guys,

plugins are strange creatures and live a strange life, they are in fact loaded twice before paint is ever called , and as you have both discovered the paint and the action are the easy part :lol: now comes the real *fun* part making it configurable

Plugins handle

PE_DATACHANGE

(these normally call Invalidate)

PE_ACTION

PE_PAINT

PE_TIMER (via SetSingleShotTimer)

for PluginEvent rather than WindowEvents etc

there are loads more look for plugin events in the SDK, but don't go trying to capture the up or down keys as thats real hackery.

You are correct that initialize is the only oppurtunity to parse the xml, this is done outside as it were of an actual real instance of your plugin in that it runs outside of home.exe. The first time your plugin loads its parse the xml, this is because the xml parser is very prome to memory leaks so if it happened inside hom.exe as it were then it would bomb your phone so its a helper process on "cold boot" or first load.

then you need to implement

IPersistStream::Save

where you save the xml that you have just parsed and other things of interest.

The next time your plugin loads it calls

IPersistStream::Load

this loads all the information that you have parsed in intialize and stored in save ............................................ and sets the plugin state (its created in the meantime and loaded whrn the home.exe state is streamed in as it were)

To get the idea of what happening think of a "Helper function" thats sits outside home.exe in this "function" the process is

1. read in xml file

2. Create Plugin

3. Initialize plugin

4. Stream Out/ Save plugin

5. Destroy plugin

The process that occurs within home.exe is different as the plugin reads itself rahter than initialze itself. THis is done so that hom.exe remains responsive (and running) during setting changes.

1. Stream in home.exe state

2. create plugins

3. stream in plugin state

4. handle actions

Once you have all that mastered the next joy is attempting to get the homescreen colours as 2002 doesn't offer the new getcolor function and don't bother going looking for them in syscolor either as the 4 plugin colours aren't saved there either ;)

This has to be saved out into intialize to as there are no apis for it, so you need to know how to ascretain the appropriate colour scheme get the colours out and convert them to syscolors etc.

Plugins are tricky and not the simplest beast to handle or control and memory leaks are a *real* headache you must capture even the small ones as they mount up over a power cycle as it were (home.exe doesn't die till you turn it off, or load a new homescreen) .....

Then I guess its the bgimage support in the format tags and all the default font settings etc as well as those from within your plugin (padding, alignment etc).

oh how we *wish* for a getFormat ............

I hope this has helped and given you an idea on where to start.

I can't help but think the real innovation with a plugin is actullay building one that use the homescreen colours rather than those set in the format tag on a 2002 device.

Link to comment
Share on other sites

Guest moo_ski_doo

Excellent, thanks a lot for that! Glad to see I was on the right lines with what I'd managed to figure out, even managed to use the word persistent myself :lol: Think I've managed to figure out most of the other stuff already (including getting the colours - went through that a while ago and managed to find them lurking in the registry.) In fact, I think the only thing I have left to figure out now is how to enumerate stuff like COLOR_HOMETEXT to its actual colour value. Something for another day I imagine...

How come you know exactly how these plugins work (the exact process they go through)? I managed to figure a lot of it out by trawling through the code and putting debug out etc. but don't think I'd have managed to figure all that out!

Thanks again, you've been fantastically helpful!

Link to comment
Share on other sites

Guest maxh2003

I second that, many thanks for your help. FWIW I also found some useful stuff on . Having added a print(value) to the Save method I can see it is being called with the global variables I set in Initialize, still visible.

I was going to ask for tips on IPersistStream, but then I found >>this<< url. Could someone cast their eye over it briefly and indicate whether the first long code example is the *sort of thing* I should use to save my variables?

If not thanks for all the help anyway, guys :lol:

Link to comment
Share on other sites

Guest statscat

yeah the StinkerColor look up provided by Orange rocks, see they are nice people really and they do try to help developers.

I bet they broke there balls doing it the real way and thought ... bless ....... third party developers we'll give em a lookup table so they don't die too young. Thing is though thats only available on an orange phone as it gets set by their shortcut plugin. (I figured that out too)

In terms of figurig it out I'm a tenatious lady who like to know how the black box works (its cos chix dig unix) and XML parsing is dodgy at the best of times let alone in a process that runs continuosly, and lets just say I have some experience with plugins.

Link to comment
Share on other sites

Guest statscat

Yeah the url for the persist stuff is alson the right lines, where plugins differ again is that you need to call Invalidate if the stream becomes dirty (its changed so you need to do lots of exciting stuff like re save and paint yourself).

You need to keep paint really fast too, so think about how you handle you data carefully too.

Link to comment
Share on other sites

  • 4 years later...
Guest aksheik

Two part question.

1) How do I call SHOnPluginDataChange from a C# application.

2) Where is the list of Links that are displayed in the MRU plug in

stored.

I would like to re order the MRU links and refresh the plugin using a

C# program.

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.