Unoffical empeg BBS

Quick Links: Empeg FAQ | RioCar.Org | Hijack | BigDisk Builder | jEmplode | emphatic
Repairs: Repairs

Topic Options
#203112 - 08/02/2004 17:57 Cleaing up on failures in C
mschrag
pooh-bah

Registered: 09/09/2000
Posts: 2303
Loc: Richmond, VA
So I'm wrapping some DirectShow stuff with JNI so I can get to it in Java ... One of the really nice constructs in Java is the try { .. } finally { ..} where finally is always executed no matter how the try block exists, so you can clean up nicely. Is there any equivalent to this in C or some mechanism that makes cleaning things up easier? For instance, I have a bunch of COM objects that need to get ->Release()'d, and it's pretty damn annoying trying to keep track of who is referenced at every failure point. Especially if you properly check error results -- every single call can return a failure HRESULT and potentially requires a cleanup afterwards. Any tricks of the trade would be appreciated ... I'm so spoiled from Java with not having to care about garbage collection -- that's probably the most annoying thing about doing non-Java stuff so far.

ms

Top
#203113 - 08/02/2004 18:03 Re: Cleaing up on failures in C [Re: mschrag]
Daria
carpal tunnel

Registered: 24/01/2002
Posts: 3937
Loc: Providence, RI
typically i've seen gotos which creep up the list as new things are allocated

foo = malloc(10);
if (!foo) goto cleannone;
bar = malloc(10);
if (!bar) goto cleanfoo;
baz = malloc(10);
if (!baz) goto cleanbar;

free(baz)
cleanbar:
free(bar);
cleanfoo:
free(foo);
cleannone
return;

Top
#203114 - 09/02/2004 02:53 Re: Cleaing up on failures in C [Re: mschrag]
Roger
carpal tunnel

Registered: 18/01/2000
Posts: 5683
Loc: London, UK
Is there any equivalent to this in C or some mechanism that makes cleaning things up easier?

Yeah, it's called C++ . It has exceptions, just like in Java. And, even if you need the C interface, you can still create extern "C" functions in C++ and get that exception goodness. Oh, and smart pointers, which will save you from having to call Release() anyway.

Alternatively, there's 'goto'. Ick.
_________________________
-- roger

Top
#203115 - 09/02/2004 06:49 Re: Cleaing up on failures in C [Re: Roger]
mschrag
pooh-bah

Registered: 09/09/2000
Posts: 2303
Loc: Richmond, VA
Ah hah -- This is what CComPtr is .... I had taken out those because it was screwing with my CoUninitialize call (now that I know what it is I assume it was cleaning up refs by trying to release them after I uninitialized). I'll have to look at what the proper approach is for using those two calls together.

Top
#203116 - 09/02/2004 06:54 Re: Cleaing up on failures in C [Re: mschrag]
Roger
carpal tunnel

Registered: 18/01/2000
Posts: 5683
Loc: London, UK
You should just nest the CComPtr stuff in a separate block:

void foo()

{
CoInitialize(NULL);

// BLOCK:
{
CComPtr p(something);

// yada yada
}

CoUninitialize();
}


The end of the enclosing block will cause the destructors to be called before you reach the CoUninitialize call.
_________________________
-- roger

Top
#203117 - 09/02/2004 07:30 Re: Cleaing up on failures in C [Re: Roger]
mschrag
pooh-bah

Registered: 09/09/2000
Posts: 2303
Loc: Richmond, VA
Oh man ... You're a life saver (and a typing saver ). I knew there had to be a better way -- that previous process was freaking ridiculous -- I was like a pointer accountant doing the pointer books every time i left the method. Once I toss in exceptions in there too, this code will actually look pretty damn normal. Before literally 60% of my function was error handling and cleanup.

Top
#203118 - 09/02/2004 09:08 Re: Cleaing up on failures in C [Re: mschrag]
Roger
carpal tunnel

Registered: 18/01/2000
Posts: 5683
Loc: London, UK
this code will actually look pretty damn normal

One thing that you need to be aware of is that you're really only supposed to call CoInitialize once per thread, and you should only call CoUninitialize at thread exit.

Now, this probably won't cause a problem if you're using JINI or whatever to call C++ methods, since you'll be doing it from a Java app. It becomes a problem when those functions are called from a C or C++ application that has already initialized COM. For one thing, your call will return S_FALSE (in the best-case), or RPC_E_CHANGED_MODE (in a worst case).

To understand what I mean about "worst-case", go and read up on threading models in COM. To cut a long story short, there are two main thread models in COM:

The first is the single threaded apartment model (STA), where you guarantee that a call to an object will only occur on the thread that created it (and, conversely, COM guarantees that it'll only ever call you back on the same thread). It's called "apartment", because you can have several different apartments in an application, each with their own thread. This is what you get when you call CoInitialize().

The second is the multi-threaded apartment model (MTA), where the apartment contains multiple threads, and you can issue calls on any one of them, and receive callbacks on any one of them. You get into this mode by calling CoInitializeEx and passing a different flag.

Now, some components are only compatible with a single model. This doesn't generally cause a problem, because COM will sort out the marshalling correctly -- as long as you don't lie about your requirements and the component doesn't lie about its.

Anyway, the point of this is that you're not allowed to change modes once you've initialised COM, which means that it's generally a bad idea to try to initialise COM from a library function, because it might have been initialised with a different mode already.

_________________________
-- roger

Top
#203119 - 09/02/2004 09:30 Re: Cleaing up on failures in C [Re: Roger]
mschrag
pooh-bah

Registered: 09/09/2000
Posts: 2303
Loc: Richmond, VA
Yeah -- everything I've read about the COM threading (particularly as a JNI participant) sounds kind of treacherous.

In my case, it's rather tricky to be able to call CoInitialize/Uninit at the front and back of a thread because of the nature of Java's garbage collector. I can call Initialize, for instance, when some top level class is created, but knowing when to call Uninitialize is rather tricky. Like you said, in my case, these methods are only being called by my Java wrapper, so I /think/ I can be reasonably confident that it's not already initialized. Is it OK to call multiple times as long as I know I'm the only one doing it and it's cleaning up properly each call?

ms

Top
#203120 - 09/02/2004 10:16 Re: Cleaing up on failures in C [Re: mschrag]
Roger
carpal tunnel

Registered: 18/01/2000
Posts: 5683
Loc: London, UK
Is it OK to call multiple times as long as I know I'm the only one doing it and it's cleaning up properly each call?

As long as this is the case, then, generally, yes.
_________________________
-- roger

Top