Premnath Mali Ответов: 2

Как создать указатель на функцию обратного вызова в MFC


Я работаю над демо биометрическим проектом в MFC
В msdn у нас есть некоторые функции обратного вызова, но для их использования нам нужно создать указатель на функцию-член, как это сделать.

Получаю эту ошибку:

Ошибка 1 ошибка c2440: '=' : не удается конвертировать из 'пустоты (как__stdcall CBioMetricApplicationDlg::* )(PVOID,значение HRESULT,WINBIO_UNIT_ID,PWINBIO_BIR,реализация,WINBIO_REJECT_DETAIL)" для " Void (__thiscall CBioMetricApplicationDlg::* )(PVOID,значение HRESULT,WINBIO_UNIT_ID,PWINBIO_BIR,реализация,WINBIO_REJECT_DETAIL)'

Что я уже пробовал:

// in header file CBioMetricApplicationDlg.h ...

VOID CALLBACK CaptureCallback(
__in_opt PVOID CaptureCallbackContext,
__in HRESULT OperationStatus,
__in WINBIO_UNIT_ID UnitId,
__in_bcount(SampleSize) PWINBIO_BIR Sample,
__in SIZE_T SampleSize,
__in WINBIO_REJECT_DETAIL RejectDetail
);


VOID CALLBACK(CBioMetricApplicationDlg:: *pCaptureCallback) (
__in_opt PVOID CaptureCallbackContext,
__in HRESULT OperationStatus,
__in WINBIO_UNIT_ID UnitId,
__in_bcount(SampleSize) PWINBIO_BIR Sample,
__in SIZE_T SampleSize,
__in WINBIO_REJECT_DETAIL RejectDetail
);


// in cpp file CBioMetricApplicationDlg.cpp
//in the OnInitDialog() 

// TODO: Add extra initialization here
pCaptureCallback = &CBioMetricApplicationDlg::CaptureCallback;

2 Ответов

Рейтинг:
17

Jochen Arndt

Он является общим, чтобы использовать typedef для таких функций, потому что это облегчает объявление указателей.

Для вашего случая см. Указатель функции PWINBIO_CAPTURE_CALLBACK (Windows)[^]:

typedef VOID ( CALLBACK *PWINBIO_CAPTURE_CALLBACK)(
  _In_opt_ PVOID                CaptureCallbackContext,
  _In_     HRESULT              OperationStatus,
  _In_     WINBIO_UNIT_ID       UnitId,
  _In_     PWINBIO_BIR          Sample,
  _In_     SIZE_T               SampleSize,
  _In_     WINBIO_REJECT_DETAIL RejectDetail
);

Затем объявите переменную как
PWINBIO_CAPTURE_CALLBACK pCaptureCallback;

[РЕДАКТИРОВАТЬ]
Я не был уверен как CALLBACK решается. Но кажется, что он не содержит static Поскольку функции обратного вызова должны быть статическими, объявление в качестве функции-члена класса должно быть
/* CBioMetricApplicationDlg.h */
static VOID CALLBACK CaptureCallback(
    __in_opt PVOID CaptureCallbackContext,
    __in HRESULT OperationStatus,
    __in WINBIO_UNIT_ID UnitId,
    __in_bcount(SampleSize) PWINBIO_BIR Sample,
    __in SIZE_T SampleSize,
    __in WINBIO_REJECT_DETAIL RejectDetail
    );
Чтобы получить доступ к классу внутри функции обратного вызова пройдите this как параметр контекста:
/* CBioMetricApplicationDlg.cpp */
hr = WinBioCaptureSampleWithCallback(
    sessionHandle,
    WINBIO_NO_PURPOSE_AVAILABLE,
    WINBIO_DATA_FLAG_RAW,
    CaptureSampleCallback,
    this);
и приведите параметр в функцию обратного вызова:
/* CBioMetricApplicationDlg.cpp */
VOID CBioMetricApplicationDlg::CaptureCallback(
    __in_opt PVOID CaptureCallbackContext,
    __in HRESULT OperationStatus,
    __in WINBIO_UNIT_ID UnitId,
    __in_bcount(SampleSize) PWINBIO_BIR Sample,
    __in SIZE_T SampleSize,
    __in WINBIO_REJECT_DETAIL RejectDetail
    )
{
    CBioMetricApplicationDlg *pThis = reinterpret_cast<CBioMetricApplicationDlg*>(CaptureCallbackContext);
    // Use pThis to access class members
    // ...
}
[/РЕДАКТИРОВАТЬ]


Premnath Mali

получение этой ошибки при инициализации
pCaptureCallback = &CBioMetricApplicationDlg:: CaptureCallback;

Jochen Arndt

Все та же ошибка?
Я не могу проверить это здесь в данный момент.
Вы можете попробовать упростить typedef:

typedef VOID (*PWINBIO_CAPTURE_CALLBACK)(
  PVOID                CaptureCallbackContext,
  HRESULT              OperationStatus,
  WINBIO_UNIT_ID       UnitId,
  PWINBIO_BIR          Sample,
  SIZE_T               SampleSize,
  WINBIO_REJECT_DETAIL RejectDetail
);

Это предполагает, что обратный вызов разрешает что-то содержащее static.
Если нет, то вы должны объявить функцию как статическую в вашем заголовочном файле:
static VOID CALLBACK CaptureCallback(
// ...

Premnath Mali

//in header file
VOID CALLBACK CaptureCallback(
__in_opt PVOID CaptureCallbackContext,
__in HRESULT OperationStatus,
__in WINBIO_UNIT_ID UnitId,
__in_bcount(SampleSize) PWINBIO_BIR Sample,
__in SIZE_T SampleSize,
__in WINBIO_REJECT_DETAIL RejectDetail
);

typedef VOID ( CALLBACK *PWINBIO_CAPTURE_CALLBACK)(
  _In_opt_ PVOID                CaptureCallbackContext,
  _In_     HRESULT              OperationStatus,
  _In_     WINBIO_UNIT_ID       UnitId,
  _In_     PWINBIO_BIR          Sample,
  _In_     SIZE_T               SampleSize,
  _In_     WINBIO_REJECT_DETAIL RejectDetail
);

PWINBIO_CAPTURE_CALLBACK pCaptureCallback;


//in onInitDialog()
pCaptureCallback = &CBioMetricApplicationDlg::CaptureCallback;


//in Cpp file Defination of callback method
VOID CALLBACK CBioMetricApplicationDlg::CaptureCallback(PVOID CaptureCallbackContext, 
														HRESULT OperationStatus, 
														WINBIO_UNIT_ID UnitId, 
														PWINBIO_BIR Sample, 
														SIZE_T SampleSize, 
														WINBIO_REJECT_DETAIL RejectDetail)
{
	//defination
}


и ошибка есть...

ошибка C2440:'=': не удается преобразовать из 'void (__stdcall CBioMetricApplicationDlg::* ) (PVOID, HRESULT, WINBIO_UNIT_ID,PWINBIO_BIR, SIZE_T, WINBIO_REJECT_DETAIL)' в 'CBioMetricApplicationDlg:: PWINBIO_CAPTURE_CALLBACK'

Jochen Arndt

Таким образом, обратный вызов не содержит статики (используйте символ follow в контекстном меню)?

Затем вы должны объявить функцию обратного вызова как статическую в заголовочном файле (2-й вариант из моего предыдущего комментария).

Premnath Mali

Также Эта ошибка, которую я получаю
ошибка C2724: 'CBioMetricApplicationDlg:: CaptureCallback' : 'static' не следует использовать для функций-членов, определенных в области действия файла

Premnath Mali

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

Jochen Arndt

Функция обратного вызова ДОЛЖЕН будьте статичны.
Они обычно предоставляют параметр, который можно использовать для передачи указателя на класс.

В вашем случае это CaptureCallbackContext<code> parameter. Call <code>WinBioCaptureSampleWithCallback(this, ...) и приведите параметр в функцию обратного вызова:
CBioMetricApplicationDlg *pThis = (CBioMetricApplicationDlg*)CaptureCallbackContext;

Premnath Mali

хорошо я объявляю этот метод статическим но как я могу дать определение
если я отдам вот так

static VOID CALLBACK CBioMetricApplicationDlg::CaptureCallback(PVOID CaptureCallbackContext, 
														HRESULT OperationStatus, 
														WINBIO_UNIT_ID UnitId, 
														PWINBIO_BIR Sample, 
														SIZE_T SampleSize, 
														WINBIO_REJECT_DETAIL RejectDetail)
{
	//defination
}

тогда я получаю эту ошибку
ошибка C2724: 'CBioMetricApplicationDlg:: CaptureCallback' : 'static' не следует использовать для функций-членов, определенных в области действия файла

и если я даю определение без статического ключевого слова, то я получаю следующую ошибку


Ошибка 1 ошибка lnk2001: неразрешенных внешних символ "общественности: статический недействительными __CBioMetricApplicationDlg нарушением соглашения о стандартном::IdentifyCallback(недействительными *,неподписанные долго,долго _WINBIO_IDENTITY структуры *,без знака типа char,беззнаковый Long)" (?IdentifyCallback@CBioMetricApplicationDlg@@SGXPAXJKPAU_WINBIO_IDENTITY@@ВК@з) BioMetricApplicationDlg. obj

Jochen Arndt

Смотрите мой обновленный ответ.

Ключевое слово static должно использоваться для объявления в заголовочном файле, но не для определения функции в исходном файле.

Premnath Mali

Спасибо!
Теперь это работает

Jochen Arndt

Прекрасно слышать это и благодарить вас за обратную связь и принятие моего решения.

Но я должен был заметить раньше, что ваш функтон не был статичным (__thiscall из первоначального сообщения об ошибке-это подсказка).

Premnath Mali

Сэр,
Извините, что снова прерываю вас, но во время использования есть одна маленькая проблема

pThis->ShowMessage(_T("Message"));

где ShowMessage-это функция-член
//def of ShowMessage()
void CBioMetricApplicationDlg::ShowMessage(CString msg)
{
	CString preMsg = _T("\n::::Keep Looking at Instructions::::\n\n");
	m_lblMessage.SetText(preMsg + msg);
}

и ошибка произошла во время выполнения...

Необработанное исключение в 0x003a1d1e in BioMetricApplication.exe: 0xC0000005: нарушение доступа к местоположению чтения 0x000000a0.

Jochen Arndt

Как правило, избегайте вызова функций графического интерфейса MFC из функций обратного вызова. Функции MFC не являются потокобезопасными, и такие функции обратного вызова ввода-вывода обычно вызываются из разных потоков (драйверов устройств).

В зависимости от того, что вы хотите сделать, вы можете использовать общие буферы для данных, общие переменные для статуса или отправлять пользовательские сообщения в свой класс MFC.

Но это нечто иное и на самом деле не имеет отношения к первоначальному вопросу.

Однако ошибка может быть получена и в другом месте (проверьте, является ли pThis / переданный CaptureCallbackContext допустимым указателем на ваш класс).

Premnath Mali

да, это действительный указатель. Приложение останавливается на

m_lblMessage.SetText(preMsg+msg);


но ваше предложение я буду размещать сообщения для классов MFC

благодарим Вас за дополнительную информацию о функциях вызова в mfc.

Еще раз спасибо!

Рейтинг:
1

RAMASWAMY EKAMBARAM

Адрес объекта (this) является первым неявным parm для любого метода класса. Поэтому попробуйте объявить pcapturecallback как:
Пустота обратного вызова (cbiometricapplicationdlg::*pcapturecallback)(cbiometricapplicationdlg *thisobj, __в__опт pvoid capturecallbackcontext, &ЛТ;остальные параметры и GT;);
это работает?


Jochen Arndt

Функция обратного вызова статична и поэтому не имеет этого указателя.