Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

COM with classes

Posted on 2001-07-22
10
Medium Priority
?
291 Views
Last Modified: 2013-12-03
I have a class that encapsulates a COM interface (IDirectSoundBuffer), like this:

class Sound
{
private:
    LPDIRECTSOUNDBUFFER lpBuf;

public:
    bool Create( char *wavefile );
    void Destroy();

    Sound() { lpBuf = 0; }
    ~Sound();
};


bool Sound::Create( char *wavefile )
{
    // Use IDirectSound::CreateSoundBuffer() to create
    // a buffer, then fill it with the wave data
}

void Sound::Destroy()
{
    if (lpBuf != 0)
        lpBuf->Release(), lpBuf = 0;
}

Sound::~Sound()
{
    Destroy();
}


When my program is started, it obtains an IDirectSound interface using the DirectSoundCreate() function. After that a Sound object is created, which creates a sound buffer interface.

If Sound::Destroy() is called before releasing the IDirectSound interface, then everything works properly. A problem arises, however, when the interface is released first and Destroy() is called afterwords (either manually or in the destructor). When IDirectSound is released, any buffers that were created through it are also released automatically. The Destroy() function can't detect this situation because its lpBuf member is still nonzero, so it tries to release it again. This causes an access violation exception.

Obviously the right thing to do is to just make sure to call Destroy properly, but I can't help but wonder if there is a way to detect the 'released-but-nonzero' situation and deal with it properly. If anyone has run into this problem before, I would really appreciate it if you told me how you delt with it.
0
Comment
Question by:TookH
  • 3
  • 2
  • 2
  • +2
10 Comments
 
LVL 5

Accepted Solution

by:
robpitt earned 400 total points
ID: 6307691
Hmmm, thats interesting and your right its a bit of a problem.

Effectively releasing the parent DirectSound object has caused the destruction of all the DirectSoundBuffers. I believe this to be completely counter the standard reference counting mechanism.

The only thing I can think of is to pass a reference to the IDirectSound interface to your CSound class. Your CSound class can then call AddRef() on the IDirectSound interface. This will ensure that IDirectSound isn't released until after the destructor at which point you CSound class can do a IDirectSound->Release().

0
 
LVL 9

Expert Comment

by:ShaunWilde
ID: 6308436
hmm it does seem to be that the directsound interface is keeping a reference to it without incrementing its own refcount and without tying them in to its own refcount - not an uncommon scenario - but I am surprised it deletes the buffer itself rather than let the the directsoundbuffer do it but then if you tell DirectSound that you no longer need it then it may be a default tidy up mechanism to tidy up resources left behind by 'bad' programmers
0
 
LVL 5

Expert Comment

by:robpitt
ID: 6308504
I'm pretty sure your right about it being a "default tidy up mechanism to tidy up resources left behind by 'bad' programmers"


Certainly it was the case that when the original DX was released lots of games programmers were completely ignorant of techniques such as reference counting.

Hence lots of them just took the samples and butchered them without any real understanding of what they should be releasing and when.

Rob
0
Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

 
LVL 3

Expert Comment

by:JackThornton
ID: 6309495
There's no valid or guaranteed way to detect that kind of situation, which (theoretically) isn't supposed to come up if reference counting is properly handled. What DX does, for whatever *good* reason, violates COM policy.

Three things you can do:

(1) Test pointer before releasing it by calling IsBadReadPtr against either lpBuf or a dereferenced lpBuf (given the assumption that, even with a proxy, the interface pointer points to a pointer), before releasing it. E.G.:

if (!IsBadReadPtr(lpBuf, 4) && !IsBadReadPtr(*((unsigned **)lpBuf), 1))
    lpBuf->Release();

Not guaranteed to work since the released memory could be reallocated and no longer hold the FEFEFEFE or BAADF00D that MS likes to fill the CoTaskMemFree'd memory with.

(2) Wrap the release in a try/catch block.

(3) Construct your sound buffer with a pointer to the "controlling" IDirectSound interface, and keep a addref'd reference to that interface in your buffer object. E.G.:

    lpBuf->Release();
    lpIDirectSound->Release();

This keeps the DirectSound object around until you've destroyed all your buffers yourself. This is the only "legitimate" way to handle this ugly situation.

- jack

0
 
LVL 5

Expert Comment

by:robpitt
ID: 6309534
(3) is what I suggested  :-)
0
 
LVL 3

Expert Comment

by:JackThornton
ID: 6309558
robpitt: oops! (that's what I get for not reading carefully. Or having kids and thereby destroying my few remaining brain cells).
0
 
LVL 9

Expert Comment

by:ShaunWilde
ID: 6309596
I agree about the kids - what was this question about again?
0
 
LVL 6

Expert Comment

by:snoegler
ID: 6316101
BTW: This behavior occurs in other parts of Windows API's as well ... for example, the IStorage COM interfaces behave exactly like that. If you obtain a IStream from a IStorage and you release the IStorage, the IStream is also released.

Sometimes i get the feeling that MS should only do COM after learning it :)
0
 
LVL 1

Author Comment

by:TookH
ID: 6316184
The AddRef solution looks like exactly what I need. Much thanks. :-)
0
 
LVL 1

Author Comment

by:TookH
ID: 6350427
Um... I just got about five notifs from this question. Anyone else?
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article shows how to make a Windows 7 gadget that extends its U/I with a flyout panel -- a window that pops out next to the gadget.  The example gadget shows several additional techniques:  How to automatically resize a gadget or flyout panel t…
For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…

886 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question