[Android]Error class ENotImplemented

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

[Android]Error class ENotImplemented

Postby Lena » Thu Oct 16, 2014 1:39 am

Hello.
I have code that successfully works without problems in RAD XE6. In the final APK no problem.
If I move this code in RAD XE7, then in the final APK an error class ENotImplemented, message Blocking dialogs not implemented on this platform.
The error occurs when I click on the button that has the following code:
Code: Select all
if (MessageDlg(L"Delete: " + LabelSection->Text + L"?", TMsgDlgType::mtConfirmation, TMsgDlgButtons() << TMsgDlgBtn::mbYes << TMsgDlgBtn::mbNo, 0) == mrYes)
{
//***
}

How I can fix it in RAD XE7? Show me an example please.
In APK from RAD XE6 I see the dialog box without any problems and error messages.
Thanks.
Lena
BCBJ Master
BCBJ Master
 
Posts: 636
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Android]Error class ENotImplemented

Postby minas » Thu Oct 16, 2014 10:43 am

The following may explain how is the situation with XE7 regarding Blocking MessageDlg

http://docwiki.embarcadero.com/RADStudi ... ir_Closing

Just to highlight some points

MessageDlg support a new optional parameter, <ACloseDialogProc>. Calls that include this new parameter work on all platforms, including Android.

If you call InputBox, InputQuery, or MessageDlg and you do not provide an anonymous method on your call, these methods behave as they used to behave in XE6: calls are blocking on all platforms, including iOS, and Android is not supported.
User avatar
minas
BCBJ Guru
BCBJ Guru
 
Posts: 199
Joined: Sat Jul 10, 2004 6:09 am
Location: Greece

Re: [Android]Error class ENotImplemented

Postby rlebeau » Thu Oct 16, 2014 4:57 pm

minas wrote:The following may explain how is the situation with XE7 regarding Blocking MessageDlg


The catch is that the anonymous procedure is now required for Android, but implementing an anonymous procedure in C++ is more difficult than in Delphi.

How to Handle Delphi Anonymous Methods in C++

For example:

Code: Select all
class TMyMessageDlgCloseProc : public TInterfacedObject, public Fmx::Dialogs::TInputCloseDialogProc
{
public:
    HRESULT STDMETHODCALLTYPE QueryInterface (const GUID& riid, void** ppvObject) { return TInterfacedObject::QueryInterface (riid, ppvObject); }
    ULONG STDMETHODCALLTYPE AddRef() { return TInterfacedObject::_AddRef(); }
    ULONG STDMETHODCALLTYPE Release() { return TInterfacedObject::_Release(); }
 
    void __fastcall Invoke(const TModalResult AResult)
    {
        if (AResult == mrYes)
        {
            //***
        }
    }
};


Code: Select all
_di_TInputCloseDialogProc proc = new TMyMessageDlgCloseProc;
MessageDlg(L"Delete: " + LabelSection->Text + L"?", TMsgDlgType::mtConfirmation, TMsgDlgButtons() << TMsgDlgBtn::mbYes << TMsgDlgBtn::mbNo, 0, proc);


If you need to make multiple MessageDlg() calls, look at the template example that the above link provides, so that you can reuse a single TInputCloseDialogProc implementation for different object methods.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1665
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Android]Error class ENotImplemented

Postby Lena » Sat Oct 18, 2014 3:49 am

Thank you for your help! How I can fix this error?
In main cpp:
Code: Select all
class TMyMessageDlgCloseProc : public TInterfacedObject, public Fmx::Dialogs::TInputCloseDialogProc
{
   public:
      HRESULT STDMETHODCALLTYPE QueryInterface (const GUID& riid, void** ppvObject) { return TInterfacedObject::QueryInterface (riid, ppvObject); }
      ULONG STDMETHODCALLTYPE AddRef() { return TInterfacedObject::_AddRef(); }
      ULONG STDMETHODCALLTYPE Release() { return TInterfacedObject::_Release(); }

      void __fastcall Invoke(const TModalResult AResult, int number)
      {
         switch (number)
         {
          case 1:
            {
             if (AResult == mrYes)
               {
               //***
               }
             break;
            }

          case 2:
            {
             if (AResult == mrYes)
               {
               //***
               }
             break;
            }
         default:
            ;
         }



      }
};

TMainForm *MainForm;

//*****************************
_di_TInputCloseDialogProc proc = new TMyMessageDlgCloseProc;
 MessageDlg(L"Delete: " + LabelSection->Text + L"?", TMsgDlgType::mtConfirmation, TMsgDlgButtons() << TMsgDlgBtn::mbYes << TMsgDlgBtn::mbNo, 0, proc, 1);

//*****************************
_di_TInputCloseDialogProc proc = new TMyMessageDlgCloseProc;
 MessageDlg(L"Delete: " + LabelSection->Text + L"?", TMsgDlgType::mtConfirmation, TMsgDlgButtons() << TMsgDlgBtn::mbYes << TMsgDlgBtn::mbNo, 0, proc, 2);



[bccaarm Error] MobUnit1.cpp(715): allocating an object of abstract class type 'TMyMessageDlgCloseProc'
sysmac.h(300): unimplemented pure virtual method 'QueryInterface' in 'TMyMessageDlgCloseProc'
FMX.Dialogs.hpp(182): unimplemented pure virtual method 'Invoke' in 'TMyMessageDlgCloseProc'
Lena
BCBJ Master
BCBJ Master
 
Posts: 636
Joined: Sun Feb 06, 2011 1:28 pm

Re: [Android]Error class ENotImplemented

Postby rlebeau » Sat Oct 18, 2014 7:14 pm

Lena wrote:Thank you for your help! How I can fix this error?


The compiler should not be complaining about QueryInterface() being abstract, as TMyMessageDlgCloseProc does implement it. The only way it could be causing an error is if the signature of QueryInterface() is different on Android than what I showed (I did not check).

The Invoke() error is because you added an extra parameter to your Invoke() method, so it is no longer overriding the TInputCloseDialogProc::Invoke() method. You cannot change the signature of Invoke()! And you are trying to pass the extra value via an additional parameter of MessageDlg(), but there is no such parameter, so the compiler should be complaing about that as well.

If you need to pass an extra value to your close procedure, you have to do so via the constructor instead, eg:

Code: Select all
class TMyMessageDlgCloseProc : public TInterfacedObject, public Fmx::Dialogs::TInputCloseDialogProc
{
private:
    int FNumber;

public:
    TMyMessageDlgCloseProc(int ANumber)
        : TInterfacedObject(), FNumber(ANumber)
    {
    }

    HRESULT STDMETHODCALLTYPE QueryInterface (const GUID& riid, void** ppvObject) { return TInterfacedObject::QueryInterface (riid, ppvObject); }
    ULONG STDMETHODCALLTYPE AddRef() { return TInterfacedObject::_AddRef(); }
    ULONG STDMETHODCALLTYPE Release() { return TInterfacedObject::_Release(); }

    void __fastcall Invoke(const TModalResult AResult)
    {
        switch (FNumber)
        {
            ...
        }
    }
};


Code: Select all
_di_TInputCloseDialogProc proc = new TMyMessageDlgCloseProc(1);
MessageDlg(L"Delete: " + LabelSection->Text + L"?", TMsgDlgType::mtConfirmation, TMsgDlgButtons() << TMsgDlgBtn::mbYes << TMsgDlgBtn::mbNo, 0, proc);


Code: Select all
_di_TInputCloseDialogProc proc = new TMyMessageDlgCloseProc(2);
 MessageDlg(L"Delete: " + LabelSection->Text + L"?", TMsgDlgType::mtConfirmation, TMsgDlgButtons() << TMsgDlgBtn::mbYes << TMsgDlgBtn::mbNo, 0, proc);


Otherwise, you need to use separate classes instead, eg:

Code: Select all
class TMyMessageDlgCloseProc1 : public TInterfacedObject, public Fmx::Dialogs::TInputCloseDialogProc
{
public:
    HRESULT STDMETHODCALLTYPE QueryInterface (const GUID& riid, void** ppvObject) { return TInterfacedObject::QueryInterface (riid, ppvObject); }
    ULONG STDMETHODCALLTYPE AddRef() { return TInterfacedObject::_AddRef(); }
    ULONG STDMETHODCALLTYPE Release() { return TInterfacedObject::_Release(); }

    void __fastcall Invoke(const TModalResult AResult)
    {
        ...
    }
};

class TMyMessageDlgCloseProc2 : public TInterfacedObject, public Fmx::Dialogs::TInputCloseDialogProc
{
public:
    HRESULT STDMETHODCALLTYPE QueryInterface (const GUID& riid, void** ppvObject) { return TInterfacedObject::QueryInterface (riid, ppvObject); }
    ULONG STDMETHODCALLTYPE AddRef() { return TInterfacedObject::_AddRef(); }
    ULONG STDMETHODCALLTYPE Release() { return TInterfacedObject::_Release(); }

    void __fastcall Invoke(const TModalResult AResult)
    {
        ...
    }
};


Code: Select all
_di_TInputCloseDialogProc proc = new TMyMessageDlgCloseProc1;
MessageDlg(L"Delete: " + LabelSection->Text + L"?", TMsgDlgType::mtConfirmation, TMsgDlgButtons() << TMsgDlgBtn::mbYes << TMsgDlgBtn::mbNo, 0, proc);


Code: Select all
_di_TInputCloseDialogProc proc = new TMyMessageDlgCloseProc2;
 MessageDlg(L"Delete: " + LabelSection->Text + L"?", TMsgDlgType::mtConfirmation, TMsgDlgButtons() << TMsgDlgBtn::mbYes << TMsgDlgBtn::mbNo, 0, proc);


Or, use the template wrapper class that is provided in the article I linked to earlier:

Code: Select all
void __fastcall TMyForm::CloseProc1(const TModalResult AResult)
{
    ...
}

void __fastcall TMyForm::CloseProc2(const TModalResult AResult)
{
    ...
}

void __fastcall TMyForm::DoSomething()
{
    ...
    _di_TInputCloseDialogProc proc = new TMethodRef<TInputCloseDialogProc, void (__closure*)(const TModalResult), void, const TModalResult>(&CloseProc1);
    MessageDlg(L"Delete: " + LabelSection->Text + L"?", TMsgDlgType::mtConfirmation, TMsgDlgButtons() << TMsgDlgBtn::mbYes << TMsgDlgBtn::mbNo, 0, proc);
    ...
}

void __fastcall TMyForm1::DoSomethingElse()
{
    ...
    _di_TInputCloseDialogProc proc = new TMethodRef<TInputCloseDialogProc, void (__closure*)(const TModalResult), void, const TModalResult>(&CloseProc2);
    MessageDlg(L"Delete: " + LabelSection->Text + L"?", TMsgDlgType::mtConfirmation, TMsgDlgButtons() << TMsgDlgBtn::mbYes << TMsgDlgBtn::mbNo, 0, proc);
    ...
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1665
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: [Android]Error class ENotImplemented

Postby Lena » Sun Oct 19, 2014 11:23 am

Thank you very much!!!
Lena
BCBJ Master
BCBJ Master
 
Posts: 636
Joined: Sun Feb 06, 2011 1:28 pm


Return to Technical

Who is online

Users browsing this forum: No registered users and 17 guests