Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在DirectShow筛选器';s EnumPins方法(Delphi/DSPACK)?_Delphi_Filter_Directshow_Dspack - Fatal编程技术网

在DirectShow筛选器';s EnumPins方法(Delphi/DSPACK)?

在DirectShow筛选器';s EnumPins方法(Delphi/DSPACK)?,delphi,filter,directshow,dspack,Delphi,Filter,Directshow,Dspack,我在WindowsXP/32机器上使用DSPACK DirectShow组件库在Delphi6中编写了一个自定义推送源代码过滤器。在编码过程中,当我在应用程序的编译器选项中打开范围检查后,我遇到了一个问题,即属于DSPACK(BaseClass.pas)的基类单元中出现了范围检查错误 错误发生在使用EnumPins()方法的过程中。注意,此方法驻留在DSPACK的基类单元中,而不是我的应用程序中。我跟踪了这个问题,发现它发生在我构建的使用我的过滤器的过滤器图播放过滤器时。请注意,我的筛选器将作为

我在WindowsXP/32机器上使用DSPACK DirectShow组件库在Delphi6中编写了一个自定义推送源代码过滤器。在编码过程中,当我在应用程序的编译器选项中打开范围检查后,我遇到了一个问题,即属于DSPACK(BaseClass.pas)的基类单元中出现了范围检查错误

错误发生在使用EnumPins()方法的过程中。注意,此方法驻留在DSPACK的基类单元中,而不是我的应用程序中。我跟踪了这个问题,发现它发生在我构建的使用我的过滤器的过滤器图播放过滤器时。请注意,我的筛选器将作为未注册的专用筛选器而不是外部AX直接合并到我的应用程序中。当DirectShow调用基类方法TBCEnumPins.Next()时,如果ppPins参数为NIL,则会发生范围检查错误。由于我不是DirectShow专家,我不确定在不干扰DirectShow pin枚举过程的正确流程的情况下,修复此错误的正确方法是什么。如果它是一个不可忽略的真实错误条件,那么我需要知道在该事件中要抛出的正确异常或要返回的HRESULT代码是什么。有人能告诉我调整NIL ppPins参数的正确方法吗?完整的方法代码如下所示,范围检查错误发生的行突出显示:

function TBCEnumPins.Next(cPins: ULONG; out ppPins: IPin; pcFetched: PULONG): HRESULT;
type
  TPointerDynArray = array of Pointer;
  TIPinDynArray = array of IPin;
var
  Fetched: cardinal;
  RealPins: integer;
  Pin: TBCBasePin;
begin
    // ATI: Debugging range check error.
    try
        if pcFetched <> nil then
          pcFetched^ := 0
        else
          if (cPins>1) then
          begin
            result := E_INVALIDARG;
            exit;
          end;
        Fetched := 0; // increment as we get each one.

        // Check we are still in sync with the filter
        // If we are out of sync, we should refresh the enumerator.
        // This will reset the position and update the other members, but
        // will not clear cache of pins we have already returned.
        if AreWeOutOfSync then
          Refresh;

        // Calculate the number of available pins
        RealPins := min(FPinCount - FPosition, cPins);
        if RealPins = 0 then
        begin
          result := S_FALSE;
          exit;
        end;

        {  Return each pin interface NOTE GetPin returns CBasePin * not addrefed
           so we must QI for the IPin (which increments its reference count)
           If while we are retrieving a pin from the filter an error occurs we
           assume that our internal state is stale with respect to the filter
           (for example someone has deleted a pin) so we
           return VFW_E_ENUM_OUT_OF_SYNC }

        while RealPins > 0 do
        begin
          // Get the next pin object from the filter */
          inc(FPosition);
          Pin := FFilter.GetPin(FPosition-1);
          if Pin = nil then
          begin
            // If this happend, and it's not the first time through, then we've got a problem,
            // since we should really go back and release the iPins, which we have previously
            // AddRef'ed.
            ASSERT(Fetched = 0);
            result := VFW_E_ENUM_OUT_OF_SYNC;
            exit;
          end;

          // We only want to return this pin, if it is not in our cache
          if FPinCache.IndexOf(Pin) = -1 then
          begin
            // From the object get an IPin interface
            TPointerDynArray(@ppPins)[Fetched] := nil; // <<<<<< THIS IS WHERE THE RANGE CHECK ERROR OCCURS.
            TIPinDynArray(@ppPins)[Fetched] := Pin;
            inc(Fetched);
            FPinCache.Add(Pin);
            dec(RealPins);
          end;
        end; // while RealPins > 0 do

        if (pcFetched <> nil) then pcFetched^ := Fetched;

        if (cPins = Fetched) then result := NOERROR else result := S_FALSE;
    except
        On E: Exception do
        begin
            OutputDebugString(PChar(
                '(TBCEnumPins.Next) Exception class name(' + E.ClassName + ') message: ' + E.Message
            ));

            raise;
        end;
    end;
end;
通过告诉Next()方法要检索多少个管脚,TBCEnumPins.Next()方法代码及其异常的动态数组强制转换结果是安全的,因为它只会将Next()函数“cPins”参数中请求的管脚数复制到ppPins“out”参数中。只要调用方通过一个目标缓冲区,该缓冲区可以保存“cPins”中请求的管脚数,一切都可以正常工作(只要关闭范围检查)。注意,在本例中,名为“outPin”的IPin变量是目标缓冲区。如果打开范围检查,则会发生范围检查错误,因为Delphi将NIL视为零长度数组。

方法不应使用
ppPins==NULL
调用。因此,最好的处理方法是立即返回
E_指针
错误代码


您可能需要检查调用方的代码,以了解为什么您首先在那里有
NULL

我怀疑您对
ppPins
参数的声明以及对
TPointerDynArray
TIPinDynArray
的强制转换

如果假装传入的数组是Delphi动态数组,而实际上不是,则会出现范围错误。Delphi动态数组在数组的第一项之前有一个内存块,用于标识数组的引用计数及其长度。由于数组中缺少此块,因此诱使编译器相信它存在将导致您看到的错误

我会按如下所示做。这与MSDN中使用的声明相匹配。您必须使用一点指针运算,但我相信这样做更容易,因为您的代码现在将很容易与您可以在线查找的任何C++样本相关。
type
  PIPin = ^IPin;

function TBCEnumPins.Next(cPins: ULONG; ppPins: PIPin; pcFetched: PULONG): HRESULT;
begin
  ... 
  // this is the meat of the loop, assign to the output array, and increment
  Pointer(ppPins)^ := nil; // initialise the intf ref to avoid bogus _Release
  ppPins^ := Pin;
  inc(ppPins);
  ...
end;

我实际上怀疑pppin是否真的是空的。如果是,则将出现访问冲突,而不是范围错误。
ppPins
的COM声明是指向
IPin
的指针,但问题中的代码以可疑的方式使用了
out
参数,这一事实也使问题变得复杂。同意。谈到范围检查,如果调用者请求同时枚举2个以上的pin,并且函数的定义方式是
ppPins
是单个值,而不是数组,那么问题可能会出现。尽管如此,OP还是询问了
NULL
参数,现在开始。我认为调用代码不是外部的,OP在自己的代码中调用方可能有问题。@David Heffernan。你确定这里一定会发射A/V吗?Delphi将NIL数组视为零长度,如果编译器首先将其视为零长度,则当索引应用于空数组时,将在访问冲突之前触发范围检查错误,因为它是零长度。@RobertOschler是的,您是正确的。我的错误。但是你必须理解我对动态数组的误用。您复制的示例代码可能与范围检查一起工作。在上面链接后面的代码段中,
ppPins
永远不会是
NULL
,它始终是一个有效指针。您好@David Heffeman。我会解释代码,但正如我所说,这是DSPACK附带的库存代码,所以我不知道其结构背后的原因。注意“范围检查错误”是DSPACK(progdigy)论坛上的一个已知错误。我会试试你的代码。@Robert我加了一行代码。我意识到我忽略了一个事实,即数组需要进行零初始化,以避免Delphi在调用未初始化的引用时写入发布。老实说,在loop.Heffeman之外调用FillChar或ZeroMemory可能是最简单的。请参阅我在Roman的回复中对“out”参数/NIL组合的评论。@Robert
ppPins
不应为
NULL
。我的意思是,根据MSDN,而不是在您的代码中。如果你能回答我关于什么是
NULL
的问题,那就容易多了。无论如何,当范围检查打开时,您的原始代码显然是错误的。我相信我的回答解释了你所报道的一切。正如我所说,这不是我的代码。它是DSPACK基类单元的一部分。如果调用方调用TBCEnumPins.Next()时目标缓冲区中恰好出现了这种情况,则ppPins可以为NIL。如果为NIL,则在启用范围检查时,它将被视为零长度数组。NIL恰好位于ppPins指向的目标缓冲区的开始处。通过添加
type
  PIPin = ^IPin;

function TBCEnumPins.Next(cPins: ULONG; ppPins: PIPin; pcFetched: PULONG): HRESULT;
begin
  ... 
  // this is the meat of the loop, assign to the output array, and increment
  Pointer(ppPins)^ := nil; // initialise the intf ref to avoid bogus _Release
  ppPins^ := Pin;
  inc(ppPins);
  ...
end;