Solved

COM with classes

Posted on 2001-07-22
10
248 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 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
 
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
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
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

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

As more and more people are shifting to the latest .Net frameworks, the windows presentation framework is gaining importance by the day. Many people are now turning to WPF controls to provide a rich user experience. I have been using WPF controls fo…
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…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

762 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

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now