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);
}
Related
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;
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.
I have been struggling for days to figure out the probably obvious reason why i cant get my code to compile.
I have a class (based on wxThread) where the callback is defined:
-- Header file --
class TestClass : public wxThread
{
private:
static void WlanNotification(WLAN_NOTIFICATION_DATA *wlanNotifData, VOID *p);
};
-- Code file --
I call the WlanRegisterNotification function, that needs the above callback function as a parameter:
dwResult = WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, true, (WLAN_NOTIFICATION_CALLBACK) WlanNotification, this, 0, &dwPrevNotif);
This compiles and works fine, but the problem is the function is marked as static, so i cant access my non static stuff from the callback (which i need for other reasons).
I have tried every single combination i can think of to pass in the callback as non static:
-- Header file --
void WINAPI WlanNotification(PWLAN_NOTIFICATION_DATA data, PVOID context);
-- Code file --
dwResult = WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, true, (WLAN_NOTIFICATION_CALLBACK)WlanNotification, this, 0, &dwPrevNotif);
i just get:
error C2660: 'WlanRegisterNotification' : function does not take 6
arguments
error C2440: 'type cast' : cannot convert from 'overloaded-function'
to 'WLAN_NOTIFICATION_CALLBACK'
I'm thinking its related to the typedef somehow:
typedef VOID (WINAPI *WLAN_NOTIFICATION_CALLBACK) (PWLAN_NOTIFICATION_DATA, PVOID);
I have tried googling for examples of using the WlanRegisterNotification function, but none of the examples i could find is calling it from a class, which is what seems to be an issue here, so i'm really lost.
A non-static class method has a hidden this parameter that the callback is not expecting let alone know how to fill in. That is why you cannot use it as a callback unless you either 1) use static to remove that parameter, or 2) create a thunk to use as the actual callback and then have it internally delegate to a non-static class method. Remember that the Windows API is designed for C, not C++. There are no classes or implicit this pointers in C.
In this case, a static callback can access non-static members of your class because you are explicitly passing the object's this pointer as the pCallbackContext of WlanRegisterNotification(), which is then passed as-is to the context of the callback:
class TestClass : public wxThread
{
private:
static VOID WINAPI WlanNotification(PWLAN_NOTIFICATION_DATA wlanNotifData, PVOID context);
};
VOID WINAPI TestClass::WlanNotification(PWLAN_NOTIFICATION_DATA wlanNotifData, PVOID context)
{
TestClass *pThis = (TestClass*) context;
// use pThis-> to access non-static members as needed..
}
// get rid of the typecast when passing the callback. If it does
// not compile, then it is not declared in a compatible manner...
dwResult = WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, TRUE, &WlanNotification, this, 0, &dwPrevNotif);
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.
invalid conversion from 'DWORD (*)(void*)' to 'DWORD (*)(void*)' .
cake==lie
1==0
I have no idea what this means ... I get it in this code
HANDLE CPlugin::CreateWinampThread() ||
{ __VVVVVVVV__
hWinampThreadHandle = (HANDLE)CreateThread(NULL, 0, StartWinampThread, (void*)this, 0, &dwWinampThreadID);
if (!hWinampThreadHandle)
return 0;
CloseHandle(hWinampThreadHandle);
return hWinampThreadHandle;
}
.
DWORD WINAPI CPlugin::StartWinampThread(void* lpParam)[...]
StartWinampThread must be static if it is member function.
See here: in-c-is-it-safe-portable-to-use-static-member-function-pointer-for-c-api-callb for why you need to use a extern "C"
The correct way would be somthing like this:
HANDLE CPlugin::CreateWinampThread() ||
{ __VVVVVVVV__
hWinampThreadHandle = (HANDLE)CreateThread(NULL, 0, ::StartWinampThread, (void*)this, 0, &dwWinampThreadID);
if (!hWinampThreadHandle)
return 0;
CloseHandle(hWinampThreadHandle);
return hWinampThreadHandle;
}
.
// A callback function for C code must have C linkage.
// That is not possable for C++ static member functions.
extern "C" DWORD WINAPI StartWinampThread(void* lpParam)
{
// You can always call your static member function here.
CPlugin::StartWinampThread(lpParam)
}
Is it to do with objects - there's an implicit 'this' paramter to your object's StartWinampThread method because it's a member of a class.
What happens if you change it to be a standalone method but keep the same signature i.e. from
DWORD WINAPI CPlugin::StartWinampThread(void* lpParam)[...]
to
DWORD WINAPI StartWinampThread(void* lpParam)[...]
(I know it won't work for you, I'm just interested to see if it removes the compiler's complaint)