2

I have a DLL in unmanaged 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);
   }

I'd like to call this method from Delphi and it should return an interface to a created manager.

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;

The problem is I get an access violation when it reaches the end; in this delphi method.

Do you have any ideea what could be wrong?

Thx, rufusz

Edit: But I'm using a macro for implementing Release and

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; }

Furthermore : When I debug from Delphi, I get the access violation in the UnsetExceptionHandler 004046F7 3901 cmp [ecx],eax. Maybe this can help to diagnose the problem.

Also if I declared an external function outside my C++ class, and called that from Delphi, I didn't get the access violation, but didn't get the interface pointer neither.

Also: If I do nothing in the C++ method, I still get the AccessViolation.

3 Answers 3

2

Should be

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

Notice the "OUT", you somehow dropped a indirection. (an interface is only one *, not two)

Sign up to request clarification or add additional context in comments.

2 Comments

In the .idl if I declare it with one * HRESULT CreateManager([in]...,[out]ICOMEditArticleManager* pEdit..) I get a compiler error that out pointers should use double indirection : error MIDL2284 : [out] interface pointers must use double indirection
Rufus, you have to get it right in both languages. You already had it right in C++. Your Delphi code was wrong. The C++ needs two stars because interfaces are just ordinary classes there. You need a pointer to the object, and then a pointer to the pointer. Delphi interfaces are already references, so you just need one additional reference, which you get with out. The IDL [out] doesn't actually do anything; it's just documentation.
1

It's odd you try to declare STDMETHODIMP CreateManager within your class in C++, this may be causing trouble.

Also COM provides a standard way of having an object-factory (class-object), which responds to CoCreateInstance calls, you may want to have a look at that.

3 Comments

Can you elaborate on this? CoCreateInstance should be called from Delphi to create a COM object? Or how?
Declaring the function in the class is definitely causing problems; Rufus mentions that making it a standalone function makes the crash go away. He has two problems, and both need fixing before things will work. He needs to make the C++ function a non-member (or static member), and he needs to use out on the Delphi declaration.
To elaborate: you mention you have a DLL written in C++? Does it contain a TypeLibrary, does it export DllGetClassObject msdn.microsoft.com/en-us/library/ms680760(VS.85).aspx (preferably using a framework like ATL)? Is it properly registered in the registry (HKEY_CLASSES_ROOT\CLSID and other)? Then CoCreateInstance will do the work for you of loading and linking the DLL and creating an object.
0

Most likely there's something wrong with the reference counting.

When the function exists, the reference count to all interfaces is decremented. The Delphi compiler automatically creates the necessary code to call ICOMEditArticleManager::Release.

Either its implementation is flawed or you are not returning a valid IUnknown interface.

You can try the following:

  • In VC++ set a breakpoint at the implementation of ICOMEditArticleManager::Release
  • In Delphi switch to the CPU mode and single-step through the disassembled code.

That way you should find the cause or at least narrow it down.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.