在 Delphi 中无法从MSDN正确编写函数

5t7ly7z5  于 2023-02-15  发布在  其他
关注(0)|答案(1)|浏览(98)

我想创建我自己的过滤器并在DirectShow库中使用它。过滤器看起来可以写,但在创建图形时出现了问题。我的代码基于"Creating an Audio Capture Graph"文章。在最后,它说文章"Add a Filter by CLSID""Connect Two Filters"中的函数也被使用。我重写了最相似的函数,但代码不起作用。
我用许多个“!"指示错误的位置。
项目Project1.exe引发了异常类AEccessViolation,并返回消息“模块”Project1.exe“中地址0045 AAA 8处存在访问冲突。读取地址0000000”。进程已停止。请使用步骤或“运行”继续。
一般来说,我有以下代码:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, DirectShow9,ActiveX,BaseClass, DirectInput,
  StdCtrls,DirectSound, DirectSetup,  DirectPlay8,   DirectMusic,
  Dialogs;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListBox2: TListBox;
    procedure Button1Click(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
    function AddFilterByCLSID(pGraphA: IGraphBuilder; clsid: TGUID; wazName: PWideChar;  ppF: IBaseFilter): HRESULT;
    function ConnectFilter( pGraph: IGraphBuilder; pSrc: IBaseFilter; pdest: IBaseFilter): HRESULT;
    function GetUnconnectedPin(pFilter: IBaseFilter; PinDir: PIN_DIRECTION; ppPin: IPin): HRESULT;
    function ConnectFilterPin( pGraph: IGraphBuilder; pOut: IPin; pdest: IBaseFilter): HRESULT;
  end;
var
  PropertyName:IPropertyBag;
  pSrc, pWaveDest, pWriter: IBaseFilter; 
  pSink: IFileSinkFilter;
  pGraph: IGraphBuilder;
  FMediaControl: IMediaControl;
  pDevEnum: ICreateDevEnum;
  pEnum: IEnumMoniker;
  pMoniker: IMoniker;
  MArray1,MArray2: array of IMoniker;

  hr: HRESULT;

  DeviceName:OleVariant;
  FAudioCaptureFilter:  IBaseFilter;
const
  CLSID_WavDest : TGUID = '{3C78B8E2-6C4D-11d1-ADE2-0000F8754B99}';
  CLSID_CRleFilter: TGUID = '{BEBCF0A3-2673-42A7-82F2-5D4FC3126171}'; //My Filter.
  IID_ICRleFilter: TGUID = '{35C0AC80-C3E4-4EEA-A1F5-049401E29400}'; //Myfilter
var
  Form1: TForm1;

implementation

{$R *.dfm}

function TForm1.AddFilterByCLSID(pGraphA: IGraphBuilder; clsid: TCLSID;
  wazName: PWideChar; ppF: IBaseFilter): HRESULT;
var
 pF: IBaseFilter;
begin
 CoCreateInstance(clsid, nil, CLSCTX_INPROC_SERVER, IID_IBaseFilter, pF);
 hr:=pGraph.AddFilter(pF, WazName);

   if hr<> S_OK then
   begin
   ShowMessage('фильтр вавдеста не добавился');
   end;
   PPf:= pF;
//   pF._Release;
end;

procedure TForm1.Button1Click(Sender: TObject);
 var
   pOut: IPin;
begin
 HR:= CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER,
                   IID_IGraphBuilder, pGraph);

 if hr<> S_OK then
   begin
   ShowMessage('Граф не создался');
   end;
  HR:= CoCreateInstance(CLSID_SystemDeviceEnum, NIL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, pDevEnum);
 if hr<> S_OK then
   begin
   ShowMessage('перечеслитель не создался');
   Exit;
   end;

    HR:=pDevEnum.CreateClassEnumerator(CLSID_AudioInputDeviceCategory, pEnum, 0);
if HR<>S_OK  then EXIT;
//Обнуляем массив в списке моникеров
setlength(MArray2,0);
//Пускаем массив по списку устройств
while (S_OK=pEnum.Next(1,pMoniker,Nil)) do
begin
setlength(MArray2,length(MArray2)+1); //Увеличиваем массив на единицу
MArray2[length(MArray2)-1]:=pMoniker; //Запоминаем моникер в масиве
HR:=pMoniker.BindToStorage(NIL, NIL, IPropertyBag, PropertyName); //Линкуем моникер устройства к формату хранения IPropertyBag
if FAILED(HR) then Continue;
HR:=PropertyName.Read('FriendlyName', DeviceName, NIL); //Получаем имя устройства
if FAILED(HR) then Continue;
//Добавляем имя устройства в списки
Listbox2.Items.Add(DeviceName);
end;
 Listbox2.ItemIndex:=0;
   MArray2[Listbox2.ItemIndex].BindToObject(NIL, NIL, IID_IBaseFilter, FAudioCaptureFilter);
              //добавляем устройство в граф фильтров
              Pgraph.AddFilter(FAudioCaptureFilter, 'AudioCaptureFilter');
 // pGraph.AddFilter(pSrc, 'Capture');

  AddfilterByCLSID(pGraph, CLSID_CRleFilter, '_CRleFilter', pWaveDest);


  ConnectFilter(pGraph, pWaveDest, pWriter); // This is where the mistakes start !!!!!!!!!!!!!!!!!
  pGraph.QueryInterface(IID_IMediaControl, FMediaControl);

 FMediaControl.Run();
end;
{
There is no function overloading in Delphi, so I named the functions differently
                                                                                }
function TForm1.ConnectFilterPin(pGraph: IGraphBuilder; pOut: IPin;
  pdest: IBaseFilter): HRESULT;
  var
 pIn : IPin;
begin
  pIn:= nil;
  GetUnconnectedPin(pdest, PINDIR_OUTPUT, pIn);
  pGraph.Connect(pOut, pin);
end;

function TForm1.ConnectFilter(pGraph: IGraphBuilder; pSrc: IBaseFilter;
  pdest: IBaseFilter): HRESULT;
  var
    pOut: IPin;
begin
  //pOut:= 0;

   GetUnconnectedPin(pSrc, PINDIR_OUTPUT, pOut);
   ConnectFilterPin(pGraph, pOut, pdest);

end;

function TForm1.GetUnconnectedPin(pFilter: IBaseFilter;
  PinDir: PIN_DIRECTION; ppPin:  IPin): HRESULT;
var
 pEnum: IEnumPins;
 pPin: IPin;
 hr: HRESULT;
 ThisPinDir : PIN_DIRECTION;
 pTmp: IPin;
begin
  pTmp:=nil;
  ppPin:= nil;
 // pEnum:= nil;
  pPin:= nil;
 hr:= pFilter.EnumPins(pEnum); // This is where the error occurs !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  if hr<> S_OK then
  begin
    ShowMessage('перечесление пинов: не равно S_OK');
  end;

  while pEnum.Next(1, pPin, nil) = S_OK do
  begin
   pPin.QueryDirection(ThisPinDir);
   if ThisPinDir = PinDir then
    begin
     hr:= pPin.ConnectedTo(pTmp);
          if Succeeded(hr) then
           begin
            pTmp._Release;
           end else
           begin
           pEnum._Release;
           ppPin:= pPin;
           Result := S_OK;
           Exit;
           end;

          end;
       end;
      pPin._Release;
       
  ShowMessage('ошибка: не правильный код');
  Result:= E_FAIL;
 // ShowMessage('ошибка: не правильный код');

end;

end.

我希望错误是由指针引起的,或者更确切地说是指针的缺失。我试图把它们放在绝对所有的组合中,但这并没有导致期望的结果。此外,在 Delphi 中到处都根本没有使用指针。也许函数中的某个地方参数没有正确传递。我检查了所有的函数5次,试图找到错误,但这并不管用,指针也不管用。
我知道这个错误很小,很容易纠正,但我不知道它在哪里。

olhwl3o2

olhwl3o21#

错误不在指针中。Connect Filter函数的用途是连接两个筛选器。结构看起来像ConnectFilter(Graph, Filter 1, Filter 2);。我只向项目添加了一个筛选器。结果是,没有任何东西被发送到函数而不是第二个过滤器。有一个地址阅读错误,很难捕捉。如果我使用各种各样的检查,可能会很容易发现错误。由于C使用指针,而 Delphi 不使用,我以为错误是在指针中,因为我没有使用它们。但修复结果更简单:你需要添加第二个过滤器,并将其作为第三个参数发送。从这些错误中我们可以得出结论:
1.即使是在实验代码中,也值得进行尽可能多的检查。
1.仔细观看和阅读。
1.从其他函数调用的函数应该在这些函数之上。没有错误,但在Flenov M.E. The Bible of Delphi (第三版),chapter 5.4中指出: Delphi 中的程序和函数。其他错误的解决方法也在那里描述。
1.与C
不同, Delphi 不需要给新变量赋值nil,Delphi自己就可以完成。
1.您也不需要自己调用Release
我重写了代码,纠正了我注意到的所有错误。我将它留在下面:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, DirectShow9,ActiveX,BaseClass, DirectInput,
  StdCtrls,DirectSound, DirectSetup,  DirectPlay8,   DirectMusic,
  Dialogs;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListBox2: TListBox;
    procedure Button1Click(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
    function AddFilterByCLSID(pGraphA: IGraphBuilder; clsid: TGUID; wazName: PWideChar; var ppF: IBaseFilter): HRESULT;
    function ConnectFilter( pGraph: IGraphBuilder; pSrc: IBaseFilter; pdest: IBaseFilter): HRESULT;
    function GetUnconnectedPin(pFilter: IBaseFilter; PinDir: PIN_DIRECTION; var ppPin: IPin): HRESULT;
    function ConnectFilterPin( pGraph: IGraphBuilder; pOut: IPin; pdest: IBaseFilter): HRESULT;
  end;
var
  PropertyName:IPropertyBag;
  pSrc, pWaveDest, pWriter: IBaseFilter;
  pSink: IFileSinkFilter;
  pGraph: IGraphBuilder;
  FMediaControl: IMediaControl;
  pDevEnum: ICreateDevEnum;
  pEnum: IEnumMoniker;
  pMoniker: IMoniker;
  MArray1,MArray2: array of IMoniker;

  hr: HRESULT;

  DeviceName:OleVariant;
  FAudioCaptureFilter:  IBaseFilter;
const
  CLSID_WavDest : TGUID = '{3C78B8E2-6C4D-11d1-ADE2-0000F8754B99}';
  CLSID_CRleFilter: TGUID = '{BEBCF0A3-2673-42A7-82F2-5D4FC3126171}';
  IID_ICRleFilter: TGUID = '{35C0AC80-C3E4-4EEA-A1F5-049401E29400}';
var
  Form1: TForm1;

implementation

{$R *.dfm}

function TForm1.AddFilterByCLSID(pGraphA: IGraphBuilder; clsid: TCLSID;
  wazName: PWideChar; var ppF: IBaseFilter): HRESULT;
  {The last parameter of the function is returned,
   for this you need to add [ var ] before the declaration.
   Возвращается последний параметр функции,
    для этого вам нужно добавить [ var ] перед объявлением.}
var
  pf: IBaseFilter;
begin
  hr:= CoCreateInstance(clsid, nil, CLSCTX_INPROC_SERVER, IID_IBaseFilter, pF);
    if Succeeded(hr) then               // Added full error checking
    begin
      hr:=pGraph.AddFilter(pF, WazName);
      if Succeeded(hr) then
      begin
       ppf:= pf;
      end else
       ShowMessage('фильтр добавился / Filter not added');
    end else
     ShowMessage('фильтр добавился / Filter not added 2');
   Result:= hr;
end;

function TForm1.GetUnconnectedPin(pFilter: IBaseFilter;
  PinDir: PIN_DIRECTION; var ppPin:  IPin): HRESULT;
var
 pEnum: IEnumPins;
 pPin: IPin;
 hr: HRESULT;
 ThisPinDir : PIN_DIRECTION;
 pTmp: IPin;
begin
  //you don't need to assign [ nil ]; Delphi does it by itself.
  //Не нужно явно указывать [ nil ]; Delphi делает это самостоятельно.
 hr:= pFilter.EnumPins(pEnum);

  if Failed(hr) then
  begin
    ShowMessage('перечесление пинов: ошибка / pin listing: error');
  end;

  while pEnum.Next(1, pPin, nil) = S_OK do
  begin
   pPin.QueryDirection(ThisPinDir);
   if ThisPinDir = PinDir then
    begin
     hr:= pPin.ConnectedTo(pTmp);
          if Succeeded(hr) then
           begin
           end else
           begin
           ppPin:= pPin;
           Result := S_OK;
           Exit;
           end;
    end;
  end;

  ShowMessage('ошибка: не правильный код / error: invalid code');
  Result:= E_FAIL;

end;

function TForm1.ConnectFilterPin(pGraph: IGraphBuilder; pOut: IPin;
  pdest: IBaseFilter): HRESULT;
  var
 pIn : IPin;
begin
 GetUnconnectedPin(pdest, PINDIR_OUTPUT, pIn);
 pGraph.Connect(pOut, pin);
end;

function TForm1.ConnectFilter(pGraph: IGraphBuilder; pSrc: IBaseFilter;
  pdest: IBaseFilter): HRESULT;
  var
    pOut: IPin;
begin
   GetUnconnectedPin(pSrc, PINDIR_OUTPUT, pOut);
   ConnectFilterPin(pGraph, pOut, pdest);

end;

procedure TForm1.Button1Click(Sender: TObject);
 var
   pOut: IPin;
begin
 HR:= CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER,
                   IID_IGraphBuilder, pGraph);

 if hr<> S_OK then
   begin
   ShowMessage('Ошибка создания графа / Graph creation error');
   end;
  HR:= CoCreateInstance(CLSID_SystemDeviceEnum, NIL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, pDevEnum);
 if hr<> S_OK then
   begin
   ShowMessage('Ошибка создания графа / Graph creation error');
   Exit;
   end;

    HR:=pDevEnum.CreateClassEnumerator(CLSID_AudioInputDeviceCategory, pEnum, 0);
if HR<>S_OK  then EXIT;
 //Обнуляем массив в списке моникеров  /  Resetting the array in the list of monikers
 setlength(MArray2,0);
 //Пускаем массив по списку устройств  /  Let's run the array through the list of devices
while (S_OK=pEnum.Next(1,pMoniker,Nil)) do
begin
 setlength(MArray2,length(MArray2)+1); //Увеличиваем массив на единицу  /  Incrementing the array by one
 MArray2[length(MArray2)-1]:=pMoniker; //Запоминаем моникер в масиве  /  Remembering the moniker in the array
 HR:=pMoniker.BindToStorage(NIL, NIL, IPropertyBag, PropertyName); //Линкуем моникер устройства к формату хранения IPropertyBag
                                                                  // Link Device Monitor to IPropertyBag Storage Format
 if FAILED(HR) then Continue;
 HR:=PropertyName.Read('FriendlyName', DeviceName, NIL); //Получаем имя устройства  /  Getting the device name
 if FAILED(HR) then Continue;
 //Добавляем имя устройства в списки  /  Adding the device name to the lists
 Listbox2.Items.Add(DeviceName);
end;
 Listbox2.ItemIndex:=0;
 MArray2[Listbox2.ItemIndex].BindToObject(NIL, NIL, IID_IBaseFilter, FAudioCaptureFilter);
              //добавляем устройство в граф фильтров  /  adding a device to the filter graph

  Pgraph.AddFilter(FAudioCaptureFilter, 'AudioCaptureFilter');
  AddfilterByCLSID(pGraph, CLSID_FileWriter, 'File Writer', pWriter);
  AddfilterByCLSID(pGraph, CLSID_CRleFilter, '_CRleFilter', pWaveDest);

  {The error was that [ ConnectFilter ] connects two filters, and only one was specified.
   The first filter is specified in the second parameter; the second filter is
   specified in the third parameter; In order for the function to execute correctly,
   you must first add two filters, then use [ ConnectFilter ] }

  {Ошибка заключалась в том что [ ConnectFilter ] соединяет два фильтра,
   а задавался только один. Первый фильтр указан во втором параметре;
   второй фильтр указывается в третьем параметре; Что бы функция выполнилась правильно,
   нужно предварительно добавить два фильтра, затем использовать [ ConnectFilter ] }

  ConnectFilter(pGraph, FAudioCaptureFilter, pWaveDest);
  ConnectFilter(pGraph, pWaveDest, pWriter);

  pGraph.QueryInterface(IID_IMediaControl, FMediaControl);
  FMediaControl.Run();
end;

end.

相关问题