1

What's the cheapest way for a JavaScript like setTimeout-function in C++?

I would need this: 5000 miliseconds from now, start function xy (no parameters, no return value).

The reason for this is I need to initialize COM for text to speech, but when I do it on dll attach, it crashes.

It works fine however if I do not call CoInitialize from dllmain.

I just need to call CoInitialize and CoCreateInstance, and then use the instance in other functions. I can catch the uninitialized instance by checking for NULL, but I need to initialize COM - without crashing.

Stefan Steiger
  • 68,404
  • 63
  • 337
  • 408

2 Answers2

5

Calling CoInitialize() from DllMain() is a bad thing to do; there are LOTS of restrictions on what you can do from DllMain(); see here: http://blogs.msdn.com/larryosterman/archive/2004/04/23/118979.aspx

Even if it DID work reliably then initialising COM from within DllMain() isn't an especially nice thing to do as COM is initialised per thread and you don't know what the application itself wants to do with regards to COM apartments for the thread that you want to initialise COM for... This means that you might initialise COM in one way and then the application might need to initialise it in another way and might fail because of what your DLL had done...

You COULD spin up a thread in DllMain() as long as you are careful (see here http://blogs.msdn.com/oldnewthing/archive/2007/09/04/4731478.aspx) and then initialise COM on that thread and do all your COM related work on that thread. You would need to marshal whatever data you need to use COM with from whatever thread you're called on to your own COM thread and make the COM call from there...

And then there's the question of whether the instance of the COM object that you create (could you reliably do what you want to do) would be usable from the thread that was calling into your DLL to make the call... You do understand how you'd have to marshal the interface pointer if required, etc?

Alternatively you should expose YOUR functionality via COM and then have the application load your DLL as a COM DLL and everything will work just fine. You can specify the apartment type that you need and the app is responsible for setting things up for you correctly.

So, in summary, you don't need the answer to your question.

Len Holgate
  • 20,256
  • 4
  • 40
  • 89
  • And what has this to do with my question? I'm exactly trying to avoid calling CoInitialize in DllMain, that's why I need setTimeout, to execute the function once DllMain has finished. Threading is not a solution either, you can't really start a thread in DllMain... – Stefan Steiger Apr 20 '10 at 17:28
  • PS: No, I can't export the function and call it from the executable, because I don't have the source of the executable. – Stefan Steiger Apr 20 '10 at 17:29
  • So, assuming you CAN set the timer that you want, which thread would the code be executed on when it fires after DllMain() has returned? Follow the link I posted, you CAN start a thread in DllMain() if you abide by the rules; it's still not recommended though. And, as I pointed out, it's not YOUR place to decide that you should initialise COM in a particular way on a thread that the application owns... – Len Holgate Apr 20 '10 at 20:17
  • It's done. It's indeed possible to start a thread from dllmain although it's not recommended. One however cannot access the COM class pointer from outside the thread, it's NULL outside. So you have to use vecors, push the data from outside the thread, and then pop them in the thread, in an infinite loop with sleep. That way it never gets properly uninitialized, but I don't care about that. – Stefan Steiger Apr 21 '10 at 08:41
  • That's not strictly true, you COULD access the COM interface pointer from outside your thread if you wanted to but you'd need to a) make sure that COM was initialised in the way that you wanted it on the thread that you wanted to access the pointer from and b) that you marshalled the interface pointer from the thread where you co-created it to the thread where you want to use it. By the sounds of it you're simply using a vector to marshal your parameters from the calling thread in your DLL to your COM thread... There are probably better ways than using sleep, perhaps an event or semaphore? – Len Holgate Apr 21 '10 at 09:03
  • Can we discuss that here: http://stackoverflow.com/questions/2681446/howto-access-thread-data-outside-a-thread ? I don't quite understand how I should do this, marshal the interface pointer ? – Stefan Steiger Apr 21 '10 at 12:02
0

When it is OK to stop the execution for 5 seconds entirely, you can use the Winapi Sleep function. Beware that the documentation of Sleep minds some possible problems with CoInitialize and Messages.

Rudi
  • 17,566
  • 3
  • 50
  • 74