Close OleCreatePropertyFrame externally - c++

I am using OleCreatePropertyFrame to display property pages of the webcam. But, I wasn't able to make the dialog modal or close the frame externally when closing the camera.
OleCreatePropertyFrame(
NULL, // Parent window
0, 0, // Reserved
lpcostr, // Caption for the dialog box
1, // Number of objects (just the filter)
&pFilterUnk, // Array of object pointers.
caGUID.cElems, // Number of property pages
caGUID.pElems, // Array of property page CLSIDs
0, // Locale identifier
0, NULL // Reserved
);
Any help is appreciated.

OleCreatePropertyFrame is standard API for modal dialog box meaning that it is supposed that the mesasge box is displayed until closed interactively. That is, you are not supposed to be able to close it from code.
This function always creates a modal dialog box and does not return until the dialog box is closed.
One of the ways to make the dialog modal is to re-implement property page host (IPropertyPage and friends) and put it into your customized UI as a modeless window or otherwise. It is quite doable overall, and mostly expects basic knowledge of COM.
Another [traditional?] trick to close standard modal UI externally is to PostQuitMessage into the inner message loop of OleCreatePropertyFrame API so that it closes the dialog box in response to non-interactive signal, and then remove pending WM_QUIT message from the outer message loop, added by the API after closing the dialog in attempt to forward quit command further.

Related

Using a dialog box as a main window. Not receiving WM_INITDIALOG messages

I have created a modeless dialog as a main window, but the window procedure isn't being sent WM_INITDIALOG messages.
Here's what I've done.
Created a dialog template using Visual Studio's resource editor, and
set its class name to a custom class.
Used WNDCLASSEX to register the class, window procedure, as well as
some icons and brush etc.
Used CreateDialog() with the last two parameters set to NULL, (Parent
window, and window procedure).
Created the message loop using IsDialogMessage(), TranslateMessage()
and DispatchMessage();
Returned DefDlgProc() in the window procedure as the default if no
messages were processed.
I can't think of anything else significant. Everything works well except for not receiving WM_INITDIALOG messages.
I've done it this way so the app minimises to the task bar, and I can have a menu if needed.
So my first question is, Have I done anything stupid?
Secondly, should I expect to receive WM_INITDIALOG messages using this system?
And if not, what is a good way to initialise say a combobox with strings.
(I've looked at things like WM_ACTIVATE, WM_ACTIVATEAPP etc, but nothing seems appropriate.
And the combobox isn't created yet at WM_CREATE.)
Thanks in advance.
I realised the answer shortly after posting.
As mentioned in the comments above, it's a window procedure, not a dialog procedure, so I shouldn't have been trying to initialize child windows within the procedure.
So I initialized them outside the procedure, after creating the dialog box and before the message loop.
All the dialog features are working as expected, but it's a main window that can have a menu and minimizes to the taskbar.

check for reparented window close events

I am trying to make a xlib traybar for X11 where it embeds the tray icons using XEMBED as described in the tray specs. However when I close the application with the tray icon it just removes it from the container window but the black container window rectangle and the entry in my code still exists.
In the XEMBED documentation it says
It is the responsibility of the embedder to keep track of all forwarded
accelerators and to remove them when the client window dies.
However my application does not get any events or indication when a embedded window dies.
I basically only receive a dock request event and nothing else afterwards. When a dock request event comes in I create a child window for my panel which contains the tray window and reparent it like this:
enum trayIconSize = 24; // dimensions of icon
icon.trayWindow = XCreateWindow(x.display, panel.window, 0, 0, ...);
icon.ownerHandle = event.data.l[2]; // window id of icon which wants to dock
XReparentWindow(x.display, icon.ownerHandle, icon.trayWindow, 0, 0);
XMoveResizeWindow(x.display, icon.ownerHandle, 0, 0, trayIconSize, trayIconSize);
Adding it to the panel works without any problems but I don't know how to check when to remove it again.
How do I make my application receive close events for those tray icons or how do I check if the reparented window still exists?
I have actually done this before myself: https://github.com/adamdruppe/taskbar it has hacks for my specific setup in the width thing, but most of it should be reasonably usable and the code might help guide you.
But what you want to do is ask for events on the icon window. It has been a while, so I'm kinda using my own code as a guide here, but when I got the dock request, I called XSelectInput(dd, id, EventMask.StructureNotifyMask);
StructureNotifyMask subscribes to events including MapNotify, DestroyNotify, you prolly see where this is going :)
Once you have selected the input on the icon window, you regular event loop can check for the DestroyNotify and UnmapNotify events (my code checks both, tbh, I'm not sure which one actually triggers when the icon is removed) and compare the .window member of the event to your icon's window ID. If it matches, go ahead and remove it from your list because it is gone now.
My taskbar does seem to have a bug if the application crashes as opposed to being closed normally, so I might still be missing something, but checking the event works in most cases.

Programmatically closing a dialog box - win32

I'm working on an application to detect a pop-up dialog and then
automatically dismiss it. I'm writing this as a C++/Win32 app. The
dialog box is generated by IE 7 and I can detect the window, but
several methods to get the OK button to "click" have failed.
Doing searches for other people's solutions, sending these messages to
the button handle seems to have worked in a lot of situations:
PostMessage( handle, WM_LBUTTONDOWN, 0, 0 );
PostMessage( handle, WM_LBUTTONUP, 0, 0 );
PostMessage( handle, BM_SETSTATE, 1, 0 );
It has no effect on the button state in my tests though.
I can send tab characters to the main window and see that the OK
button gets focus, but then sending return characters does nothing.
To learn more about this I used Spy++ to get information about the
window hierarchy and what messages are delievered when I manually
click the OK button.
Looking at the message log and reading about WM_MOUSEACTIVATE seamed
to offer a solution. The log info shows that 0002166C was the button
window. So in my code I tried this:
GetClassNameA( handle, str, str_size );
if( strcmp( str, "Internet Explorer_Server" ) != 0 )
return TRUE; // Not the window we're interested in.
// Send a message to activate the button window and have it process a mouse click.
PostMessage( handle, WM_MOUSEACTIVATE, (WPARAM) dialog_handle, MAKELPARAM( HTCLIENT, WM_LBUTTONDOWN );
Based on the window hierarchy and message log, I think the window with
the class name "Internet Explorer_Server" is the button. Maybe I'm
wrong, because it does seem like an odd class name for a button...
Below is a link to the window hierarchy image, message log when I
manually click the OK button. Last is the code that's executed on a 1
second timer ticket, looking for the window.
Any insight and help is appreciated!
Image of the window hierarchy, source, window messages, and test dialog source are available here:
https://sites.google.com/site/matthewmillersmiscellanea/Home/
Ideally, you should create a DLL which exports a Global CBT Window Hook. This would allow you to get early notification when a dialog is going to be created. This would avoid the need to drain resources by constantly polling.
Once you've detected that a dialog is about to be created, you have two options:
1) Prevent the dialog creation.
I don't recommend this, it causes all sorts of problems with code that was fully expecting a valid HWND to be returned by CreateDialog();
2) Asynchronously control the dialog.
We achieved this by using PostMessage with a Registered user message and picking it up by hooking the WNDPROC. When you get this message, then you have to decide how to kill the dialog that you're in.
There are multiple ways to exit the dialog:
a) Simulate pressing OK, Cancel, Abort, No buttons using WM_COMMAND(BN_CLICKED) (as Chris comments). You can use GetDlgItem(), look for the WindowText and make your choice. However, this doesn't work for non-US-English. There may be some distance in leveraging the Accessibility API here though.
b) Simulate closing the dialog with PostMessage(WM_CLOSE, m_hWnd). This doesn't always work as expected - some dialogs have no [X] close button and their client code is expecting a specific button to be pressed instead.
c) Simulate user input using the SendInput() API. This worked around dialogs that had anti-popup-killer code in them :)
Our final solution was a rule+heuristic-based approach that had a configuration file which we could tweak when the app/IE dialogs changed their ID's, class names or parent class names.
To close continually a specific popup given that you know the window class name and window caption
#define UNICODE
#include <windows.h>
#pragma comment(lib, "user32")
int main (int nn, char ** aa)
{
while (true) {
HWND iHandle = FindWindow (L"theWindowClassName", L"theWindowCaption");
if (iHandle > 0) SendMessage(iHandle, WM_SYSCOMMAND, SC_CLOSE, 0);
Sleep (200); // check 5 times per second
}
return 0;
}
if one is not known or too generic (e.g. "Dialog") you can omit it by passing a null
HWND iHandle = FindWindow (L"theWindowClassName", 0);
or
HWND iHandle = FindWindow (0, L"theWindowCaption");
of course this will close all windows with the given names.

C++/Win32 API - SetFocus to button does not work

HWND button = CreateWindowEx(0, "BUTTON", ...);
SetFocus(button); // Button no get focus! :(
Also, I have other controls on my form that I am able to SetFocus() to.
Thanks, Martin
It has been FOREVER since I've had to do this, but...
Were this a dialog, I would tell you to send a WM_NEXTDLGCTL via PostMessage(). The default dialog item message handler would take care of the rest for you setting keyboard focus and selection activation. However, this is a different case if I read this correctly. You're creating both parent and child windows raw on the fly. If this is the case, SetFocus() to the parent window, and handle WM_SETFOCUS on the parent window by bringing it to top, then setting focus on the child window. WM_SETFOCUS, and WM_KILLFOCUS were designed to allow you to switch the 'activated' state of your controls, and most handle it for you (unless your window is an owner draw control or some such). But in a raw window, when your base parent window is sent the focus, you need to appropriately ensure the proper child has it if you're hosting any (think of it as managing your own 'dialog'). Again, normally this is done by the default dialog procedure for you if this were a dialog, but being raw windows you're kind of stuck managing it all yourself.
Though I can't imagine how, I hope that helped somewhat.
SetFocus is a function, not a procedure. Call it as a function and check its returned value. Either the retuned value is null because you made an error in the CreateWindowEx() call and "button" isn't a valid handle or it's a window not associated with your thread's message queue, or the return value is not null (it's now the prior focused window's handle) and you do have the focus (but are somehow failing to detect it).
Try setting the WS_TABSTOP style on the button.
If you create that button in respond of the WM_INITDIALOG message you should return FALSE to prevent dialog box procedure to change the focus.

win32 DialogBox app: how to show text from callback on the DialogBox?

I'm working on a win32 DialogBox based app. This uses DialogBox() to create the dialog box, and has a dialog box procedure which does all the usual things.
The dialog box has some static text controls on it, and generally I'm showing text in these via SendDlgItemMessage() from within the dialog box procedure.
However at one point the DialogBox initiates a lengthy operation. This operation has a callback with a series of status messages. I'm having some trouble showing these messages on the dialog box, for two reasons:
The callback function doesn't know what the dialog box HWND is, because it gets called from the code which carries out the lengthy operation. I suppose I can define a file scope HWND variable and copy the dialog box HWND into it from the dialog box procedure just before the lengthy operation is started. That way, the callback function could have access to the dialog box HWND. But that seems awfully kludgy: is there a more elegant way?
The dialog box procedure is blocked while the lengthy operation happens. This doesn't matter because it's an embedded system. But will Windows even show the text in the dialog box if I issue a SendDlgItemMessage() while the dialog box procedure is blocked?
edit I've done some investigations using SendDlgItemMessage() to send a WM_SETTEXT to a static text control on a dialog. The text is displayed immediately even if the dialog box procedure is blocked.
Well, your dialog HWND is a singleton so it isn't the end of the world. But yes, the standard way this is done is by passing an opaque pointer to the code that gets the job done. Compare with the lParam argument of EnumWindows() for example, the callback gets that pointer back.
Whether a control repaints itself immediately is an implementation detail. I only know of progress bar doing this. You could call UpdateWindow on the dialog window handle to get any pending paint updates flushed to the screen.
The all-around better mouse trap is to perform long running tasks on a worker thread. Avoids Windows displaying the "Not Responding" ghost window, avoids timeouts on broadcast messages and numerous potential deadlock problems. But tends to be tricky to get right, you cannot update the window directly from the worker thread.