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);
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.
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.
I have a problem when trying to hook the keyboard (not a keylogger!) I´m trying to automate Word, then i´m calling dll with a especific hook.
I have a desktop and a notebook (the two have same antivirus + windows 7 x64), the only diference is that in the notebook the windows was installed with a newer version. THE PROBLEM: In the notebook EVERYTHING WORKS FINE. But in the desktop odd things happen: the hook was installed and works well if targeted to Notepad, but, when targeted to Word, though the hook was installed, the call to a external function is supressed!
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{
if (code<0) {
return CallNextHookEx(HookHandle,code,wParam,lParam);
}
bool callNextHook = true;
if (callFunction != NULL) {
// ONLY WITH WORD AND ONLY IN THE DESKTOP callFunction SEENS TO BE NULL!!!
// this is a pointer to a function in main application
callFunction(code,wParam,lParam,&callNextHook);
} else {
ShowMessage("THE UNKNOW ERROR! THIS MESSAGE IS SHOWED, THEN HOOK IS INSTALLED");
}
//Call the next hook in the chain
if (callNextHook) {
return CallNextHookEx(HookHandle,code,wParam,lParam);
}
return 0;
}
I already tried disabling antivirus, changing user account control, running the program as admin... nothing works. What is causing this difference?
It probably has to do with the LowLevelHooksTimeout value in the registry.
On faster machines, they can process the hooks fast enough and make it under the default 200 ms to process timeout. On slower machines, they have a harder time.
For me I've had to bump up this value from the default to 500 ms (0x1F4) for my application involving hooks, to be reliable across machines.
To see the effect of changing this registry value, you have to restart your computer.
See the fourth paragraph in the remarks on the documentation here:
LowLevelKeyboardProc callback function
The hook procedure should process a message in less time than the data
entry specified in the LowLevelHooksTimeout value in the following
registry key:
HKEY_CURRENT_USER\Control Panel\Desktop
The value is in
milliseconds. If the hook procedure times out, the system passes the
message to the next hook. However, on Windows 7 and later, the hook is
silently removed without being called. There is no way for the
application to know whether the hook is removed.
Hope that helps.
Seems to be a bug in rad studio xe2, compiling the hook dll with xe6 resolved the issue. Interesting, with this bug and some extra code, was possible to hook both 32 and 64 programs with only one dll. This way, I continue using the old dll compiled with xe2.
I've got a Qt application that has two main windows. On Linux, when one main window brings up a modal dialog, it comes up behind the other main window. What can I do to cause the dialog to always come up on top of ALL main windows?
NOTE: This only happens on Linux. We build this app on MacOSX as well, and the problem does not occur there.
Here's the code that brings up the dialog. The stuff in the #if is all the things I've tried to bring the window forward. I've tried various combinations and orders of these things.
QMessageBox dialog;
dialog.setIcon( QMessageBox::Information );
dialog.setWindowTitle( _documentName );
dialog.setText( tr("This document has unsaved changes. Do you want to save before closing?") );
dialog.setInformativeText( tr("Your changes will be lost if you don't save them.") );
dialog.setStandardButtons( QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel );
dialog.setDefaultButton( QMessageBox::Save );
dialog.setFixedSize( dialog.size() ); // non-resizable window
#if STUFF_I_TRIED
dialog.show();
dialog.setVisible(true);
dialog.open();
dialog.activateWindow();
dialog.raise();
#endif
int result = dialog.exec();
I realize that exec() should be all I need to show the window. My idea in calling show() or open() was just to allow activateWindow() or raise() to take affect. Just foolin' around trying to get that damn dialog to come forward.
TIA for any help!
All the sequcence between #if 1_ and #endif looks pretty weird to me.
Normally, to show modal dialog, only exec() is needed:
QMessageBox msgBox;
msgBox.setText("They killed Kenny, again.");
int ret = msgBox.exec();
Reference.
You are doing quite a bit of things between your #if 1, that is likely confusing X11.
You need only ONE of those. Since you are working with Mac and X11, I suspect you want to use open() and get a sheet.
IIRC, show() vs. open() causes different window flags to be set, so
calling them right after each other may get the window into a strange
state. Also calling show() or open() should always activate or raise the window if it is a dialog, which QMessageBox is.
Try only using one of these and seeing what happens.
I'm localizing an MFC app into Japanese, and have the resources working right.
My current problem is that, when I use AfxMessageBox or MessageBox, the dialog title and button messages come up in English, and I haven't found anywhere to change that.
I haven't found anything useful searching MSDN or Google.
So,
Does this work? Does Windows come up with "OK" or "Yes/No" buttons in Japanese, Arabic, and Russian?
If not, what do I specify to change these?
Edit: I went with MessageBoxEx, writing a wrapper class to make it as convenient to use as AfxMessageBox. It does appear that MB_OK comes up as "OK" in both English and Japanese, but other button options like MB_YESNO are translated into something that I assume is correct Japanese. This was a fairly small application to translate, and we might want to use something automated for the larger ones.
Use MessageBoxEx and specify the WORD wLanguageId field.
wLanguageId
[in] Specifies the language for the text displayed in the message box
button(s). Specifying a value of zero
(0) indicates to display the button
text in the default system language.
If this parameter is
MAKELANGID(LANG_NEUTRAL,
SUBLANG_NEUTRAL), the current language
associated with the calling thread is
used.
To specify a language other than the current language, use the
MAKELANGID macro to create this
parameter. For more information, see
MAKELANGID.
More information on MAKELANGID can be found here.
If this does not work well for you, the alternative would be to make your own dialog box.
The title is a string you specify, so you should be able to translate it.
In AfxMessageBox(), the title is the application name (AfxGetAppName() IIRC).
Regarding the buttons, the text is part of the OS and cannot be translated.
MessageBoxEx (mentioned by Brian) never worked well regarding languages support. This MS KB article from over a decade ago says the language id will be correctly supported by Windows 2000. But it obviously never made it through.
So you're pretty much out of luck. Your only solution would be to use a 3rd party implementation such as the excellent XMessageBox and provide translations through your string table.
Note that appTranslator's glossary contains words such as Yes, no, cancel,... in 25 languages and would translate them automatically.
Create your own L10N macros/function and use this code:
static LRESULT __stdcall ChangeCaptions(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_ACTIVATE) {
SetWindowText(GetDlgItem((HWND) wParam, IDOK), L10N(GUI_OK_MSG));
SetWindowText(GetDlgItem((HWND) wParam, IDCANCEL), L10N(GUI_CANCEL_MSG));
SetWindowText(GetDlgItem((HWND) wParam, IDYES), L10N(GUI_YES_MSG));
SetWindowText(GetDlgItem((HWND) wParam, IDNO), L10N(GUI_NO_MSG));
}
return 0;
}
int addon_gui_messagebox(HWND parentHWnd, HINSTANCE hInstance, void *text, void *caption, int type)
{
int ret;
hook = SetWindowsHookEx(WH_CBT, ChangeCaptions, hInstance, GetCurrentThreadId());
ret = MessageBox(parentHWnd, text, caption, type);
UnhookWindowsHookEx(hook);
return ret;
}
As I wrote previously MessageBoxEx currently ignore lang arg.