Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting to a struct from LPVOID - C

Tags:

c

winapi

I am writing a simple console application which will allow me to create a number of threads from a set of parameters passed through the arguments I provide.

DWORD WINAPI ThreadFunc(LPVOID threadData)
{
}

I am packing them into a struct and passing them as a parameter into the CreateThread method and trying to unpack them by casting them to the same type as my struct from the LPVOID.

I'm not sure how to cast it to the struct after getting it through so I can use it in the method itself, i've tried various combinations (Example attatched) but it won't compile.

Struct:

#define numThreads 1

struct Data
{
    int threads;
    int delay;
    int messages;
};

Call to method:

HANDLE hThread;
    DWORD threadId;
    struct Data *tData;

    tData->threads = numThreads;
    tData->messages = 3;
    tData->delay = 1000;


    // Create child thread
    hThread = CreateThread(
                            NULL,       // lpThreadAttributes (default)
                            0,          // dwStackSize (default)
                            ThreadFunc, // lpStartAddress
                            &tData,     // lpParameter
                            0,          // dwCreationFlags
                            &threadId   // lpThreadId (returned by function)
                           );

My attempt:

DWORD WINAPI ThreadFunc(LPVOID threadData)
    {
        struct Data tData = (struct Data)threadData;

        int msg;

        for(msg = 0; msg<5; msg++)
        {
            printf("Message %d from child\n", msg);
        }
        return 0;
}

Compiler error:

error C2440: 'type cast' : cannot convert from 'LPVOID' to 'Data'

As you can see I have implemented a way to loop through a number of messages already, I'm trying to make things slightly more advanced and add some further functionality.

like image 773
Jamie Keeling Avatar asked Dec 03 '22 06:12

Jamie Keeling


1 Answers

OK, for starters, this is going to blow up:

struct Data *tData;

tData->threads = numThreads;
tData->messages = 3;
tData->delay = 1000;

...because you've created a variable of type 'pointer to a struct', but you haven't initialized the pointer to point to anything. tData is uninitialized, so you're writing to a wild pointer.

You might want something like this:

// Allocate memory for the struct on the heap
struct Data *tData = malloc( sizeof(struct Data) );

// Initialize _all_ fields of the struct (malloc won't zero fill)
tData->threads = numThreads;
tData->messages = 3;
tData->delay = 1000;

Secondly, you're passing the address of tData (the location in memory where the tData variable resides), rather than the location in memory that tData is pointing to:

// Create child thread
hThread = CreateThread( ...,
                        &tData, // OOPS - ADDRESS OF THE POINTER VARIABLE ITSELF!
                        ... );

You probably want to pass the value of the pointer (the address of the struct that it points to):

// Create child thread
hThread = CreateThread( ...,
                        tData,  // Value of the pointer
                        ... );

When you receive the address of the struct in your callback function, cast it back to the original pointer-to-struct type, dereference and enjoy:

DWORD WINAPI ThreadFunc(LPVOID threadData)
{
    struct Data *tData = (struct Data *)threadData;

    int numMessages = tData->messages;
    // ...
}
like image 75
Scott Smith Avatar answered Dec 26 '22 23:12

Scott Smith