Проблема COM между неуправляемым C ++ и Delphi - PullRequest
2 голосов
/ 14 июля 2009

У меня есть DLL в неуправляемом C ++:

EditArticleManagerFactory.h:

class __declspec(dllexport) EditArticleManagerFactory : public NamedClassFactory<SCEditArticleManager>,
   public SCBLEditArticle:ICOMEditArticleManagerFactory
{
public:
   STDMETHODIMP CreateManager(BSTR bstrName, SCBLEditArticle::ICOMEditArticleManager** pEditArticleManager);

}


interface ICOMEditArticleManagerFactory : IUnknown
       {
          HRESULT CreateManager([in]BSTR bstrName, [out]ICOMEditArticleManager** pEditArticleManager);      
       }

EditArticleManagerFactory.cpp:

STDMETHODIMP EditArticleManagerFactory::CreateManager(BSTR bstrName,     SCBLEditArticle::ICOMEditArticleManager** pEditArticleManager)
  {
      manager = factory->createManager(bstrName);
       return manager->QueryInterface(__uuidof(SCBLEditArticle::ICOMEditArticleManager), (void**)&pEditArticleManager);
   }

Я хотел бы вызвать этот метод из Delphi, и он должен вернуть интерфейс для созданного менеджера.

Delphi:

function CreateManager(bstrName: wideString; pEditArticleManager: ICOMEditArticleManager): HResult; stdcall; external 'SCBLEditArticle.dll';

procedure CreateManager;
var
   hr:HResult;
   mCOMEditArticleManager: ICOMEditArticleManager;
begin
   hr := CreateManager('MANAGER1', mCOMEditArticleManager);
end;

Проблема в том, что я получаю нарушение прав доступа, когда оно достигает конца; в этом методе Дельфи.

У вас есть идеи, что может быть не так?

Спасибо, Руфус

Edit: Но я использую макрос для реализации Release и

EditArticleManagerFactory.h : 

IMPLEMENT_UNKNOWN_NODELETE(EditArticleManagerFactory) BEGIN_INTERFACE_TABLE(EditArticleManagerFactory) IMPLEMENTS_INTERFACE(SCBLEditArticle::ICOMEditArticleManagerFactory) END_INTERFACE_TABLE()

Inttable.cpp:
define IMPLEMENT_UNKNOWN_NODELETE(ClassName) \

STDMETHODIMP QueryInterface(REFIID riid, void **ppv) \ { \ HRESULT hr = InterfaceTableQueryInterface(this, GetInterfaceTable##ClassName(), riid, ppv);\ __if_exists(InheritedQueryInterface##ClassName) { if ( FAILED(hr) ) hr = InheritedQueryInterface##ClassName(riid, ppv); } \ return hr; \ }\ STDMETHODIMP_(ULONG) AddRef(void) { return 2; } \ STDMETHODIMP_(ULONG) Release(void) { return 1; }

Кроме того: Когда я отлаживаю в Delphi, я получаю нарушение прав доступа в UnsetExceptionHandler 004046F7 3901 cmp [ecx], eax. Может быть, это поможет диагностировать проблему.

Также, если я объявил внешнюю функцию вне моего класса C ++ и вызвал ее из Delphi, я не получил нарушения доступа, но не получил и указатель интерфейса.

Также: Если я ничего не делаю в методе C ++, я все равно получаю AccessViolation.

Ответы [ 3 ]

2 голосов
/ 14 июля 2009

Должно быть

function  CreateManager(bstrName: wideString; OUT pEditArticleManager: ICOMEditArticleManager): HResult; stdcall; external 'SCBLEditArticle.dll';

Заметьте "OUT", вы как-то сбросили косвенное (интерфейс только один *, а не два)

1 голос
/ 14 июля 2009

Странно, что вы пытаетесь объявить STDMETHODIMP CreateManager в вашем классе на C ++, это может вызвать проблемы.

Также COM предоставляет стандартный способ иметь фабрику объектов (class-object), которая отвечает на вызовы CoCreateInstance , вы можете захотеть взглянуть на это.

0 голосов
/ 14 июля 2009

Скорее всего, что-то не так с подсчетом ссылок.

Когда функция существует, счетчик ссылок на все интерфейсы уменьшается. Компилятор Delphi автоматически создает необходимый код для вызова ICOMEditArticleManager::Release.

Либо его реализация имеет недостатки, либо вы не возвращаете действительный IUnknown интерфейс.

Вы можете попробовать следующее:

  • В VC ++ установить точку останова при реализации ICOMEditArticleManager::Release
  • В Delphi переключитесь в режим CPU и пошагово пройдитесь по разобранному коду.

Таким образом, вы должны найти причину или, по крайней мере, сузить ее.

...