Консультация № 56555
24.09.2006, 18:55
0.00 руб.
0 3 2
Добрый день, уважаемые Эксперты!
Пишу класс, позволяющий работать с джойстиками средствами DirectX. В качестве отправной точки взял пример из DirectX SDK.
После создания объекта DirectInput, необходимо произвести перечисление (enumerate) подключенных джойстиков.
Выполняется это следующим образом (кусок из примера):
//-----------------------------------------------------------------------------
// Function-prototypes
//-----------------------------------------------------------------------------
BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext );
HRESULT InitDirectInput( HWND hDlg );

//-----------------------------------------------------------------------------
// Реализация
//-----------------------------------------------------------------------------
// Name: InitDirectInput()
// Desc: Initialize the DirectInput variables.
//-----------------------------------------------------------------------------
HRESULT InitDirectInput( HWND hDlg )
{
HRESULT hr;

hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION,
IID_IDirectInput8, (VOID**)&g_pDI, NULL );

hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL,
EnumJoysticksCallback,
NULL, DIEDFL_ATTACHEDONLY );
}

//-----------------------------------------------------------------------------
// Name: EnumJoysticksCallback()
// Desc: Called once for each enumerated Joystick. If we find one, create a
// device interface on it so we can play with it.
//-----------------------------------------------------------------------------
BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
VOID* pContext )
{
UNREFERENCED_PARAMETER( pContext );
HRESULT hr;

// Obtain an interface to the enumerated Joystick.
hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL );

if( FAILED(hr) )
return DIENUM_CONTINUE;

return DIENUM_STOP;
}

Функции g_pDI->EnumDevices в качестве второго параметра передается адрес функции EnumJoysticksCallback, которая вызывается для перечисления устройств.

В примере, функции DirectX приведены как обычные функции (не методы класса).
Пример рабочий, компилируется и выполняется без ошибок.

Теперь я то же самое «заворачиваю» в методы класса:
//-----------------------------------------------------------------------------
// Function-prototypes
//-----------------------------------------------------------------------------
class CDIJoystick
{
public:
CDIJoystick();
private:
HRESULT InitDirectInput( HWND hDlg ) const;
bool Enumerate_Joysticks(void);
bool CALLBACK EnumJoyCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext );
}
//-----------------------------------------------------------------------------
// Методы класса
//-----------------------------------------------------------------------------

bool CALLBACK CDIJoystick::EnumJoyCallback( const DIDEVICEINSTANCE* pdidInstance,VOID* pContext )
{
HRESULT hr;

hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL );

if( FAILED(hr) )
return DIENUM_CONTINUE;

return DIENUM_STOP;
}

HRESULT CDIJoystick::InitDirectInput( HWND hDlg ) const
//-----------------------------------------------------------------------------
// Name: InitDirectInput()
// Desc: Initialize the DirectInput variables.
//-----------------------------------------------------------------------------
{
HRESULT hr;

hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&g_pDI, NULL );

hr=g_pDI->EnumDevices(DI8DEVCLASS_GAMECTRL ,EnumJoyCallback,NULL,DIEDFL_ATTACHEDONLY);
return S_OK;
}
И вот тут начинаются проблемы:

При компиляции получаю:
error C3867: ‘CDIJoystick::EnumJoyCallback‘: function call missing argument list; use ‘&CDIJoystick::EnumJoyCallback‘ to create a pointer to member
на функции:
hr=g_pDI->EnumDevices(DI8DEVCLASS_GAMECTRL ,EnumJoyCallback,NULL,DIEDFL_ATTACHEDONLY);

Ладно, делаю как просят:
hr=g_pDI->EnumDevices(DI8DEVCLASS_GAMECTRL ,&CDIJoystick::EnumJoyCallback,NULL,DIEDFL_ATTACHEDONLY);

В итоге ругательства меняются, но ругань все на ту же строку:
error C2664: ‘IDirectInput8W::EnumDevices‘ : cannot convert parameter 2 from ‘bool (__stdcall CDIJoystick::* )(const DIDEVICEINSTANCE *,void *)‘ to ‘LPDIENUMDEVICESCALLBACKW‘

Все, тут я застрял. Описание и параметры функций одинаковы с примером. В примере работает, у меня нет. Что меняется при использовании этих функций в качестве методов класса и как это лечить?

VisualStudio 2005

Спасибо!

Обсуждение

Неизвестный
25.09.2006, 00:56
общий
это ответ
Здравствуйте, MayBe!
В примере:
BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext )
функция EnumJoysticksCallback имеет два параметра!
Компилятор вам и говорит: "function call missing argument list" - у вызова функции отсутствует список аргументов. А вы конкретизируете пространство имен, вместо того, чтобы сделать вызов ф-ии. Вот к чему дальше это "use ‘&CDIJoystick::EnumJoyCallback‘ to create a pointer to member..." - не знаю. Но баг, похоже, именно в этом. Даже если у вас аргументы бы имели значение по умолчанию - все равно скобки надо было бы писать.
Неизвестный
25.09.2006, 03:43
общий
В книге Бьярна Страустрапа (Например, <a href=http://kadet.cross-edu.ru/knigi/si/gl5_2.htm>тут</a>) написано, что нормально получить адрес функции-члена класса не представляется возможным нормальными способами:Можно брать адрес члена класса. Получение адреса функции члена часто бывает полезно, поскольку те цели и причины, которые приводились в #4.6.9 относительно указателей на функции, в равной степени применимы и к функциям членам. Однако, на настоящее время в языке имеется дефект: невозможно описать выражением тип указателя, который получается в результате этой операции. Поэтому в текущей реализации приходится жульничать, используя трюки. Что касается примера, который приводится ниже, то не гарантируется, что он будет работать. Используемый трюк надо локализовать, чтобы программу можно было преобразовать с использованием соответствующей языковой конструкции, когда появится такая возможность. Этот трюк использует тот факт, что в текущей реализации this реализуется как первый (скрытый) параметр функции члена.Я не знаю, насколько это старая информация, но может быть, дело именно в компиляторе. Или даже вообще в Стандарте.
Неизвестный
25.09.2006, 09:44
общий
это ответ
Здравствуйте, MayBe!
вы не сможете передать адрес функции члена класса в качестве параметра!
используйте третью функцию со ссылкой на класс в качестве аргумента
например так:

class abc
{
};

void f_callback(LPCDIDEVICEINSTANCE v1, LPVOID * c)
{
((abc*)c)->blablabla();
}

int main(..)
{
....
abc * myclass = new abc;
EnumDevices(DI8DEVCLASS_GAMECTRL, callback, myclass, DIEDFL_ATTACHEDONLY);
...
}

таким образом, на сколько я понял из msdn, каждый раз при вызове callback из EnumDevices, ей в качестве параметра будет передаваться указатель

удачи
Форма ответа