I am trying to use the following function of my library in a thread:
typedef void (*TIPO_FUNCION_APARCAR_COMMIT) (HCoche hc);
typedef void (*TIPO_FUNCION_PERMISO_AVANCE) (HCoche hc);
typedef void (*TIPO_FUNCION_PERMISO_AVANCE_COMMIT)(HCoche hc);
int PARKING2_aparcar(HCoche,void *datos,TIPO_FUNCION_APARCAR_COMMIT,
TIPO_FUNCION_PERMISO_AVANCE,
TIPO_FUNCION_PERMISO_AVANCE_COMMIT);
But I can't figure out how I can call it, because in CreateThread() the input parameter is LPVOID and I don't see how I can use it.
I tried this syntax, but it doesn't work:
CreateThread(0, 0, fPARKING2_apagar, {&hc,(LPTHREAD_START_ROUTINE)fPARKING2_getDatos(hc), &commit, &goForward, &goForwardCommit}, NULL, NULL, &threadId);
I also tried to use std::thread, but it seems that I don't have C++11 so I can't use it.
The fPARKING2_apagar() function you are trying to pass to CreateThread() does not satisfy the signature that CreateThread() is expecting. The signature of your thread function MUST match that of ThreadProc():
DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter);
Also, you are trying to pass an anonymous struct to the lpParameter param of CreateThread(). That will not work, either.
You need to write a wrapper function that you can pass to CreateThread(), and then that wrapper can call the library function. Use the lpParameter param of CreateThread() to pass user-defined data to the thread function, which can then pass it on to the library function as needed.
Try something more like this:
struct PARKING2_aparcar_params
{
HCoche hc;
void *datos;
TIPO_FUNCION_APARCAR_COMMIT aparcarCommit;
TIPO_FUNCION_PERMISO_AVANCE permisoAvance;
TIPO_FUNCION_PERMISO_AVANCE_COMMIT permisoAvanceCommit;
};
DWORD WINAPI PARKING2_aparcar_wrapper(LPVOID lpParameter)
{
PARKING2_aparcar_params *params = static_cast<PARKING2_aparcar_params*>(lpParameter);
fPARKING2_aparcar(params->hc, params->datos, params->aparcarCommit, params->permisoAvance, params->permisoAvanceCommit);
delete params;
return 0;
}
...
PARKING2_aparcar_params *params = new PARKING2_aparcar_params;
params->hc = hc;
params->datos = fPARKING2_getDatos(hc);
params->aparcarCommit = &commit;
params->permisoAvance = &goForward;
params->permisoAvanceCommit = &goForwardCommit;
hThread = CreateThread(NULL, 0, &PARKING2_aparcar_wrapper, params, 0, &threadId);
if (!hThread)
delete params;
Related
Below there is a part of my code:
class MyClass
{
...
HANDLE m_ListenThr;
DWORD WINAPI ListenThread (LPVOID WorkContext);
bool CreateListenThreads();
}
bool MyClass::CreateListenThreads()
{
...
m_ListenThr = CreateThread(NULL, 0, MyClass::ListenThread,(void*)this, 0,&dwThreadId);
}
DWORD WINAPI MyClass::ListenThread (LPVOID WorkThreadContext)
{
MyClass pThis = reinterpret_cast<MyClass*>(WorkThreadContext);
...
}
After compiling i get this error:
error C3867: 'MyClass::ListenThread': function call missing argument
list; use '&MyClass::ListenThread' to create a pointer to member
what i do wrong?
You have to define the thread function DWORD WINAPI ListenThread (LPVOID WorkContext); as a static function of the class:
class MyClass
{
public:
static DWORD WINAPI ListenThread (LPVOID WorkContext);
}
It is not possible to call a member function without an instance of an object. In your case this is only a parameter that will be passed as WorkContext in your now static function ListenThread.
As another solution, you could also consider using C++11 std::bind so as to create a function object from that you would pass to CreateThread.
That would go something like this - sorry I have not windows so as to check if this compiles - but it gives you the idea:
bool MyClass::CreateListenThreads()
{
using std::placeholders;
std::function <void (void*)> threadFunction = std::bind(&MyClass::ListenThread, *this, _1);
m_ListenThr = CreateThread(NULL, 0, threadFunction,(void*)this, 0,&dwThreadId);
}
but that would sort of use the reference to this twice: as the instance of the class to call the function on, and as a parameter LPVOID WorkContext. Maybe it's awkward in this present case.
Im modifiy my display drivers to get update notifcation sent from the USB port. So far so good, but i got stock on follow:
GPEFlat::GPEFlat()
{
PBOOT_ARGS args;
ULONG fbSize;
ULONG fbOffset;
ULONG offsetX;
ULONG offsetY;
BOOL bFoundArgs = FALSE;
BOOL m_MouseDisabled = TRUE;
HANDLE m_hAttachEvent = CreateEvent(NULL, FALSE, FALSE, L"MouseAttached");
HANDLE m_hDetachEvent = CreateEvent(NULL, FALSE, FALSE, L"MouseDetached");
HANDLE m_hCursorThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MouseEventThread, NULL, 0, NULL);
DWORD
GPEFlat::MouseEventThread(void)
{
DWORD rc = TRUE;
HANDLE handles[2];
handles[0] = m_hAttachEvent;
handles[1] = m_hDetachEvent;
The resulting error is:
Error 1 error C2440: 'type cast' : cannot convert from 'overloaded-function' to 'LPTHREAD_START_ROUTINE' drivers\display\vgaflat
So the line : HANDLE m_hCursorThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MouseEventThread, NULL, 0, NULL);
Dosnt work. Got some pointers that it may be to non static method.
How should i do this?
Greetings
The thing to understand is that functions (including static methods) and non-static methods are different things. CreateEvent expects a function. You must give it that, it will not work with GPEFlat::MouseEventThread because that's a method. What you can do though is give it a function which calls GPEFlat::MouseEventThread. Usually this is done like this
DWORD WINAPI thread_starter(LPVOID that)
{
return ((GPEFlat*)that)->MouseEventThread();
}
...
CreateThread(NULL, 0, thread_starter, this, 0, NULL);
Note that I pass this to CreateThread, that's very important. CreateThread passes it to the parameter that in thread_starter, which uses that to call the method you wanted to call all along.
The MouseEventThread have to be a static function, because a function pointer is not the same as a member function pointer. Static methods can be used as normal function pointers, but non-static member functions can not.
If you need to reference class members, then one very simple solution is to have a static wrapper functions, which takes the instance of the object (this in the constructor) and then calls the actual member function using that instance pointer.
Something like
class GPEFlat
{
// ...
private:
static DWORD MouseEventThreadWrapper(LPVOID instance)
{ return reinterpret_cast<GPEFlat*>(instance)->MouseEventThread(); }
// ...
};
Create the thread with this wrapper function instead, passing this as argument to it:
GPEFlat::GPEFlat()
{
// ...
HANDLE m_hCursorThread = CreateThread(
NULL, 0, (LPTHREAD_START_ROUTINE)MouseEventThreadWrapper, this, 0, NULL);
}
To define my thread I have in my Header file:
class HttpClient
{
public:
...
unsigned int __stdcall PerformLogin(void*);
...
};
Then in my cpp file I have:
unsigned int __stdcall PerformLogin(void*){
...
}
And to call this thread I use
hThread = (HANDLE)_beginthreadex( NULL, 0, &PerformLogin, NULL, 0, &threadID );
But i Have an error on the &PerformLogin saying that:
the args of type unsigned int (__stdcall HttpClient::)(void) is not compatible with the param unsigned int (__stdcall*)(void*).
I understand the error, but I really don't know how to fix this!
A possible way to fix this would be to make the member function static, though this means PerformLogin() does not have a this pointer and would have no access to non-static members of HttpClient.
Another is to move PerformLogin() out of HttpClient altogether, and make it a free function.
What I usually to is to add 'this' as the void* parameter to the static function - you can then call methods on it in the static function with a bit of casting..
Member functions get this pointer implicitly as a first parameter.
So if you want to start a thread with a class member function, you should explicitly pass a pointer to a class instance in your call to _beginthreadex.
So, remove explicit argument:
class HttpClient
{
public:
...
unsigned int __stdcall PerformLogin();
...
};
And call _beginthreadex while passing this as an argument:
hThread = (HANDLE)_beginthreadex( NULL, 0, &PerformLogin, this, 0, &threadID );
It's worth mentioning that this is a bit hacky. C++ FAQ advises against it.
I still prefer this approach. Of course I just use boost::thread usually.
WARNING: THIS IS AN EXAMPLE CODE.
I need to define this typedef and this definitions to get the code to compile well.
I have the following code and I need to know what should be in __WHAT_HERE1 and __WHAT_HERE2:
#include <windows.h>
#include <winbase.h>
_ifdef _WIN32_
typedef ____WHAT_HERE1 THREAD_TYPE;
_endif
_ifdef _LINUX_
typedef void (*THREAD_TYPE);
_endif
THREAD_TYPE thread_function( void * )
{
}
class ThreadInfo {
public:
_ifdef _WIN32_
____WHAT_HERE2 func;
LPVOID args;
_endif
_ifdef _LINUX_
void *(*func) (void*);
void *args;
_endif
}
ThreadInfo *infoThread;
CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE) infoThread->func,
infoThread->args,
0,
NULL
);
You can deduce the type from the code you pasted:
According to the CreateThread documentation, the third argument is of type LPTHREAD_START_ROUTINE. You're apparently aware of this already, as you cast infoThread->func to that.
Hence, ____WHAT_HERE2 (the type of infoThread->func) should be LPTHREAD_START_ROUTINE.
Since you will probably assign the address of the thread_function function to infoThread->func, the return value of the function (denoted by ____WHAT_HERE1 in your code sketch) should be the return type as indicated by LPTHREAD_START_ROUTINE. Checking the LPTHREAD_START_ROUTINE documentation shows that this is DWORD.
However, this will not be sufficient since on Windows, a thread procedure uses the __stdcall calling convention. You need to take that into account when defining your thread_function.
am trying to make a worker thread using MFC so here is the codes:
struct ThreadParam
{
HWND mDlg; // Note: A handle.
};
UINT TestMFCThread::Test( LPVOID pParam ){
//do work!
}
void TestMFCThread::OnBnClickedButton2()
{
ThreadParam* param = new ThreadParam;
param->mDlg = m_hWnd;
AfxBeginThread(Test, param);
}
but it gives me this error :
1 IntelliSense: no instance of overloaded function "AfxBeginThread" matches the argument list
argument types are: (UINT (LPVOID pParam), ThreadParam *)
idk whats wrong it's supposed to be right!
From the documentation for AfxBeginThread() you need to cast the second argument to LPVOID:
AfxBeginThread(Test, (LPVOID) param);
and set calling convention of Test to __cdecl:
UINT __cdecl Test( LPVOID lParam)
just declare your member function as static , it will solve the issue