1
#include <windows.h>

BOOL MyCtrlHandler(DWORD ctrlType) {
    return TRUE;
}

int main(void) {
    SetConsoleCtrlHandler(MyCtrlHandler, TRUE);
    return 0;
}

The function signature matches the doc:

The PHANDLER_ROUTINE type defines a pointer to this callback function. HandlerRoutine is a placeholder for the application-defined function name.

If I cross-compile it with MinGW in 64 bits, it works:

$ x86_64-w64-mingw32-gcc ctrl.c
$

But in 32 bits, I get a warning:

$ i686-w64-mingw32-gcc ctrl.c
ctrl.c: In function ‘main’:
ctrl.c:8:27: warning: passing argument 1 of ‘SetConsoleCtrlHandler’ from incompatible pointer type [-Wincompatible-pointer-types]
    8 |     SetConsoleCtrlHandler(MyCtrlHandler, TRUE);
      |                           ^~~~~~~~~~~~~
      |                           |
      |                           BOOL (*)(DWORD) {aka int (*)(long unsigned int)}
In file included from /usr/share/mingw-w64/include/windows.h:74,
                 from ctrl.c:1:
/usr/share/mingw-w64/include/wincon.h:249:68: note: expected ‘PHANDLER_ROUTINE’ but argument is of type ‘BOOL (*)(DWORD)’ {aka ‘int (*)(long unsigned int)’}
  249 |   WINBASEAPI WINBOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine,WINBOOL Add);
      |
$

I don't understand why, because MyCtrlHandler should have the same type as PHANDLER_ROUTINE.

rom1v
  • 2,752
  • 3
  • 21
  • 47
  • 2
    The link you give says `BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType);` Is it necessary to use the *exact* same definition? Which would be `BOOL WINAPI MyCtrlHandler(_In_ DWORD ctrlType);` – Weather Vane May 10 '20 at 19:27
  • Yup, I tried it as `BOOL WINAPI MyCtrlHandler(DWORD ctrlType)` and it compiles just fine, without it, I got `Error C2440 'function': cannot convert from 'BOOL (__cdecl *)(DWORD)' to 'PHANDLER_ROUTINE'...` ` – jwdonahue May 10 '20 at 19:33

1 Answers1

4

The problem here is the difference between __cdecl and __stdcall. You must have lucked out with the default calling convention on your one successful attempt to compile. You need:

BOOL WINAPI MyCtrlHandler(DWORD ctrlType) {
    return TRUE;
}
jwdonahue
  • 6,199
  • 2
  • 21
  • 43
  • In x64 cdecl and stdcall, are the same. In x86, on the other hand, cdecl has the caller clean (pop) the stack, while stdcall has the callee clean the stack. – Eryk Sun May 10 '20 at 20:30
  • @ErykSun, Ah yes, I have been aware of that difference in the past, and completely forgot about it. Thanks. – jwdonahue May 10 '20 at 20:47