How to display a modal message box in C++ on Mac? - c++

CFUserNotificationDisplayAlert and CFUserNotificationDisplayNotice creates a non-modal window and this is bad because it could bring your application UI in a very undesired state if you select the original application window (the message box is hidden but the applicaton does not respond).
The old SystemAlert was modal but this one doesn't fully support Unicode strings.
How can i display a message box as a modal window under Mac? I'm looking for someting similar to MessageBox from Windows?

I've implemented it with CFUserNotificationDisplayAlert and it doesn't return until the user closes the MessageBox.
If you want to take a look of the code, I have it in MessageBox function in Mac
there you will find a MessageBox function implemented for mac, it's only implemented for MB_OKCANCEL, but with little more code could cover the entire MessageBox flags and return values, is a good starting point.

It looks that CreateStandardAlert is the right solution because this one is modal.
DialogRef theItem;
DialogItemIndex itemIndex;
CreateStandardAlert(kAlertNoteAlert, CFSTR("aaa"), CFSTR("bbb"), NULL, &theItem);
RunStandardAlert(theItem, NULL, &itemIndex);

Have a look at NSBeginAlertSheet function or at NSApp's:
- (void)beginSheet:(NSWindow *)sheet modalForWindow:(NSWindow *)docWindow
modalDelegate:(id)modalDelegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo
may be its what you want. Here is also a nice article about working with sheets.

Related

Windows.h - Notification when focus enters a text input

I'm trying to come up with a solution for setting up a notification when focus enters a text field. The end goal in mind is to recreate the type of functionality you see on mobile devices with on screen keyboards.
So far I've been exploring SetWinEventHook with EVENT_OBJECT_FOCUS and GetGUIThreadInfo with GUI_CARETBLINKING.
From the docs:
EVENT_OBJECT_FOCUS
An object has received the keyboard focus. The system sends this event
for the following user interface elements: list-view control, menu
bar, pop-up menu, switch window, tab control, tree view control, and
window object.
GUI_CARETBLINKING The caret's blink state. This bit is set if the
caret is visible.
Using these methods I've come up with this solution:
void TextInputHelper::setupEventHook(FREContext iCtx)
{
ctx = iCtx;
CoInitialize(NULL);
evHook = SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_END, NULL,
handleEventObjectFocus, 0, 0,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
}
void CALLBACK handleEventObjectFocus(HWINEVENTHOOK hook, DWORD evt, HWND hwnd,
LONG idObj, LONG idChild, DWORD thread, DWORD time)
{
GUITHREADINFO threadInfo;
threadInfo.cbSize = sizeof(GUITHREADINFO);
BOOL result = GetGUIThreadInfo(thread, &threadInfo);
if(threadInfo.flags & GUI_CARETBLINKING)
{
//text field focus
}
}
This does seem to work in some cases but its definitely not reliable. Programs like Notepad an IE seem to work fine but others like Firefox do not. This also will not work for things like text fields on websites because it doesn't look like handleEventObjectFocus will get called.
Does anyone know of another way to approach this problem? I've been searching around and it seems like I might be looking for something in the Accessibility APIs but I haven't been able to dig up to much on it.
Thanks!
edit
To clarify, I'm looking to receive a notification when focus enters any text field. This application is a win32 dll and will never have focus its self.
If you're using standard Windows controls WM_SETFOCUS should do the trick. No need to get fancy with hooking etc.
EDIT: For system wide behavior you can check out SetWindowsHookEx. To catch events system-wide you need to use it from within a DLL. You can use a combination of hooks including one that catches WM_SETFOCUS.
If you're trying to supply an alternative text input method, you should look into "IME" - "Input Method Editor". These are directly supported by the OS.
You can catch the entrance into a text field using the EN_SETFOCUS notification.
WM_FOCUS is for the window itself, not for controls that are in it. Otherwise said, if you want to use WM_FOCUS, you'll have to subclass your EDIT field. It's not necessary here.
EDIT: it wasn't completely clear that you wanted a system-wide behavior. IN that case you have to use an hook (cf. SetWindowsHookEx) as explained in the answer above. Sorry.

Modal QMessageBox does not behave like native Windows dialogs

My application has a dialog that asks the user via a QMessageBox whether he wants to discard all changes he made or wants to keep editing. I want this dialog to be modal to the whole application.
I read somewhere that this is the standard behavior for a QMessageBox, so I dont have to set it explicitly with something like:
mbox.setWindowModality(Qt::ApplicationModal);
I wonder why it behaves differently from other modal dialogs in the OS (Windows 7 in my case). On the one hand it functions like it should, i.e. all other input methods in the application are blocked until the user answeres the dialog. However, it doesn't 'blink'* if the user clicks any other window of the application. Is there any way to get Qt to behave like a native Windows dialog?
Thanks in advance!
*If you don't know what I mean with this 'blinking': Just open notepad on a Windows OS, type some text and try to close it. A dialog pops up that asks to save, discard or keep editing. Now click somewhere on the editor window -> the border and titlebar of the dialog flashes/blinks a few times.
The problem arises when the message box has no parent. This works fine for me:
QMessageBox box(this);
box.setStandardButtons(QMessageBox::Close);
box.exec();
But this does not:
QMessageBox box;
box.setStandardButtons(QMessageBox::Close);
box.exec();
This makes sense... the message box can't blink unless it knows that its parent was clicked on.
A simple solution that comes into my mind and if you want to deploy your application only on windows you should #include <windows.h> and use the MessageBoxA API.
Besides that this works great for me in Windows and ubuntu
if (QMessageBox::question(this,"Close?","Close this dialog?",QMessageBox::Yes,QMessageBox::No) == QMessageBox::Yes)
{
this->close();
}

Find a window using c++ and modifying controls

I would like to use c++ without mfc(and not clr) in order to modify textbox's and activate a button on a form outside of my project. I don't know where to start. I've done a lot of searching but can only find information for VB. A starting point would help.
Thanks.
I tried this and it doesn't seem to work.
HWND fWindow = FindWindow(NULL ,(LPCWSTR)"title");
and I also tried this
HWND fWindow = FindWindow(NULL ,LPCWSTR("title"));
I ALSO tried using LPTSTR instead of LPCWSTR, incase it was a unicode deal.
Maybe I don't understand this microsoft LPCWSTR and LPTSTR crap.
I also tried
HWND fWindow = FindWindow(NULL,TEXT("title"));
and that didn't work.
I guess the windows api must just be broken.
I tried the function on other programs...I'm using xp and I tried catching the calculator, and an explorer window, and something else. But I got nothing.
Heres some of the exact code I'm using to try and figure this out.
HWND face = NULL;
face = FindWindow(NULL,TEXT("My Computer"));
LPSTR title = TEXT("");
GetWindowText(face,title,250);
if(face != NULL)
{
MessageBox(NULL,title,TEXT("WOOP"),1);
}
face = nothing.
title = ""
Bear in mind, I'm not actually trying to hook explorer, I just want to figure out how to get it to work.
Use spy++ or winspector to see the actual "text" of the window.
(Strictly speaking, the caption of the window need not match it's window text. Especially true of "fancy" windows which paint their own caption.)
The following works fine for me (using Calc.exe to test).
HWND hwnd = NULL;
hwnd = FindWindow(NULL,_T("Calculator"));
TCHAR title[251];
if(hwnd != NULL)
{
GetWindowText(hwnd,title,250);
MessageBox(NULL,title,_T("WOOP"),MB_OK);
}
else
MessageBox(NULL,_T("No such window."),_T("OOPS"),MB_OK);
Edit: You should have used _TEXT instead of TEXT.
One way to do this is to use FindWindow to get a handle to the form. Then if you know the button and edit window Ids, you can use GetDlgItem to get their window handles. If you dont know the ids, you can use EnumChildWindows to examine all of the controls on the form.
Once you have the window handles for the controls, you can use SetWindowText to set the text on the edit control, and send a WM_COMMAND message to the form window with the button ID as the command value to make the form think that the button has been clicked.
There are a lot of ways to go about this once you have the correct window handles. There are security issues when you use the window handles of another process, but if the process isn't secured, then inter-process use of window handles just works. For a secured process, you won't be able to find out the window handles.
The windows API provides Methods for this. These should be independent of MFC and CLR, as they are plain win32. I had a project once accessing the Form fields of an Applictation from a loaded DLL (don't ask why).
you might want to look here (Codeproject)
or here (msdn)
At first, you need to obtain a handle to the process you want to access.
When have this, you can use GetDlgItem() (search msdn for that) to retrieve a handle to the desired textbox.
With this handle, you should be able to modify the control in question.
If your trying to get big (and do some more UI automation), you sould have a closer look at these:
Microsoft Active Accessibility
IAccessible2
Microsoft UI Automation
Windows Automation API (Win7)

MFC maximize window feature

I have tried to make the fullscreen feature of a SDI application with splitter windows by following the forum link. However, my status bar, system menu as well as the title bar of the application have disappeared. Do you have any suggestions on any easy ways of getting these back (or if I have to use different method of making the application maximized during startup instead of fullscreen)? Thanks in advance.
I got rid of any manipulations on the cs structure in the PreCreateWindow handler and used a ShowWindow(SW_MAXIMIZE) function call in the OnCreate function implementation of my MainFrame function, and it works quite well.
It sounds like you just want the window to be maximized. Take a look at the SetWindowPlacement function or ShowWindow.

How to add custom item to system menu in C++?

I need to enumerate all running applications. In particular, all top windows. And for every window I need to add my custom item to the system menu of that window.
How can I accomplish that in C++?
Update.
I would be more than happy to have a solution for Windows, MacOS, and Ubuntu (though, I'm not sure if MacOS and Ubuntu have such thing as 'system menu').
For Windows, another way to get the top-level windows (besides EnumWindows, which uses a callback) is to get the first child of the desktop and then retrieve all its siblings:
HWND wnd = GetWindow(GetDesktopWindow(), GW_CHILD);
while (wnd) {
// handle 'wnd' here
// ...
wnd = GetNextWindow(wnd, GW_HWNDNEXT);
}
As for getting the system menu, use the GetSystemMenu function, with FALSE as the second argument. The GetMenu mentioned in the other answers returns the normal window menu.
Note, however, that while adding a custom menu item to a foreign process's window is easy, responding to the selection of that item is a bit tricky. You'll either have to inject some code to the process in order to be able to subclass the window, or install a global hook (probably a WH_GETMESSAGE or WH_CBT type) to monitor WM_SYSCOMMAND messages.
Once you have another window's top level handle, you may be able to call GetMenu() to retrieve the Window's system menu and then modify it, eg:
HMENU hMenu = GetMenu(hwndNext);
You can use EnumWindows() to enumerate top level Windows.
I don't have a specific answer for the second part of your question, but if you subclass the window, I imagine you can modify the system menu.
EDIT: or do what Chris said: call GetMenu()
Re: the update - please note that not even Microsoft Windows requires windows to have a sytem menu. GetMenu( ) may return 0. You'll need to intercept window creation as well, because each new top window presumably needs it too.
Also, what you propose is rather intrusive to other applications. How are you going to ensure they don't break when you modify their menus? And how are you going to ensure you suppress the messages? In particular, how will you ensure you intercept them before anyone else sees them? To quote Raymond Chen, imagine what happens if two programs would try that.