I've been re-architecting some fairly procedural C++ into something more classy. The original code runs just fine and part of it spins up a new thread to do some file cleaning. The function that does this cleaning is the entry point for the new thread. See code below. NB: This code won't execute, but it shows the principle that worked.
#include <stdlib.h>
// Structure for passing application data to a new thread.
typedef struct threadData {
networkShare* netArchive;
rig* rigInfo;
rigDatabase* dbConn;
networkConn* netConn;
char* logBuffer;
} THREADDATA;
// Global handle to a mutex object
// Used to control access to the inter thread log buffer
HANDLE ghMutex;
DWORD WINAPI cleanLocalArchive(LPVOID lpParam) {
THREADDATA* p_threadData = (THREADDATA*)lpParam;
// ... Do stuff ...
return <<something>>;
}
int main(int argc, char** argv) {
// Variables for local archive thread
HANDLE h_CleanerThread = 0;
THREADDATA* p_threadData = NULL;
DWORD dwThreadId;
// Create a mutex with no initial owner
ghMutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (ghMutex == NULL) {
printf("CreateMutex error: %d\n", GetLastError());
return 1;
}
// Declare the data structure for passing app setting to a new Thread and populate it.
p_threadData = DBG_NEW THREADDATA;
p_threadData->netArchive = &rigArchive;
p_threadData->rigInfo = &thisRig;
p_threadData->logBuffer = (char*)malloc(BUF_SIZE);
p_threadData->dbConn = &archiveDB;
p_threadData->netConn = &netConnection;
// Initialise p_threadData->logBuffer in case we never put anything else in there.
sprintf_s(p_threadData->logBuffer, BUF_SIZE, "");
// Start a new thread
h_CleanerThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
cleanLocalArchive, // thread function name
p_threadData, // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
// ... Do other stuff ...
return 0;
}
I've now refactored the code into classes and the function "cleanLocalArchive" is a member function of the application class AircatFeeder. When I call this member function in the in CreateThread() I get various errors depending on what I do to the code:
As-is: call line = "cleanLocalArchive,"
error C3867: 'AirCatFeeder::cleanLocalArchive': non-standard syntax; use '&' to create a pointer to member
So I add in an ampersand: call line = "&cleanLocalArchive,"
error C2276: '&': illegal operation on bound member function expression
error C2660: 'CreateThread': function does not take 5 arguments
After some head scratching and Google-Foo I found this link which I hoped would solve the issue. It certainly shed some light on the why. I created a wrapper function outside the class and tried calling that. The function and its call was as follows:
Function call:
// Start a new thread
h_CleanerThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
trampoline, // thread function name
p_threadData, // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
Wrapper Function:
DWORD trampoline(LPVOID data) {
AirCatFeeder* scheduler = static_cast<AirCatFeeder*>(data);
return scheduler->cleanLocalArchive(data);
}
However, I still ended up with the same issues/error messages. Whether I call the member function, or the wrapper function, IntelliSense still reports a similar error message:
argument of type "DWORD(*)(LPVOID lpParam)" is incompatible with parameter of type "LPTHREAD_START_ROUTINE"
Hopefully it is now clear what I'm trying to achieve. Can someone please educate me on what I'm doing wrong? Thanks.
Answer courtesy of Hans Passant. See Comments on question:
The trampoline is missing WINAPI in its definition.