Watch, Follow, &
Connect with Us

Please visit our new home
community.embarcadero.com.


Welcome, Guest
Guest Settings
Help

Thread: Implementation of interface in TForm descendant



Permlink Replies: 2 - Last Post: Jun 26, 2017 11:42 AM Last Post By: Remy Lebeau (Te... Threads: [ Previous | Next ]
khanh hoa

Posts: 1
Registered: 7/17/17
Implementation of interface in TForm descendant
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 17, 2017 8:46 AM
This message is no longer available.
Antonio Estevez

Posts: 612
Registered: 4/12/00
Re: Implementation of interface in TForm descendant [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 17, 2017 9:30 AM   in response to: khanh hoa in response to: khanh hoa
El 17/06/2017 a las 17:52, khanh hoa escribió:
In example bellow compilation is without error, but in runtime Error: 'Pure virtual function called' is raised

File interface.h

//---------------------------------------------------------------------------
#ifndef InterfaceH
#define InterfaceH

__interface INTERFACE_UUID("{9EB5933E-7556-46FD-A3EB-85163E462809}") ITest : public IInterface
{
private:
protected:
public:
virtual void __fastcall SetTest(int Scale) = 0; // Pure virtual
virtual int __fastcall GetTest(void) = 0; // Pure virtual
__property int Test = { read = GetTest, write = SetTest };
};
typedef System::DelphiInterface<ITest> _di_Test;
#endif
//---------------------------------------------------------------------------

File Unit1.h
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include "Interface.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm, public ITest
{
__published: // IDE-managed Components
private: // User declarations
void __fastcall SetTest(int Scale) { }; // Override
int __fastcall GetTest(void) {return 1;}; // Override
public: // User declarations
__fastcall TForm1(TComponent* Owner);

};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

File Unit1.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
_di_Test i1;

if (this->GetInterface(i1)) // <====== Error: Pure virtual function called (Win32),
{
i1->Test = 1;

int x = i1->Test;
}
}
//---------------------------------------------------------------------------

Where is mistake? Thanks

You must implement both AddRef() and Release() methods of the IUnknown interface:

class TForm1 : public TForm, public ITest
{
__published:	// IDE-managed Components
private:	// User declarations
    // IUnknown
    virtual ULONG STDMETHODCALLTYPE AddRef(void);
    virtual ULONG STDMETHODCALLTYPE Release(void);
    // ITest
    void __fastcall SetTest(int Scale) { }; // Override
    int __fastcall GetTest(void) {return 1;}; // Override
public:		// User declarations
    __fastcall TForm1(TComponent* Owner);
};


ULONG STDMETHODCALLTYPE TForm1::AddRef( void)
{
    return _AddRef();
}
 
ULONG STDMETHODCALLTYPE TForm1::Release( void)
{
    return _Release();
}
Remy Lebeau (Te...


Posts: 8,942
Registered: 12/23/01
Re: Implementation of interface in TForm descendant [Edit]
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 19, 2017 10:20 AM   in response to: Antonio Estevez in response to: Antonio Estevez
Antonio Estevez wrote:

You must implement both AddRef() and Release() methods of the
IUnknown interface

And QueryInterface() as well.

These 3 methods are already implemented by TComponent for you. And
while your code example is correct (for AddRef() and Release(), but you
are missing QueryInterface()), you did not explain why you wrote the
code the way you did. This is actually documented on Embarcadero's
DocWiki:

http://docwiki.embarcadero.com/RADStudio/en/Inheritance_and_Interfaces#IUnknown_and_IInterface

The root issue is that "the Delphi definition of IUnknown, however,
does not correspond to the definition of IUnknown that is used in
C++Builder." Because of that, you have to implement the C++ version of
IUnknown and delegate it to the Delphi implementation of IIinterface:

class TForm1 : public TForm, public ITest
{
__published:	// IDE-managed Components
    //...
private:	// User declarations
public:		// User declarations
    __fastcall TForm1(TComponent* Owner);
 
    // IUnknown
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(const GUID &IID,
void **Obj);
    virtual ULONG STDMETHODCALLTYPE AddRef(void);
    virtual ULONG STDMETHODCALLTYPE Release(void);
 
    // ITest
    void __fastcall SetTest(int Scale);
    int __fastcall GetTest(void);
};
 
HRESULT STDMETHODCALLTYPE TForm1::QueryInterface(const GUID &IID, void
**Obj)
{
    return TForm::QueryInterface(IID, (void*)Obj); 
}
 
ULONG STDMETHODCALLTYPE TForm1::AddRef( void)
{
    return TForm::_AddRef();
}
 
ULONG STDMETHODCALLTYPE TForm1::Release( void)
{
    return TForm::_Release();
}
 
void __fastcall TForm1::SetTest(int Scale)
{
    //...
}
 
int __fastcall TForm1::GetTest(void)
{
    return ...;
}


You can simplify this by using the INTFOBJECT_IMPL_IUNKNOWN() macro,
which implements and delegates the IUnknown methods for you:

class TForm1 : public TForm, public ITest
{
__published:	// IDE-managed Components
    //...
private:	// User declarations
public:		// User declarations
    __fastcall TForm1(TComponent* Owner);
 
    // IUnknown
    INTFOBJECT_IMPL_IUNKNOWN(TForm);
 
    // ITest
    void __fastcall SetTest(int Scale);
    int __fastcall GetTest(void);
};
 
void __fastcall TForm1::SetTest(int Scale)
{
    //...
}
 
int __fastcall TForm1::GetTest(void)
{
    return ...;
}


--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02