🔒 Locked
help with callback function
Advertisement
Original Post
Hello everyone,
I’m hoping someone can help me. This has nothing to do with game programming but still hoping someone can help me out. I have a lib file, which is a static library from a third party that allows me to communicate with their server without me having to worry about the TCP\IP commutation. I don’t have access to this code at all. I’m having a problem that I’m hoping someone can help me with. Ok, I have to create an instance of their class and pass in a callback function. Once I pass in the callback function it will send me a message when it has connected to the server or errors like a bad username or password. Well, here my problem. I don’t want to leave my function(in this example, MyLogin) until I have the status of the connection, either being connected to the server or bad username/password. The reason I’m having trouble is because when I pass in the callback function, the callback function is on the same thread as MyLogin, so when I do something like Sleep, WaitForMultipleObjects, the callback function never receives messages because I’m telling that thread to sleep. I was hoping there was a api like MsgWaitForMultipleObjects but to allow me to process the callback function events but there isn’t. Here is an example of what I’m talking about
HANDLE thisEvent[2];
MyCallBack(Message msg)
{
if(msg = thisEvent)
{
SetEvent(thisEvent[0]);
{
else
{
SetEvent(thisEvent[1]);
}
}
MyLogin()
{
thisEvent[0] = CreateEvent();
thisEvent[1] = CreateEvent();
MyClass *Example;
Example = new(MyCallBack);
Example ->Login("user", "pass");
::WaitForMultipleObjects(2, thisEvent, FALSE, INFINITE);
}
but like I said, once I call the function WaitForMultipleObjects, the callback function never gets called because they’re on the same thread. So I had another idea, have my main thread create the object, pass it to a worker thread and have it wait, like this
MyCallBack(Message msg)
{
if(msg = thisEvent)
{
SetEvent(thisEvent[0]);
{
else
{
SetEvent(thisEvent[1]);
}
}
DWORD WINAPI LoginThread(LPVOID lpObject)
{
MyCallBack *Object =( MyCallBack *)lpObject;
Object ->Login("user", "pass");
::WaitForMultipleObjects(2, thisEvent, FALSE, INFINITE);
}
MyLogin()
{
thisEvent[0] = CreateEvent();
thisEvent[1] = CreateEvent();
MyClass *Example;
Example = new(MyCallBack);
hThread = CreateThread(NULL, 0, LoginThread, (LPVOID)Example, 0,NULL)
WaitForSingleObject(1, hThread, INFINITE);
}
Once again, the callback never gets called because both threads are now sleeping. So I had another idea, have the worker thread not wait at all, like this
MyCallBack(Message msg)
{
if(msg = thisEvent)
{
SetEvent(thisEvent[0]);
{
else
{
SetEvent(thisEvent[1]);
}
}
DWORD WINAPI LoginThread(LPVOID lpObject)
{
MyCallBack *Object =( MyCallBack *)lpObject;
Object ->Login("user", "pass");
}
MyLogin()
{
thisEvent[0] = CreateEvent();
thisEvent[1] = CreateEvent();
MyClass *Example;
Example = new(MyCallBack);
hThread = CreateThread(NULL, 0, LoginThread, (LPVOID)Example , 0,NULL)
WaitForSingleObject(1, hThread, INFINITE);
}
but it crashes, and I think it crashes because the thread terminates before login completes or maybe because login is the one that is calling the callback function but before the callback is called, the thread is terminated so you are calling a callback function on a thread that no longer exist.. So if anyone can help me with this problem I would really be thankful. Once again, what I need to do is process the callback function events before leaving MyLogin….Thank you for everyones help
Michael
[edited by - bravescharm on June 12, 2002 1:54:37 PM]
[edited by - bravescharm on June 12, 2002 1:55:41 PM]
The code you posted is very confusing but this is what I think your after:
1) Create an event object and set it to non-signaled (ResetEvent())
2) The main thread creates a worker thread to do the login work.
3) The main thread then calls WaitForSingleObject and waits on the event.
4) Once the worker thread completes the login routine it signals the event (SetEvent()) and dies.
5) WaitForSingleObject returns and the main thread continues.
Of course the real question is: If the callback is run by the same thread how could the function you use to pass the call back possibly return before the callback has been called? Is any of this necessary?
[edited by - Solo on June 12, 2002 5:28:53 PM]
1) Create an event object and set it to non-signaled (ResetEvent())
2) The main thread creates a worker thread to do the login work.
3) The main thread then calls WaitForSingleObject and waits on the event.
4) Once the worker thread completes the login routine it signals the event (SetEvent()) and dies.
5) WaitForSingleObject returns and the main thread continues.
Of course the real question is: If the callback is run by the same thread how could the function you use to pass the call back possibly return before the callback has been called? Is any of this necessary?
[edited by - Solo on June 12, 2002 5:28:53 PM]
solo,
Ok, let me give you a little more detail. I have a COM object i''ve developed. It uses a library from a third party that allows me to connect to their server. I have a Interface method called Connect which creates an instance of the third party object. This object requires a callback function in it''s constructor, which allows you to recieve messages about the connection to the server. Ok, after creating and instance of this object and passing it my callback function, I call a method on this object called Login
HRESULT MyCOMObject::Connect(user, pass)
{
ThirdPartyObject = new TheObject(MyCallBackFunction);
ThirdPartyObject->Login(user, pass);
return S_OK;
}
Now, when the server has validated my username and pass, it sends me a message through my callback function saying it has connected. It also sends me a error if it was not able to connect to the server. Now, I don''t want to leave my interface method Connect until I have either established a connection with the server or a error has happened, so Connect can return a status code to the client, either saying it connected or didn''t connect. The problem i''m having is the callback function is on the same thread as the callback function. What I am needing to do is somehow not return from Connect until I either i have established a connection or the server send me a error message, which the callback function will recieve. Does anyone know how to sleep inside a function/method and still allow a callback function to recieve messages. I have tried creating two events, one event that gets signaled when a error happened and another event when I was able to established a connection with the server. Then I created a new thread and have that new thread create an instance of the third party object and then call login. After calling login, I call WaitForMulptileObjects, waiting for either of my events to become signaled, because when they''re signaled, then I know my callback function has recieved an event, and depending on which one is signaled, I know if a error happened or I established a connection. The problem with this method is my callback function never gets called because when I call WaitForMulptileObjects, the thread sleeps and the callback never gets called. So i''m having trouble figuring out how to stay in my interface method Connect until I recieve a message by my callback function. if anyone can help, please help because i''m havint trouble thinking of a way. Thanks everyone. Michael
Ok, let me give you a little more detail. I have a COM object i''ve developed. It uses a library from a third party that allows me to connect to their server. I have a Interface method called Connect which creates an instance of the third party object. This object requires a callback function in it''s constructor, which allows you to recieve messages about the connection to the server. Ok, after creating and instance of this object and passing it my callback function, I call a method on this object called Login
HRESULT MyCOMObject::Connect(user, pass)
{
ThirdPartyObject = new TheObject(MyCallBackFunction);
ThirdPartyObject->Login(user, pass);
return S_OK;
}
Now, when the server has validated my username and pass, it sends me a message through my callback function saying it has connected. It also sends me a error if it was not able to connect to the server. Now, I don''t want to leave my interface method Connect until I have either established a connection with the server or a error has happened, so Connect can return a status code to the client, either saying it connected or didn''t connect. The problem i''m having is the callback function is on the same thread as the callback function. What I am needing to do is somehow not return from Connect until I either i have established a connection or the server send me a error message, which the callback function will recieve. Does anyone know how to sleep inside a function/method and still allow a callback function to recieve messages. I have tried creating two events, one event that gets signaled when a error happened and another event when I was able to established a connection with the server. Then I created a new thread and have that new thread create an instance of the third party object and then call login. After calling login, I call WaitForMulptileObjects, waiting for either of my events to become signaled, because when they''re signaled, then I know my callback function has recieved an event, and depending on which one is signaled, I know if a error happened or I established a connection. The problem with this method is my callback function never gets called because when I call WaitForMulptileObjects, the thread sleeps and the callback never gets called. So i''m having trouble figuring out how to stay in my interface method Connect until I recieve a message by my callback function. if anyone can help, please help because i''m havint trouble thinking of a way. Thanks everyone. Michael
I am in a MTA threading (Free threading) and MyCallBackFunction is not part of my interface nor is it part of my class. It''s a stand-alone function. Do you have any ideas by any chance?
Then my original post stands. Look at it like this: In order for ThirdPartyObject to call MyCallBackFunction with your thread (the thread executing MyCOMObject::Connect()) your thread must be executing it's code. This occurs when you call ThirdPartyObject's constructor and when you call ThirdPartyObject->Login(). Once ThirdPartyObject->Login() returns your thread is no longer executing ThirdPartyObject's code and therefore ThirdPartyObject can't use it to call MyCallBackFunction. If MyCallBackFunction is not called before ThirdPartyObject->Login() returns it never will get called (at least not by your thread).
So either...
a) MyCallBackFunction is called before ThirdPartyObject->Login() returns.
or...
b) MyCallBackFunction is called by a different thread and so the Event object / WaitForSingleObject combo should work.
[edited by - Solo on June 13, 2002 10:26:58 AM]
So either...
a) MyCallBackFunction is called before ThirdPartyObject->Login() returns.
or...
b) MyCallBackFunction is called by a different thread and so the Event object / WaitForSingleObject combo should work.
[edited by - Solo on June 13, 2002 10:26:58 AM]
Solo,
I don't mind creating a new thread but i had trouble doing that as well. Ok, here is where i had trouble with a new thread as well...I have MyCOMObject::Connect() create a new thread called MyLoginThread which I have MyLoginThread create an instance of this third party object and then call ThirdPartyObject->Login(). Ok, after calling ThirdPartyObject->Login() I call ::WaitForMultipleObjects to wait until either of those event objects become signaled. Now, because i'm calling ::WaitForMultipleObjects, MyLoginThread is now sleeping and the callback function still will not get processed because the thread is sleeping.
DWORD MyLoginThread (LPVOID lpData)
{
TheObject *ThirdPartyObject = NULL;
ThirdPartyObject = new TheObject(MyCallBackFunction);
ThirdPartyObject->Login(user, pass);
//This will wait for either object to become signaled
//in the callback function so I know i can move on.
::WaitForMultipleObjects(2, thisEvent, FALSE, INFINITE);
}
HRESULT MyCOMObject::Connect(user, pass)
{
hThread = CreateThread(NULL, 0, MyLoginThread, (LPVOID)Example, 0,NULL)
WaitForSingleObject(1, hThread, INFINITE);
}
With this code, as I said, the callback still doesn't get called because MyLoginThread is waiting for those objects to become signaled and the program also locks up because the thread sleeps forever which means Connect never returns.
I also tried taking out the ::WaitForMultipleObjects out of MyLoginThread, but then the program crashes because when the callback function is called, it's called on a thread that no longer exist! Maybe there is a way to tell windows to run that callback function on a different thread? Anyway, thank you for your help!
Michael
[edited by - bravescharm on June 13, 2002 10:45:44 AM]
I don't mind creating a new thread but i had trouble doing that as well. Ok, here is where i had trouble with a new thread as well...I have MyCOMObject::Connect() create a new thread called MyLoginThread which I have MyLoginThread create an instance of this third party object and then call ThirdPartyObject->Login(). Ok, after calling ThirdPartyObject->Login() I call ::WaitForMultipleObjects to wait until either of those event objects become signaled. Now, because i'm calling ::WaitForMultipleObjects, MyLoginThread is now sleeping and the callback function still will not get processed because the thread is sleeping.
DWORD MyLoginThread (LPVOID lpData)
{
TheObject *ThirdPartyObject = NULL;
ThirdPartyObject = new TheObject(MyCallBackFunction);
ThirdPartyObject->Login(user, pass);
//This will wait for either object to become signaled
//in the callback function so I know i can move on.
::WaitForMultipleObjects(2, thisEvent, FALSE, INFINITE);
}
HRESULT MyCOMObject::Connect(user, pass)
{
hThread = CreateThread(NULL, 0, MyLoginThread, (LPVOID)Example, 0,NULL)
WaitForSingleObject(1, hThread, INFINITE);
}
With this code, as I said, the callback still doesn't get called because MyLoginThread is waiting for those objects to become signaled and the program also locks up because the thread sleeps forever which means Connect never returns.
I also tried taking out the ::WaitForMultipleObjects out of MyLoginThread, but then the program crashes because when the callback function is called, it's called on a thread that no longer exist! Maybe there is a way to tell windows to run that callback function on a different thread? Anyway, thank you for your help!
Michael
[edited by - bravescharm on June 13, 2002 10:45:44 AM]
I don't think you need to create a new thread. Try this:
HRESULT MyCOMObject::Connect(user, pass)
{
TheObject *ThirdPartyObject = NULL;
ResetEvent(hsome_event);
ThirdPartyObject = new TheObject(MyCallBackFunction);
ThirdPartyObject->Login(user, pass);
WaitForSingleObject(1, hsome_event, INFINITE);
}
MyCallBackFunction
{
... // Your code here
SetEvent(hsome_event);
}
If your thread really calls MyCallBackFunction the event will be set when it reaches WaitForSingleObject and will run right through it (you've already got your result from MyCallBackFunction - no need to wait). If another thread calls MyCallBackFunction, MyCOMObject::Connect() won't return until MyCallBackFunction sets the event (which wont happen until after you've got your result from MyCallBackFunction).
[edited by - Solo on June 13, 2002 11:25:20 AM]
HRESULT MyCOMObject::Connect(user, pass)
{
TheObject *ThirdPartyObject = NULL;
ResetEvent(hsome_event);
ThirdPartyObject = new TheObject(MyCallBackFunction);
ThirdPartyObject->Login(user, pass);
WaitForSingleObject(1, hsome_event, INFINITE);
}
MyCallBackFunction
{
... // Your code here
SetEvent(hsome_event);
}
If your thread really calls MyCallBackFunction the event will be set when it reaches WaitForSingleObject and will run right through it (you've already got your result from MyCallBackFunction - no need to wait). If another thread calls MyCallBackFunction, MyCOMObject::Connect() won't return until MyCallBackFunction sets the event (which wont happen until after you've got your result from MyCallBackFunction).
[edited by - Solo on June 13, 2002 11:25:20 AM]
Solo,
Once again thank you for your reply. Now, I've tried this. When you call WaitForSingleObject(1, hsome_event, INFINITE);, it will put your current thread(the thread MyCOMObject::Connect is running on) to sleep until hsome_event becomes signaled. Now, if your thread is sleeping, MyCallBackFunction NEVER gets called because
MyCallBackFunction AND MyCOMObject::Connect are on the same thread, which is sleeping until hsome_event becomes signaled, which never becomes signaled because the thread MyCallBackFunction is running on was put to sleep by WaitForSingleObject. If that makes any sense? Anyway, thank you for your help. Maybe you or someone else has another idea?
Michael
[edited by - bravescharm on June 13, 2002 11:33:17 AM]
Once again thank you for your reply. Now, I've tried this. When you call WaitForSingleObject(1, hsome_event, INFINITE);, it will put your current thread(the thread MyCOMObject::Connect is running on) to sleep until hsome_event becomes signaled. Now, if your thread is sleeping, MyCallBackFunction NEVER gets called because
MyCallBackFunction AND MyCOMObject::Connect are on the same thread, which is sleeping until hsome_event becomes signaled, which never becomes signaled because the thread MyCallBackFunction is running on was put to sleep by WaitForSingleObject. If that makes any sense? Anyway, thank you for your help. Maybe you or someone else has another idea?
Michael
[edited by - bravescharm on June 13, 2002 11:33:17 AM]
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement