在这种情况下,为啥在调用 AviFileExit() 之前需要核对 IAviFile 指针?

Posted

技术标签:

【中文标题】在这种情况下,为啥在调用 AviFileExit() 之前需要核对 IAviFile 指针?【英文标题】:Why is it necessary to nuke the IAviFile pointer in this case before calling AviFileExit()?在这种情况下,为什么在调用 AviFileExit() 之前需要核对 IAviFile 指针? 【发布时间】:2012-05-25 14:57:40 【问题描述】:

我发现了一个 Stack Overflow 帖子,其中包含一个示例,展示了如何获取 AVI 文件的持续时间:

Getting AVI file duration

我在我的 Delphi 6 应用程序中对其进行了修改,并创建了以下代码。最初,我在调用 AviFileExit() 之前删除了核对 IAviFile 指针的行。但是当我这样做时,我在调用 AviFileExit() 时遇到了访问冲突。我恢复了线路,访问冲突消失了。

为什么在调用 AviFileExit() 之前需要核对 IAviFile 引用?这是内存泄漏吗?我认为正常的接口引用计数在这里可以正常工作,但显然不能。有没有其他方法可以消除错误,比如调用 AviStreamRelease() 之类的?

这是我的代码:

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】:

您必须手动清除变量,因为 Delphi 不知道 AVIFileRelease() 释放了接口。 AVIFileRelease() 没有为您将变量设置为 nil,因此该变量仍然具有非零值。如果您不手动清除它,Delphi 将尝试在变量超出范围时调用Release()AVIFileExit() 调用之后)并崩溃。

IAVIFile 接口是IUknown 的后代,所以我不知道微软为什么首先创建AVIFileRelease() 函数。它会减少接口的引用计数并在计数降至零时执行清理。接口背后的实现可以简单地在内部处理,而不需要显式函数。所以那是微软的坏事。

【讨论】:

谢谢雷米。至少我现在知道为什么了。

以上是关于在这种情况下,为啥在调用 AviFileExit() 之前需要核对 IAviFile 指针?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 elisp 局部变量在这种情况下保持其值?

为啥 ngAfterContentInit 钩子被调用两次?

为啥 u-boot 在 rpi3 中调用 grub?

为啥在这种情况下需要 catch IOException

为啥在这种情况下星号位置存在差异,而其他情况则没有?

iOS 为啥在这种情况下 backBarButtonItem 为零