Solved

COM with classes

Posted on 2001-07-22
10
278 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
  • 2
  • +2
10 Comments
 
LVL 5

Accepted Solution

by:
robpitt earned 100 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
NFR key for Veeam Backup for Microsoft Office 365

Veeam is happy to provide a free NFR license (for 1 year, up to 10 users). This license allows for the non‑production use of Veeam Backup for Microsoft Office 365 in your home lab without any feature limitations.

 
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

Online Training Solution

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action. Forget about retraining and skyrocket knowledge retention rates.

Question has a verified solution.

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

In this article, I will show how to use the Ribbon IDs Tool Window to assign the built-in Office icons to a ribbon button.  This tool will help us to find the OfficeImageId that corresponds to our desired built-in Office icon. The tool is part of…
After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
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…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…

615 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