Why is it necessary to nuke the IAviFile pointer in this case before calling AviFileExit()?

345 views Asked by At

I found a Stack Overflow post with a sample showing how to get the duration of an AVI file:

Getting AVI file duration

I modified it for my purposes in my Delphi 6 app and created the code below. Initially I removed the line that nukes the IAviFile pointer before calling AviFileExit(). But when I did that I got an Access Violation when AviFileExit() is called. I restored the line and the access violation went away.

Why is it necessary to nuke the IAviFile reference before calling AviFileExit()? Is this a memory leak? I would think normal interface reference counting would work properly here but obviously it does not. Is there another way to eliminate the error like calling AviStreamRelease() or the like?

Here's my code:

function getAviDurationSecs(theAviFilename: string): Extended;
var
    aviFileInfo : TAVIFILEINFOW;
    intfAviFile : IAVIFILE;
    framesPerSecond : Extended;
begin
    intfAviFile := nil;

    AVIFileInit;

    try
        // Open the AVI file.
        if AVIFileOpen(intfAviFile, PChar(theAviFilename), OF_READ, nil) <> AVIERR_OK then
            raise Exception.Create('(getAviDurationSecs) Error opening the AVI file: ' + theAviFilename);

        try
            // Get the AVI file information.
            if AVIFileInfoW(intfAviFile, aviFileInfo, sizeof(aviFileInfo))  <> AVIERR_OK then
                raise Exception.Create('(getAviDurationSecs) Unable to get file information record from the AVI file: ' + theAviFilename);

            // Zero divide protection.
            if aviFileInfo.dwScale < 1 then
                raise Exception.Create('(getAviDurationSecs) Invalid dwScale value found in the AVI file information record: ' + theAviFilename);

            // Calculate the frames per second.
            framesPerSecond := aviFileInfo.dwRate / aviFileInfo.dwScale;

            Result := aviFileInfo.dwLength  / framesPerSecond;
        finally
            AVIFileRelease(intfAviFile);
            // Commenting out the line below that nukes the IAviFile
            //  interface reference leads to an access violation when
            //  AVIFileExit() is called.
            Pointer(intfAviFile) := nil;
        end;
    finally
        AVIFileExit;
    end;
end;
1

There are 1 answers

1
Remy Lebeau On BEST ANSWER

You have to clear your variable manually because Delphi does not know that AVIFileRelease() released the interface. AVIFileRelease() does not set the variable to nil for you, so the variable still has a non-nil value to it. If you don't clear it manally , Delphi will try to call Release() on the variable when it goes out of scope (after the AVIFileExit() call) and crash.

The IAVIFile interface is an IUknown descendant, so I don't know why Microsoft created the AVIFileRelease() function in the first place. It decrements the interface's reference count and perform cleanup if the count falls to zero. The implementation behind the interface could simply have handled that internally without needing an explicit function. So that's Microsoft's bad.