How to make modal form un-minimize after a Show Desktop (or windows + D) - c++builder-xe5

When I start my application, the first and only form that shows is a login form in modal:
frmLogin = new TfrmLogin(Application);
frmLogin->Init();
if(frmLogin->ShowModal() == mrCancel)
{
//this will exit the application because user cancel the login
return -1;
}
There is code happening after the ShowModal which open the main form (not in modal) of the application.
When I press Show Desktop or do windows + D and I'm still on the modal form for the login, I can't get the login back when clicking on the taskbar.
1. Is there a way to un-minimize the modal login after a 'Show Desktop'?
2. Also, if I open my application and the login appears, I can't seem to be able to close it when right-clicking on it in the taskbar > 'Close windows'. Is there a way to close it by the taskbar? (It close perfectly when using the red 'x' in the corner of the login form though)
I'm using c++ Builder 10.1 Berlin

As #Remy Lebeau suggested, I came to the solution by overriding the CreateParams() function.
In my Login.h
protected:
virtual void __fastcall CreateParams(TCreateParams &Params);
In my Login.cpp
void __fastcall TfrmLogin::CreateParams(TCreateParams &Params)
{
TForm::CreateParams(Params);
Params.ExStyle = WS_EX_APPWINDOW;
Params.WndParent = GetDesktopWindow();
}
My code is based on the Delphi example found here:
https://forums.embarcadero.com/thread.jspa?threadID=244599
Now, my Login form is able to be un-minimized after a ctrl + D!
Hopes this helps other c++ builder programmers out there.

Related

Can not use Alt + F4 to close program when WPF application have a Webview

My application have a Webview. It's fullscreen application. The problem is when I press Alt+F4, the application is not exit, nothing happen.
I think the Webview swallow the focus because: When I press Window key > Show start menu > press Window key again > Hide start menu > Alt + F4 > The application exit as expected.
I found that WPF WebBrowser have WebBrowserShortcutsEnabled but i can't find something like that in Windows community toolkit WebView.
Please help me to make Alt + F4 works. Thank you!
I had the same issue and solved it pragmatically by handling the WebView's AcceleratorKeyPressed event (checking for Alt+F4 and closing the window in this case).
MainWindow.xaml:
<Controls:WebView ... AcceleratorKeyPressed="WebView_AcceleratorKeyPressed"/>
MainWindow.xaml.cs:
private void WebView_AcceleratorKeyPressed(object sender, Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT.WebViewControlAcceleratorKeyPressedEventArgs e)
{
if (e.VirtualKey == Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT.VirtualKey.F4 && Keyboard.Modifiers.HasFlag(ModifierKeys.Alt))
Close();
}

AlwaysOnTop property not behaving properly

For some reason, the AlwaysOnTop attribute for a form's design isn't properly working.
Here's the context: we are trying to have a form that stays on top of every other one when opened. Simple no? Also, we don't want to set the WindowType to Popup according to my superior for some other reason (if you have any idea why, please let me know).
So my question is, is there any parameter/security feature somewhere that somehow restricts the forms to be on top at any time?
Even WinApi's setForegroundWindow returns false with the form's hWnd. Any ideas?
Oh, also we're running on Dynamics AX 4.0.
If you want your form to have modal behavior, then call the wait method from the form itself!
public void run()
{
super();
this.wait(true);
}
The true parameter triggers the modal mode. This works on all versions of AX.
The wait may be called from the caller instead, but that is less attractive as most forms are called through menu items.
formRun.init();
formRun.run();
formRun.wait(true);
I managed this case long time ago with the lostFocus event and the setFocus method. I didn't find a proper way to make a form stay on top (I think AX prevents this specifically to avoid locking a terminal) but it worked fine this way: When the form lost focus, set the focus on the form.
I don't have the code as it was on an old project. It was for a PDA project but I think you can't ever avoid user on changing form with Alt+Tab.
This is an interesting point, please keep us updated.
EDIT:
Someome in twitter got an cute solution for modal forms. I'm pretty sure it will make the trick for you. In the init method of the form:
public void run()
{
super();
element.wait(true);
// Execution will resume at this point, only after
// the user has closed the form.
}
Source: http://gotdax.blogspot.com.es/2013/08/modal-forms-in-dynamics-ax.html
What I did to solve this was by making the form modal through WinAPI. The code below is a copy from a saved text so it might need some polishing. (Also keep in mind that it might not be working as of AX2009.)
void setFormModal(int _thisHWND, boolean _bModal)
{
DLL _winApiDLL;
DLLFunction _EnabledWindow;
DLLFunction _getTop;
DLLFunction _getNext;
DLLFunction _getParent;
void local_enableWHND(int _lHWND)
{
int lnextWnd;
lnextWnd = _getTop.call(_getParent.call(_lHWND));
while (lnextWnd)
{
if (lnextWnd != _lHWND)
_enabledWindow.call(lnextWnd, (!_bModal));
lnextWnd = _getNext.call(lnextWnd, 2);
}
}
;
_winApiDLL = new DLL('user32');
_getNext = new DLLFunction(_winApiDLL, "GetWindow");
_EnabledWindow = new DLLFunction(_winApiDLL, "EnableWindow");
_getTop = new DLLFunction(_winApiDLL, "GetTopWindow");
_getParent = new DLLFunction(_winApiDLL, "GetParent");
_getParent.returns(ExtTypes:: DWORD);
_getParent.arg(ExtTypes:: DWORD);
_EnabledWindow.returns(ExtTypes:: DWORD);
_EnabledWindow.arg(ExtTypes:: DWORD, ExtTypes:: DWORD);
_getTop.returns(ExtTypes:: DWORD);
_getTop.arg(ExtTypes:: DWORD);
_getNext.returns(ExtTypes:: DWORD);
_getNext.arg(ExtTypes:: DWORD, ExtTypes:: DWORD);
local_enableWHND(_thisHWND);
local_enableWHND(_getParent.call(_thisHWND));
}

What windows messages are used by Delphi to notice changes in a combo box?

I have a Delphi application A, which I need to control from a .NET application B.
Among other things, I need to automate this process:
User selects item X from a combo box.
Application A notices the change and reacts by displaying a certain panel.
This works fine, if I do it manually.
But when the application B selects a combo box value, no panel is displayed.
This is the problem.
Potential cause of it:
When I select a combo box item, a certain windows message is fired. Some Delphi routine reacts to this message.
When I select a combo box item programmatically, the only message I send is CB_SETCURSEL and the Delphi app seems to ignore it.
Hence I assume that I can fix the problem, if I
get to know what windows messages are used as a basis for notification about combo box value changes (e. g. OnChange) and
send that windows message from C# application.
Therefore my question: What are the windows messages, on whose occurrence OnChange (and other events that notify the Delphi application on changed combo box selection) are fired?
Update 1: Started to implement the solution proposed by David Heffernan
private const int CB_SETCURSEL = 0x14E;
private const int WM_COMMAND = 0x0111;
private const int CBN_SELCHANGE = 0x001;
private const int CN_COMMAND = 0xBD11;
private int MakeWParam(int l, int h)
{
return (l & 0xFFFF) | (h << 16);
}
...
IntPtr comboBoxHandle = new IntPtr(comboBox.Current.NativeWindowHandle);
SendMessage(comboBoxHandle, CB_SETCURSEL, (Int32)myIndexInComboBox, 0);
SendMessage(comboBoxHandle, CN_COMMAND, MakeWParam(0, CBN_SELCHANGE), 0);
At the moment, it doesn't work.
Update 2:
I noticed a very strange thing.
If I invoke CB_SETCURSEL only, the desired item is selected in the combo box.
If I invoke CB_SETCURSEL and then (after 5 seconds) CN_COMMAND, then nothing is selected in the combo box.
This means - CB_SECURSEL selects the item and CN_COMMAND undoes it.
Update 3: Styles of the combo box according to Spy++:
WS_CHILDWINDOW
WS_VISIBLE
WS_CLIPSIBLINGS
00000243
Extended styles:
WS_EX_LEFT
WS_EX_LTRREADING
WS_EX_RIGHTSCROLLBAR
Class styles:
CS_VREDRAW
CS_HREDRAW
CS_DBLCLKS
Update 4: When I select the combo box item manually, I see following messages in the Spy++ output:
<00177> 0195085E S message:0xBD33 [Custom:WM_APP+15667] wParam:6801164A lParam:0195085E
<00178> 0195085E R message:0xBD33 [Custom:WM_APP+15667] lResult:4610165A
Unfortunately, I couldn't find documentation for this message.
Update 5: I noticed that the reaction to combo box selection change does occur, but only after a relatively long time (30 seconds to 1 minute). When I do the same thing manually, the reaction occurs instantaneously.
Potential cause of this behaviour: The thread of the .NET application makes the thread of the Delphi application wait for it. Note that the UI interaction code in the .NET app is executed in a separate thread (not the UI thread).
You should follow the CB_SETCURSEL message by sending the combo box a WM_COMMAND message with NotifyCode equal to CBN_SELCHANGE. It's the CBN_SELCHANGE that triggers the OnChange event.
In Delphi the code would look like this:
SendMessage(ComboHandle, CB_SETCURSEL, NewSelectionIndex, 0);
SendMessage(ComboHandle, WM_COMMAND, MakeWParam(0, CBN_SELCHANGE), ComboHandle);
Or you could use the CN_COMMAND message instead which would perhaps be a little more direct:
SendMessage(ComboHandle, CB_SETCURSEL, NewSelectionIndex, 0);
SendMessage(ComboHandle, CN_COMMAND, MakeWParam(0, CBN_SELCHANGE), 0);
You'll want to translate that into whichever .net language you are using, but I'm sure that's easy for you.
When the user selects a ComboBox item by hand, the control receives a CBN_SELCHANGE notification, which then triggers the TComboBox.OnChange event. When you select a ComboBox item programmably, no CBN_SELCHANGE notification is sent. This is documented behavior:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775821.aspx
The CBN_SELCHANGE notification code is not sent when the current selection is set using the CB_SETCURSEL message.

How to achieve modal dialogs from NotifyIcon context menu?

I've got a shell tray icon with an attached context menu. The problem I'm having is that calling ShowDialog() from a context menu Clicked handler does not result in a modal dialog.
It's easy to reproduce this with a default C# project. Simply add the following code to the Form1.cs file:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
ToolStripMenuItem contextMenuShowMsg = new System.Windows.Forms.ToolStripMenuItem();
contextMenuShowMsg.Name = "contextMenuShowMsg";
contextMenuShowMsg.Text = "Show MessageBox...";
contextMenuShowMsg.Click += new System.EventHandler(this.contextMenuShowMsg_Click);
ContextMenuStrip contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
contextMenuStrip.Items.Add(contextMenuShowMsg);
NotifyIcon notifyIcon = new NotifyIcon();
notifyIcon.Text = "DlgTest";
notifyIcon.Icon = SystemIcons.Application;
notifyIcon.Visible = true;
notifyIcon.ContextMenuStrip = contextMenuStrip;
}
private void contextMenuShowMsg_Click(object sender, EventArgs e)
{
MessageBox.Show(this, "Test MessageBox");
}
If you build and run this, you will be able to get two message boxes on the screen by simply choosing the context menu item twice. Shouldn't this be modal? Replacing this with a call to ShowDialog() for another form results in the same non-modal behavior.
My best guess is that the NotifyIcon isn't specifically tied to the Form, as it would be in a typical Windows application. But I don't see any way of doing that.
Any ideas? Thanks in advance for any help!
I would suggest doing two things before you attempt to display a modal message box:
Make your icon's owner-window visible.
Give it focus.
Once you've done that, the this in the MessageBox.Show becomes a legal "modality parent".
Heck, it even makes more sense that the message box will be displayed on top of whatever program generated it, right? That way, the user has some context for what the message box is about!
You will need to keep track of activations of your system tray menu, and disable it when a dialog is open.

WatiN: Print Dialog

I have a screen that pops up on load with a print dialog using javascript.
I've just started using WatiN to test my application. This screen is the last step of the test.
What happens is sometimes WatiN closes IE before the dialog appears, sometimes it doesn't and the window hangs around. I have ie.Close() in the test TearDown but it still gets left open if the print dialog is showing.
What I'm trying to avoid is having the orphaned IE window. I want it to close all the time.
I looked up DialogHandlers and wrote this:
var printDialogHandler = new PrintDialogHandler(PrintDialogHandler.ButtonsEnum.Cancel);
ie.DialogWatcher.Add(printDialogHandler);
And placed it before the button click that links to the page, but nothing changed.
The examples I saw had code that would do something like:
someDialogHandler.WaitUntilExists() // I might have this function name wrong...
But PrintDialogHandler has no much member.
I initially wasn't trying to test that this dialog comes up (just that the page loads and checking some values on the page) but I guess it would be more complete to wait and test for the existence of the print dialog.
Not exactly sure about your situation, but we had a problem with a popup window that also displayed a print dialog box when loaded. Our main problem was that we forgot to create a new IE instance and attach it to the popup. Here is the working code:
btnCoverSheetPrint.Click(); //Clicking this button will open a new window and a print dialog
IE iePopup = IE.AttachToIE(Find.ByUrl(new Regex(".+_CoverPage.aspx"))); //Match url ending in "_CoverPage.aspx"
WatiN.Core.DialogHandlers.PrintDialogHandler pdhPopup = new WatiN.Core.DialogHandlers.PrintDialogHandler(WatiN.Core.DialogHandlers.PrintDialogHandler.ButtonsEnum.Cancel);
using (new WatiN.Core.DialogHandlers.UseDialogOnce(iePopup.DialogWatcher, pdhPopup)) //This will use the DialogHandler once and then remove it from the DialogWatcher
{
//At this point the popup window will be open, and the print dialog will be canceled
//Use the iePopup object to manage the new window in here.
}
iePopup.Close(); // Close the popup once we are done.
This worked for me:
private void Print_N_Email(Browser ie)
{
//Print and handle dialog.
ie.Div(Find.ById("ContentMenuLeft")).Link(Find.ByText(new Regex("Print.*"))).Click();//orig
Browser ie2 = Browser.AttachTo(typeof(IE), Find.ByUrl(new Regex(".*Print.*")));
System.Threading.Thread.Sleep(1000);
PrintDialogHandler pdh = new PrintDialogHandler(PrintDialogHandler.ButtonsEnum.Cancel);
new UseDialogOnce(ie2.DialogWatcher, pdh);
ie2.Close();
}
You still might want to check your browser AutoClose property ie.AutoClose

Resources