C++: определения типов обратного вызова с __stdcall в MSVC

Этот тип определения:

typedef DWORD WINAPI
(* CM_Open_DevNode_Key)(DWORD, DWORD, DWORD, DWORD, PHKEY, DWORD);

отлично компилируется в BorlandCpp, однако, когда я компилирую его в msvc, мне нужно удалить WINAPI (это просто псевдоним для __stdcall):

typedef DWORD
(* CM_Open_DevNode_Key)(DWORD, DWORD, DWORD, DWORD, PHKEY, DWORD);

Почему это происходит? Могу ли я безопасно удалить часть WINAPI?

Обновление: мне пришлось удалить "WINAPI" из typedef, иначе я получил

 error C2059: syntax error : '('

для линии.

Можете ли вы сказать мне, почему Borland может скомпилировать его с помощью "WINAPI", а Msvc не может?


person George    schedule 18.08.2009    source источник


Ответы (3)


Я считаю, что в VC++ вам нужно поместить соглашение о вызовах внутри () Вот пример на MSDN использования соглашения о вызовах внутри typedef указателя функции.

typedef DWORD (WINAPI * CM_Open_DevNode_Key)(DWORD, DWORD, DWORD, DWORD, PHKEY, DWORD);

Это должно скомпилироваться без проблем.

person Michael    schedule 18.08.2009

Указатель функции должен иметь информацию о соглашении о вызовах, используемом функцией. Если вы указываете на функцию, использующую соглашение о вызовах __cdecl, вы должны использовать указатель на функцию __cdecl. Если вы указываете на функцию, которая использует соглашение о вызовах __stdcall, вы должны использовать указатель функции __stdcall.

Надеюсь это поможет.

person pyon    schedule 18.08.2009

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

Если бы вы определили CM_Open_DevNode_Key как не являющийся указателем, любое объявление заголовка функции, которая должна следовать этой сигнатуре обратного вызова, могло бы быть просто записано как

CM_Open_DevNode_Key myFunc;

а не слишком многословный / подверженный ошибкам

DWORD WINAPI myFunc(DWORD, DWORD, DWORD, DWORD, PHKEY, DWORD);

Это позволило бы использовать гораздо более простой код и гораздо более точное сопоставление сигнатур функций, если это необходимо.

Не говоря уже о том, что определения типов указателей в целом являются злом, поскольку они не позволяют указывать константность content, на который указывают (печально известный пример: «const PCHAR» против правильно оцененного «const CHAR *»).

person cmaker    schedule 29.09.2011