views:

521

answers:

2

I have some code which handles data files and reports an error when it runs into trouble, but I'm having trouble working out how to give my class a callback function. Here's a quick example of the sort of thing I'm trying to achieve:

public delegate void Reporter( System::String^ stringToReport );

/// <summary>
/// Simple file handler with callback options on error
/// </summary>
public ref class MyFileHandler
{
private:
 Reporter^ m_reporter;

 void ReportError(String^ error)
 {
  if( m_reporter )
  {
   m_reporter( error );
  }
 }

public:
 MyFileHandler()
 {

 }

 void SetErrorReporter( Reporter^ reporter )
 {
  m_reporter = reporter;
 }

 bool FailingOperation()
 {
  return false;
 }

 bool GetData()
 {
  bool succeeded = false;

  // Do some operation that fails
  succeeded = FailingOperation();

  if( succeeded == false )
  {
   ReportError( "Gah, something bad happened!" );
  }

 }
};


public ref class MyFileLoader
{
private:
 MyFileHandler m_mfh;

 void ErrorHandler(String^ errorMsg)
 {
  System::Windows::Forms::MessageBox::Show( errorMsg );
 }

public:
 MyFileLoader()
 {
  m_mfh.SetErrorReporter( &CallbackFunctionTests::MyFileLoader::ErrorHandler );
 }
};

...which has a problem:

1>CallbackTest.h(131) : error C3374: can't take address of 'CallbackFunctionTests::MyFileLoader::ErrorHandler' unless creating delegate instance

So I get the impression I'm mis-using or misunderstanding things. Maybe there's a better way of achieving this?

+3  A: 

You need to create the delegate explicitly – and you need to pass the associated instance – in your case, this – to it:

m_mfh.SetErrorReporter(
    gcnew Reporter(this, &CallbackFunctionTests::MyFileLoader::ErrorHandler));
Konrad Rudolph
+1/Accepted: Excellent - that got it :-)
Jon Cage
A: 

In case anyone's interested, here's the final (working) code:

public delegate void Reporter( System::String^ stringToReport );

/// <summary>
/// Simple file handler with callback options on error
/// </summary>
public ref class MyFileHandler
{
private:
 Reporter^ m_reporter;

 void ReportError(String^ error)
 {
  if( m_reporter )
  {
   m_reporter( error );
  }
 }

public:
 MyFileHandler()
 {

 }

 void SetErrorReporter( Reporter^ reporter )
 {
  m_reporter = reporter;
 }

 bool FailingOperation()
 {
  return false;
 }

 bool GetData()
 {
  bool succeeded = false;

  // Do some operation that fails
  succeeded = FailingOperation();

  if( succeeded == false )
  {
   ReportError( "Gah, something bad happened!" );
  }

  return succeeded;
 }
};


public ref class MyFileLoader
{
private:
 MyFileHandler m_mfh;

 void ErrorHandler(String^ errorMsg)
 {
  System::Windows::Forms::MessageBox::Show( errorMsg );
 }

public:
 MyFileLoader()
 {
  m_mfh.SetErrorReporter( gcnew Reporter(this, &CallbackFunctionTests::MyFileLoader::ErrorHandler) );
 }
};
Jon Cage