I have subclassed a window using SetWindowSubclass(), and my message handler is successfully called, but when I call DefWindowProc() to pass the messages on for their original processing, no messages ever get through!
We are writing an extension to Marmalade (a kit for cross-platform mobile development). It allows for native extensions for specific platforms, and we're writing one for the Windows desktop build. We don't have direct access to the message loop, but can subclass to handle messages ourselves, however we don't seem to be able to pass the messages back to Marmalade for normal processing.
For example, even doing nothing in the callback but calling DefWindowProc() still doesn't work:
// Initialization:
const UINT_PTR gSubClassId = NULL;
DWORD_PTR subClassCBData = NULL;
SetWindowSubclass(gMainWindow, CadUtil_WindowCB, gSubClassId, subClassCBData);
...
// Message processing callback.
static LRESULT CALLBACK CadUtil_WindowCB(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
// Messages are correctly diverted here, but DefWindowProc() below isn't passing them on.
return DefWindowProc(hWnd, message, wParam, lParam);
}
Any idea how this can happen?
Thanks,
Rob.
I think the problem with your code example is that you should call DefSubclassProc instead of DefWindowProc when subclassing a window.
I still don't know why subclassing didn't work, but I was able to work around it by using hooks instead. So instead of using SetWindowSubclass() to capture messages and DefWindowProc() to pass them through, I now use SetWindowsHookEx() with WH_CALLWNDPROC and WH_GETMESSAGE to capture messages, and call CallNextHookEx() in the hook to pass messages through. This works where subclassing wouldn't.
Related
I have this code:
GetParent()->SendMessage(UWM_DELETE_NAME_HISTORY_MSG, (WPARAM)strName.GetBufferSetLength(_MAX_PATH));
strName.ReleaseBuffer();
Is it safe for me to change it like this:
GetParent()->SendMessage(UWM_DELETE_NAME_HISTORY_MSG, (WPARAM)strName.GetString());
Related to this, is it correct to use static_cast<WPARAM>(strName.GetString())?
For completion, this is my custom message handler:
LRESULT CChristianLifeMinistryEditorDlg::OnDeleteNameHistory(WPARAM wParam, LPARAM lParam)
{
auto szName = (LPCTSTR)wParam;
m_History.erase(szName);
for (auto& kv : m_mapWeekendHistData)
kv.second.erase(szName);
return 0;
}
SendMessage is a blocking call. Once it returns, it no longer needs access to its arguments. With that in mind
GetParent()->SendMessage(UWM_DELETE_NAME_HISTORY_MSG, (WPARAM)strName.GetString());
is safe (as far as the SendMessage call is concerned).
You'd still need to be careful about the implementer of the UWM_DELETE_NAME_HISTORY_MSG message (which, presumably, is a custom message). If the implementation stores a pointer and uses it after the handler has run to completion, then that is an issue that needs to be resolved.
In general, if you implement a message handler, you should follow the Windows API's core principles. There are ultimately two implementation:
Store a copy of client-provided data (such as SetWindowTextW).
Return a reference to the previous value in case the API takes ownership of the client-provided data (such as SelectObject).
To answer your question in the title:
Is it safe to use CString::GetString() with CWnd::POstMessage()?
No, it is not - the content of that CString may be reallocated or deleted by the time the message will be processed.
It is a simple question that I might delete soon, but I have a problem that I don't seem to find anywhere else (at least google has not helped).
I am trying to write a plugin for a software based completely in MFC, but I refuse to use MFC myself. I thought that, in the end, I could just use the proper handles and modules to create my windows with winapi to work with MFC but it does not seem that easy. I am trying to launch a "Modal" window (that is, it blocks the parent by calling EnableWindow(parentHwnd, FALSE)). For this window I wrote a custom wndProc function:
LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
//Do stuff to get a HWND to the parent window
switch(msg) {
case WM_CLOSE:
EnableWindow(parentHwnd, TRUE);
//DestroyWindow(hwnd);
return DefWindowProc(hwnd, msg, wParam, lParam);
case WM_DESTROY:
EnableWindow(parentHwnd, TRUE);
//PostQuitMessage(0);
return DefWindowProc(hwnd, msg, wParam, lParam);
//... Handling other messages
When the user closes the window, I want to enable the parent and simply close my custom window. You can see that the functions DestroyWindow(hwnd) and PostQuitMessage(0) are commented, and instead I return DefWindowProc. This is because leaving the message uncommented, the whole app crashes with the following exception:
My first guess would be that there is a problem with the messages in windows. I don't know if I am forced to use the "DECLARE_MESSAGE_MAP" macro or something to handle my events in MFC's wndProc. I'm quite a beginner for windows development so, even though I found a solution for this crash, I'm not quite satisfied because I have no idea why it failed in the first place. Thank you!
First, what is a "plugin" exactly? From what I can guess it must be just some additional code, built into the main executable (otherwise you wouldn't be asking about message-maps and that "MFC's wndProc"). As for your question, maybe you don't really need to get into this. I'm just wondering if it would work just calling:
DialogBox(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDD_MYDIALOG), parentHwnd, MyDlgProc);
Trying to push a message into UI and receive some result to return in synchronous way from web-service.
Method code goes as follows.
[OperationContract]
public string DecypherCaptcha(string captcha)
{
var connection = new HubConnection("http://localhost:51806");
IHubProxy hub = connection.CreateHubProxy("robo");
string decaptcha = null;
hub.On("captchaDecyphered", decyphered =>
{
decaptcha = decyphered;
});
connection.Start().Wait();
hub.Invoke<string>("DecypherCaptcha", new object[] { captcha });
return decaptcha;
}
The issue is that method finishes before value is obtained from hub's captchaDecyphered. However the expression { decaptcha = decyphered; } triggers fine from server after method exits.
Adding ManualResetEvent flag and WaitOne() for it doesn't solve the problem freezing the execution and preventing hub.On("captchaDecyphered" from firing.
Any ideas how to synchronize this?
UPDATE#1 Small notice. Cannot avoid using the intermediate synchronous WCF web-service acting as SignalR client, because of pretty specific robots sitting behind, which are able to interact with outer world only by calling webservices synchronously. Basically in this scenario when robot faces captcha it calls the web-service passing it via SignalR to UI for manual recognition.
UPDATE#2 Thanks to #Ken's inspiring advice got it working by enclosing the connection establishing and hub method invocation into separate 'Thread' followed by waiting with 'ManualResetEvent':
new Thread(() =>
{
connection.Start().Wait();
hub.Invoke<string>("DecypherCaptcha", new object[] { captcha });
}).Start();
sync.WaitOne();
Have previously been trying to start from 'Task' supposing it would run on separate thread implicitly, but with no luck.
You could have the DecypherCaptcha hub method on the SignalR server return the deciphered captcha as a Task<string> instead on invoking captchaDecyphered.
You may want to use a TaskCompletionSource to help you create the appropriate task. Basically you could call tcs.SetResult(deciphered) and return tcs.Task instead of calling Clients.Caller.captchaDecyphered(deciphered).
Then your client-side code code would simply be:
[OperationContract]
public string DecypherCaptcha(string captcha)
{
var connection = new HubConnection("http://localhost:51806");
IHubProxy hub = connection.CreateHubProxy("robo");
connection.Start().Wait();
return hub.Invoke<string>("DecypherCaptcha", captcha).Result;
}
You've got several options.
(1) Spin off the request to the SignalR hub onto a separate thread, probably using the static ThreadPool class, and then add in all the ManualResetEvent stuff. That way it won't block when you're waiting on the SignalR method to return.
(2) Make the DecypherCaptcha method asynchronous. It looks to me like the DecypherCaptcha() is intended to be a WCF method that in turn wraps a SignalR method. If that's the case, forgetting for a moment whether this is a wise approach, you could still call a WCF method on the client when the captchaDecyphered SignalR method completes. But if it's not intended to be a WCF method, then you could have DecypherCaptcha() either (a) return a Task<T>, and only flag the Task to be complete when the captchaDecyphered completes; or (b) pass in a Func<T> as a continuation parameter, and call that when the captchaDecyphered completes.
In general, one of the things that makes asynchronous programming difficult is that except for the very top-level method, you generally need to make every method that calls an asynchronous method itself asynchronous, all the way up and down the stack, either through the Async pattern (nasty), or continuation passing (better) or through a Task object + async/await (probably best). So adding in a single asynchronous method often results in significant changes to your application, all the way through. That's one of the many reasons why the new async and await keywords in .NET 4.5 are so helpful, because they help to encapsulate the necessary changes when you start making your application asynchronous.
You can use the generic Invoke method where you can specify the type of result you expect. With the method you CAN use .Result to wait for the result.
string result = IHubProxy.Invoke<string>("GetString").Result;
I have a Silverlight application that uses WCF services and also uses the Wintellect Power Threading library to ensure logic executes fully before the application continues. This is achieved by calling back to the application using delegates so it can continue after the service call has completely finished.
I wish to achieve the same thing in another part of my application but without the use of callbacks e.g. call method that uses WCF service to say load an object from the database, wait for this to return and then return the Id of the object from the original method called.
The only way I could see to do this was to carry out the call to the WCF service in a helper library which loads the object on a different thread and the original method would keep checking the helper library (using static variables) to wait for it to complete and then return it.
Is this the best way to achieve this functionality? If so here are details of my implementation which is not working correctly.
public class MyHelper
{
private static Thread _thread;
private static User _loadedObject;
public static GetUser()
{
return _loadedObject;
}
public static void LoadObject(int userId)
{
_loadedObject = null;
ParameterizedThreadStart ts = new ParameterizedThreadStart(DoWork);
_thread = new Thread(ts);
_thread.Start(userId);
}
private static void DoWork(object parameter)
{
var ae = new AsyncEnumerator();
ae.BeginExecute(DoWorkWorker(ae, Convert.ToInt32(parameter)), ae.EndExecute);
}
private static IEnumerator<Int32> DoWorkWorker(AsyncEnumerator ae, int userId)
{
// Create a service using a helper method
var service = ServiceHelper.GetService<IUserServiceAsync>();
service.BeginGetUserById(userId, ae.End(), null);
yield return 1;
_loadedObject = service.EndGetUserById(ae.DequeueAsyncResult());
_thread.Abort();
}
}
My method then is:
public int GetUser(int userId)
{
MyHelper.LoadObject(userId);
User user = MyHelper.GetUser();
while (user == null)
{
Thread.Sleep(1000);
user = MyHelper.GetUser();
}
return user.Id;
}
The call to the get the user is executed on a different thread in the helper method but never returns. Perhaps this is due to the yield and the calling method sleeping. I have checked the call to get the user is on a different thread so I think everything should be kept separate,
The whole construct you are using does not match current best practices of Silverlight. In Silverlight your data access methods (via WebServices of course) are executed asynchronously. You should not design around that, but adapt your design accordingly.
However calling services sequentially (which is different than synchonously) can be valid in some scenarios. In this blog post I have shown how to achieve this by subscribing the Completed event of the remote call and block the UI in the meantime, with which the workflow looks and feels like normal async calls.
I believe calls to the server from Silverlight apps use events that fire on the UI thread; I think that's part of the Silverlight host environment in the browser and can't be worked around. So trying to call back to the server from another thread is never going to end well. If you are waiting in program code in the UI thread, your never going to get the call result events from your WCF calls.
You can simulate a synchronous call from a non-UI thread with a callback on the UI thread, but that is probably not what you want. It's better to bite the bullet and make your program logic work with the async calls Silverlight gives you.
If you code against the Interface created for your service reference you can call the Begin and End methods 'synchronously' for each one of your service calls, we then pass in an Action<T> to execute after the End methods has completed. Take note that you have to do this from a dispatcher. This is very close to making a synchronous call as the code to run after the call is still written where the call is made, and it executes after the service call is completed. It does however involve creating wrapper methods but we also worked around that by hiding our wrappers and generating them automatically. Seems like a lot of work but isn't, and ends up being more elegant than all the event handlers etc. Let me know if you need more info on this pattern
Can somebody please explain why the event "OnNewMail" is not raised when using an STA thread in the code below? The program attempts to use the Redemption library to intercept incoming outlook mails.
class Program
{
[STAThread()] // When this line is deleted the application works
static void Main(string[] args)
{
RDOSession session = GetSession();
session.OnNewMail += Session_OnNewMail;
Console.ReadLine();
}
static void Session_OnNewMail(string EntryID)
{
Console.WriteLine("New mail received");
}
private static RDOSession GetSession()
{
var session = new RDOSession();
var application = new ApplicationClass();
session.MAPIOBJECT = application.Session.MAPIOBJECT;
return session;
}
}
COM running on an STAThread uses a message pump to raise events and call methods. When in a console application there isn't a window to pump messages for you so you need to run the pump yourself. (Several of the .NET synchronisation methods will do this for you - have a look at WaitOne etc...)
If the object is happy within a default MTA thread - you may be better off using that if you need to do this from a console application.
Instead of ReadLine - you can poll for a key and pump messages using this:
while (Console.Read() == 0)
{
Thread.CurrentThread.Join(100);
}
...but this is a hack.
Mixing COM, console apps and [STAThread] is a bit fishy and can result in other problems:
http://support.microsoft.com/default.aspx/kb/828988
When the tread is STA thread and you wait for input the library can't do anything at the same time and has no chance to fire the event when an email arrives.
The problem almost certainly has to do with message pumping.
Unless we know what type of COM object RDOSession is (STA, MTA, etc ...) we can only speculate as to what is actually going on.
My guess is that RDOSession is an MTA COM object and that somehow the event code has bound the event to an STA proxy or object. This means that part of the raising of the OnNewMail event must marshal the raise onto the STA thread. This involves window message passing. You are doing a simple ReadLine call which is a blocking call and will not process messages. Hence you won't ever get the event.