1

I want to use CreateThread function but with my own custom callback function, this is how I am using it

 HANDLE handle = CreateThread(0,0,custom_function, NULL,0,NULL);

declaration of custom_function

DWORD custom_function(void)
{
    printf("Hello from callback function");
}

the warning I get

main.c:154:37: warning: passing argument 3 of 'CreateThread' from incompatible pointer type [-Wincompatible-pointer-types]    
  154 |         handle = CreateThread(0, 0, custom_function, NULL, 0, NULL);
      |                                     ^~~~~~~~~~~
      |                                     |
      |                                     DWORD (*)(void) {aka long unsigned int (*)(void)}
In file included from C:/msys64/mingw64/include/winbase.h:29,
                 from C:/msys64/mingw64/include/windows.h:70,
                 from rce.c:3:
C:/msys64/mingw64/include/processthreadsapi.h:279:127: note: expected 'LPTHREAD_START_ROUTINE' {aka 'long unsigned int (*)(void *)'} but argument is of type 'DWORD (*)(void)' {aka 'long unsigned int (*)(void)'}
  279 |   WINBASEAPI HANDLE WINAPI CreateThread (LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
      |                                                                                                        ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
loaded_dypper
  • 262
  • 3
  • 12
  • 2
    You can do whatever you want in your function, but the signature must match the one specified by `CreateThread`. Your custom function has wrong return type and wrong parameter list. To fix this, just use the signature that is expected: `long unsigned int (*)(void *)`. You can use `DWORD` as this seems to be same as `long unsigned int` but you must take a `void*` instead of your `void` parameter list. – Gerhardh Sep 02 '22 at 10:41
  • @Gerhardh could you elaborate more I don't understand how the final struct of the function should look like – loaded_dypper Sep 02 '22 at 10:44
  • 2
    It should look like this: `DWORD custom_function(void* argument)` – Adrian Mole Sep 02 '22 at 11:05
  • 1
    The `void*` argument to the thread procedure can be used to pass arbitrary data into the newly created thread. It can be anything a client needs to pass along, an integral value or a pointer to an arbitrary structure. Also make sure that your thread procedure has the correct calling convention. A C compiler will not warn you about a mismatch (unlike a C++ compiler). – IInspectable Sep 02 '22 at 11:06
  • @IInspectable can you provide any link for the correct procedure, i am having trouble figure out how to execute the body of `custom_function` – loaded_dypper Sep 02 '22 at 11:14
  • 2
    The documentation for [`CreateThread`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread) has a link to the [`ThreadProc`](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms686736(v=vs.85)). There's also a section called [creating threads](https://learn.microsoft.com/en-us/windows/win32/procthread/creating-threads) that explains things in more detail. – IInspectable Sep 02 '22 at 11:19

1 Answers1

1

What the warning is telling you is that the parameter to the callback function needs to be a void* (or LPVOID if using Windows API types).

If POSIX threads are familiar, this is not so different - CreateThread allows you to pass a void pointer to custom data as parameter to the callback. But you don't have to use it.

The callback should correctly be written as:

DWORD WINAPI custom_function (LPVOID lpParam);

WINAPI specifies that __stdcall calling convention should be used. This might be required since this function is to be called from the OS and not from your C program (which probably uses __cdecl calling convention).

As for executing, please note that CreateThread gives you the option to create the thread suspended (asleep) or running.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • With the exception of variable argument lists, no-one uses `__cdecl`. – IInspectable Sep 02 '22 at 13:00
  • @IInspectable Older MSVC did or otherwise MS wouldn't insist on typing `WINAPI` all over the place. – Lundin Sep 02 '22 at 13:13
  • The calling convention isn't a property of a compiler. It's part of the platform's ABI. And [`__stdcall` is the calling convention of the Win32 API](https://devblogs.microsoft.com/oldnewthing/20040108-00/?p=41163), and has always been. If you're talking about *"older"* then that's 16-bit Windows. Microsoft doesn't exactly insist that you type `WINAPI` everywhere. It's just that if you don't specify the calling convention, then you'll inherit the compiler's default. Which may or may not match. – IInspectable Sep 02 '22 at 13:20
  • @IInspectable Actually I have no idea what you are on about. MSVC 19.32 for x86 32 bit: `int (__cdecl *ptr)(void) = main;` compiles fine, `int (__stdcall *ptr)(void) = main;` does not. It is clearly using `__cdecl`. https://godbolt.org/z/38Wa9Yz3e – Lundin Sep 02 '22 at 13:50
  • That's the language support library's startup code, not the OS. Microsoft's implementation uses `__cdecl`, for whatever reason (presumably because someone way into the last millennium made assumptions). If that makes you happy, let me take the initial statement back and replace it with this one: "No-one uses `__cdecl` out of free will." – IInspectable Sep 02 '22 at 15:24