вызовите IKsTopologyInfo :: CreateNodeInstance из vidcap.h в Delphi - PullRequest
4 голосов
/ 11 сентября 2011

Я пишу крошечное приложение для управления веб-камерой в Delphi. У меня есть рабочий образец кода на C ++, и мне нужно переписать его на Delphi как часть моего приложения. Все отлично работает в Delphi, кроме одного вызова метода, который выдает сообщение «Нарушение доступа по адресу 63252469 в модуле« vidcap.ax ». Запись адреса 11D206FD».

Вот часть примера кода C ++, которая работает (без обработки ошибок):

#include <vidcap.h>         // For IKsTopologyInfo  
#include <ksproxy.h>        // For IKsControl  
....  
//pKsTopologyInfo is passed from the outside
IKsControl *pKsControl = NULL;  
DWORD dwNumNodes = 0;  
pKsTopologyInfo->get_NumNodes(&dwNumNodes);  
for(unsigned int i = 0; i < dwNumNodes; i++)  
{  
  pKsTopologyInfo->get_NodeType(i, &guidNodeType);  
  if(IsEqualGUID(guidNodeType, KSNODETYPE_DEV_SPECIFIC))  
  {  
    hr = pKsTopologyInfo->CreateNodeInstance(i, IID_IKsControl, (void **)&pKsControl);

А вот соответствующая часть моего кода в Delphi:

//KsTopologyInfo is IKsTopologyInfo passed from the outside  
//pKsControl is ^IKsControl, which is taken from DirectShow9.pas from DSPack components set.
KsTopologyInfo.get_NumNodes(@dwNumNodes);  
for i:=0 to dwNumNodes-1 do  
begin  
  KsTopologyInfo.get_NodeType(i,@guidNodeType);  
  if IsEqualGUID(guidNodeType,KSNODETYPE_DEV_SPECIFIC) then  
  begin  
    KsTopologyInfo.CreateNodeInstance(i,IID_IKsControl,@pKsControl);  

Ошибка возникает в коде Delphi в последней строке здесь, в то время как в C ++ она работает нормально.
Проверка во время пошагового отладчика не показывает каких-либо различий - как в Delphi, так и в C ++ он получает 11 для dwNumNodes, затем IsEqualGUID возвращает TRUE, когда i == 3 и guidNodeType == {941C7AC0-C559-11D0-8A2B-00A0C9255AC1}. Таким образом, в обоих случаях он вызывает CreateNodeInstance с одинаковыми значениями i = 3 и IID_IKsControl = {28F54685-06FD-11D2-B27A-00A0C9223196}

К сожалению, я не смог найти vidcap.h, преобразованный в файл .pas Delphi, поэтому я написал свое собственное описание для IKsTopologyInfo, и я полагаю, что у меня есть ошибка в описании метода CreateNodeInstance. Вот это из vidcap.h:

virtual HRESULT STDMETHODCALLTYPE CreateNodeInstance(  
  /* [in] */ DWORD dwNodeId,  
  /* [in] */ REFIID iid,  
  /* [out] */ void **ppvObject) = 0;  

А вот мой вариант для Delphi:

function CreateNodeInstance(dwNodeId:DWord; iid:TGuid; p:Pointer):HRESULT; stdcall;  

Я перепробовал множество вариантов с третьим параметром - var Obj, Pointer, PPointer (то есть ^ Pointer), а также попытался передать ему значения различных вариантов (IKsControl, ^ IKsControl, ^ (^ IKsControl), Pointer ^ Указатель - и ни один из них не работает. В любом случае я получил ту же ошибку.

Нужен какой-либо совет о том, как заставить его работать и как должно выглядеть правильное описание IKsTopologyInfo.CreateNodeInstance и вызывать в Delphi.

1 Ответ

2 голосов
/ 12 сентября 2011

Согласно MSDN определение REFIID :

typedef GUID IID;
typedef IID* REFIID;

Таким образом, REFIID является указателем на GUID и должно быть переведено как PGUID или, поскольку iid является входным параметром и представляется обязательным, его также можно передать как const TGUID.

Кроме того, MSDN утверждает, что в CreateNodeInstance :

ppvObject получает указатель на запрошенный интерфейс на объекте узла. Вызывающий должен освободить интерфейс .

Таким образом, третий параметр должен быть объявлен как указатель на интерфейс, чтобы позволить Delphi управлять им.Объявляя его как var IUnknown или как выходной параметр, как out IUnknown заставляет параметр быть переменной типа IUnknown и, следовательно, должен быть приведен к реальному типу интерфейса.для его использования.

Объявление C ++

virtual HRESULT STDMETHODCALLTYPE CreateNodeInstance(  
  /* [in] */ DWORD dwNodeId,  
  /* [in] */ REFIID iid,  
  /* [out] */ void **ppvObject) = 0;

становится

function CreateNodeInstance(dwNodeId: DWord; const iid: TGUID; ppvObject: PUnknown): HRESULT; stdcall;

и может вызываться следующим образом:

var
  KsControl: IKsControl;

KsTopologyInfo.CreateNodeInstance(i, IID_IKsControl, @KsControl);
...