I’m trying to use the SendMessage function of a hotkey utility (or NirCMD, etc.) to get a hidden window to pop up. I can for example get windows to close by sending 0x0010 (WM_CLOSE), but when I try sending 0x0018 (WM_SHOWWINDOW) with a wParam of 1 and an lParam of 0, nothing happens.
I’ve looked around, and the few places where someone complained that WM_SHOWWINDOW did not work, they happily took the suggestion to use ShowWindow() instead.
However I don’t have ShowWindow() available; I can only send Windows messages. But ShowWindow() is not magic, surely it works by SendMessage-ing a WM_SHOWWINDOW or something under the covers.
How can I get a window to display itself by sending it a message?
Thanks.
Try these two messages:
SendMessage(h,WM_SYSCOMMAND,SC_MINIMIZE,0);
SendMessage(h,WM_SYSCOMMAND,SC_RESTORE,0);
Or if using 3rd party apps is ok, try cmdow
WM_SHOWWINDOW is a notification, not a command. From MSDN:
The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown.
I don't believe there is any message that you can use to make a window show itself. Actually, the very idea seems a little strange to me. The window manager is the system component responsible for showing and hiding windows. To show a window, you must use one of the window manager APIs.
I think there is no way to achieve that with SendMessage (WM_SYSCOMMAND didn't work for me). I tried actually in C#. You click the button, the window will be minimized via ShowWindow() and then you can see what messages are sent:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class Form1: Form
{
[DllImport("user32.dll", SetLastError = true)]
public static extern bool ShowWindow(IntPtr window, int showCommand);
private const int SW_MINIMIZE = 6;
private bool print = false;
public Form1()
{
Button button = new Button();
button.Click += onButtonsClick;
Controls.Add(button);
}
private void onButtonsClick(object sender, EventArgs e)
{
print = true;
ShowWindow(Handle, SW_MINIMIZE);
print = false;
}
protected override void WndProc(ref Message m)
{
if (print)
Console.WriteLine(m.Msg.ToString() + "\t0x" + m.Msg.ToString("x4") + "\t" + m.WParam + "\t" + m.LParam);
base.WndProc(ref m);
}
}
}
Related
The MS documentation (and others) "clearly" states:
... Because the normal OnOk and OnCancel member functions of a CDialog
object would call EndDialog, make sure your modeless dialog box does
not call those functions and instead overrides
Since CDialog::OnOk effectively calls CDialog::EndDialog, and that method looks like:
void CDialog::EndDialog(int nResult)
{
ASSERT(::IsWindow(m_hWnd));
if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL))
EndModalLoop(nResult);
::EndDialog(m_hWnd, nResult);
}
we can also check the docs for ::EndDialog which again "clearly" state:
Dialog boxes created by the DialogBox, DialogBoxParam,
DialogBoxIndirect, and DialogBoxIndirectParam functions must be
destroyed using the EndDialog function. An application calls EndDialog
from within the dialog box procedure; the function must not be used
for any other purpose.
Yet, I have a CDialog derived class that has it's default behavior wrt. OnOKand seemingly everything is working when I use it non-modal / modeless.
That is:
* When I close the (modeless) dialog, it is closed/removed from view.
* The application doesn't show any memory leaks. (MFC debug build)
So what? Do I need to prevent EndDialog and call DestroyWindow myself or not?
Note: I know what the docs and "the web" says. It's just that I haven't yet found why I need to do it differently, and this one class should be usable for modeless and modal mode, so not having to do anything different might be handy.
The MSDN Docs for CDialog::OnOK clearly states
If you implement the OK button in a modeless dialog box, you must
override the OnOK method and call DestroyWindow inside it. Do not call
the base-class method, because it calls EndDialog which makes the
dialog box invisible but does not destroy it
So you would need to override CDialog::OnOK and call DestroyWindow() inside -- here's a modified example from MSDN:
class CDlg : public CDialog
{
...
BOOL m_bModal;
...
}
CDlg::CDlg(CWnd* pParent /*=NULL*/)
: CDialog(CDlg::IDD, pParent)
{
...
m_bModal = FALSE;
...
}
INT_PTR CDlg::DoModal()
{ m_bModal = TRUE;
const INT_PTR rval = CDialog::DoModal();
m_bModal = FALSE;
return rval;
}
void CDlg::OnOK()
{
if (!UpdateData(TRUE))
{
TRACE(_T("UpdateData failed during dialog termination\n"));
// The UpdateData routine will set focus to correct item
return;
}
if (m_bModal)
EndDialog(IDOK);
else
DestroyWindow();
}
void CDlg::OnCancel()
{
if (m_bModal)
EndDialog(IDCANCEL);
else
DestroyWindow();
}
I have written an MFC dialog based application which is launched by some another application. For now, I have not added any code. It is just the default files that I got. The other application can successfully launch my application.
I am trying to hide the window of my application when the other application launches it.
BOOL CMyApp::InitInstance()
{
CMyAppDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
}
else if (nResponse == IDCANCEL)
{
}
return FALSE;
}
I tried to use:
dlg.ShowWindow(SW_HIDE)
but it still does not hide the window.
How can I accomplish this task?
I'd suggest you have another problem someplace.
If you create a totally new, blank MFC app (Visual Studio 2010) then in App::InitInstance, setting SW_HIDE rather than SW_SHOW does cause the resultant window to be hidden.
BOOL CProj1App::InitInstance()
{
// boilerplate code
. . .
// The one and only window has been initialized, so show and update it
m_pMainWnd->ShowWindow(SW_HIDE); // WORKS!
m_pMainWnd->UpdateWindow();
return TRUE;
}
As soon as you call DoModal your dialog is doomed to be shown. There is only one workaround that successfully avoids focus/flicker problems. See my answer here: Hiding an MFC dialog box
Hence, your code should look like this:
BOOL CMyApp::InitInstance()
{
CMyAppDlg dlg;
dlg.SetVisible(FALSE); // Sets m_visible flag to FALSE.
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
}
else if (nResponse == IDCANCEL)
{
}
return FALSE;
}
Solution to the above issue. The InitInstance code should be as follows:
BOOL CMyApp::InitInstance()
{
CWinApp::InitInstance();
AfxEnableControlContainer();
CMyAppDlg dlg;
dlg.Create(IDD_MyAppUI_DIALOG,NULL);
dlg.ShowWindow(SW_HIDE);
dlg.UpdateWindow();
m_pMainWnd = &dlg;
return TRUE;
}
First of all let me address some issues with previous solutions.
chintan s:
Indeed dialog will be killed when function goes out of scope. It would be a valid solution if dialog was declared as a member variable of the app class.
Vikky:
No need to call Windows API, since dialog is derived from CWnd and it inherits ShowWindow member that take only one parameter: show command.
ixe013:
This solution will work, however, before dialog hides, it will flash, since ShowWindow is called before OnInitDialog is called.
Pete:
This won’t work, since, modal dialog starts before m_pMainWnd has any value assigned to it.
The solution is pointed by ixe013.
This is so far the only solution that works but you will have to declare member variable in you dialog class, as described in the article.
You must hide the dialog from the inside.
Overload OnInitDialog
Call CDialogEx::OnInitDialog()
Hide your window and return
Here is the code
BOOL CMyAppDlg::OnInitDialog()
{
BOOL result = CDialogEx::OnInitDialog();
this->ShowWindow(SW_HIDE);
return result; // return TRUE unless you set the focus to a control
}
There is another method with a sentinel value, YMMV.
The showWindow method has 2 variable.
handle of window
nCmdShow(Controls how the window is to be shown)
BOOL WINAPI ShowWindow(
In HWND hWnd,
In int nCmdShow
);
HWND hWnd = GetSafeHwnd();
ShowWindow(hWnd,SW_HIDE);
See HERE
I use MessageBox function in Win32 console application.
Application does not not use MFC, not even event loop.
I need to make a wrapper, MessageBoxTimed(), that exits
(and dialog box disappears) after N seconds, if user did not press any button.
Is there more or less simple way to do this ?
This will not be trivial. Since the MessageBox() function itself is modal, you will likely need to start another thread that waits for the predefined number of seconds, and is interrupt-able if the message box is dismissed manually.
If the timer expires, use the FindWindow() API to find the handle of the message box and then simulate a click of the OK button, or perhaps more appropriately a keypress of the ESC button.
EDIT: Actually, not too bad. This isn't fully tested, may need some additional cleanup, but is enough to get you started.
#include <Windows.h>
class TimedMB
{
public:
TimedMB() : timeout_(0), caption_(0)
{
interrupt_ = CreateEvent(NULL, FALSE, FALSE, NULL);
}
~TimedMB()
{
CloseHandle(interrupt_);
}
static DWORD WINAPI timer(LPVOID param)
{
TimedMB* mb = reinterpret_cast<TimedMB*>(param);
if(WAIT_TIMEOUT == WaitForSingleObject(mb->interrupt_, mb->timeout_))
{
HWND message_box = FindWindow(NULL, mb->caption_);
if(::IsWindow(message_box))
{
PostMessage(message_box, WM_COMMAND, IDCANCEL, 0);
}
}
return 0;
}
void DisplayMessageBox(const char* msg, const char* caption, DWORD timeout)
{
timeout_ = timeout;
caption_ = caption;
CreateThread(NULL, 0, &TimedMB::timer, this, 0, NULL);
::MessageBox(NULL, msg, caption, MB_OKCANCEL);
::SetEvent(interrupt_);
}
private:
HANDLE interrupt_;
DWORD timeout_;
const char* caption_;
};
int main()
{
TimedMB mb;
mb.DisplayMessageBox("Hello There!", "My Message Box", 5000);
}
If you need to dismiss it automatically, I'd avoid using MessageBox at all. Instead, I'd just put together a dialog that closes itself after the specified period of time. If memory serves, you can do this pretty easily by setting a time when you display the pseudo-message box dialog. When the time goes off or the user clicks "ok" (or "close", etc.) you close the window and cancel the timer.
Don't do this. Modal dialogs should be closed by user intervention. Deviating from this pattern is just confusing and non-standard. If you want a message windows that closes itself, then use a balloon window.
If I show a MessageBox as modal of a window on another process, it works just fine as long as my program remains responding. If it is closed or terminated while the MessageBox is showing the windows that received the MessageBox will be locked (but still responding) and it will have to be finalized via Task Manager.
Here is a sample code to demonstrate that:
using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
namespace TestMessageBox
{
class Program
{
private WindowWrapper notepad;
Program(IntPtr handle)
{
notepad = new WindowWrapper(handle);
}
static void Main(string[] args)
{
Process[] procs = Process.GetProcessesByName("notepad");
if (procs.Length > 0)
{
Console.WriteLine("Notepad detected...");
Program program = new Program(procs[0].MainWindowHandle);
Thread thread = new Thread(new ThreadStart(program.ShowMessage));
thread.IsBackground = true;
thread.Start();
Console.Write("Press any key to end the program and lock notepad...");
Console.ReadKey();
}
}
void ShowMessage()
{
MessageBox.Show(notepad, "If this is open when the program ends\nit will lock up notepad...");
}
}
/// <summary>
/// Wrapper class so that we can return an IWin32Window given a hwnd
/// </summary>
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get { return _hwnd; }
}
private IntPtr _hwnd;
}
}
How to avoid that?
The act of showing a modal dialog disables the parent window of the dialog (Notepad's window in your example). When the modal dialog is closed, the parent window gets re-enabled.
If your program dies before it re-enables the window, that window will never get re-enabled - it's up to the thread that's showing the dialog to re-enable the parent. (In your example, it happens within MessageBox.Show(), after the user clicks OK or whatever.)
The only way to make this work would be to have a second process whose responsibility it was to put things back as they should be if the process creating the modal dialog dies prematurely, but that's horrible. And it's still not bulletproof - what if the watcher process dies too?
I'm trying to innocently call
PeekMessage(&msg, 0, WM_KEYDOWN, WM_KEYUP, PM_NOREMOVE | PM_NOYIELD);
and Windows Vista 64, in the PeekMessage call, is processing messages. The result is that I'm going re-entrant on my paint call, and all sorts of other code.
Painting can take seconds in our application, so we added the PeekMessage call to see if the user hit a key, so we could interrupt that painting and start up the next one. Little did we realize that Windows could start processing messages on us. It'd be a major refactoring to put the real work of painting in a separate thread... We're trying to see if specific keys were pressed, or if the mouse wheel rotated or mouse buttons were clicked, to interrupt rendering.
I've tried adding code specifically to prevent re-entrancy, and then re-injecting paint messages into the queue, etc. It's all very kludgey, and there are cases where it doesn't work well.
Is there some flag I could add to the PeekMessage call? I didn't see anything new in the documentation on MSDN. I really need a PeekMessage that doesn't process messages. Help!
Perhaps I'm missing the obvious, but the spec is pretty verbose that it will do so:
The PeekMessage function dispatches
incoming sent messages, checks the
thread message queue for a posted
message, and retrieves the message (if
any exist).
...
During this call, the system delivers
pending, nonqueued messages, that is,
messages sent to windows owned by the
calling thread using the SendMessage,
SendMessageCallback,
SendMessageTimeout, or
SendNotifyMessage function. Then the
first queued message that matches the
specified filter is retrieved. The
system may also process internal
events. If no filter is specified,
messages are processed in the
following order:
Sent messages
Posted messages
Input (hardware) messages and system internal events
Sent messages (again)
WM_PAINT messages
WM_TIMER messages
To retrieve input messages before
posted messages, use the wMsgFilterMin
and wMsgFilterMax parameters.
GetQueueStatus is the fastest way to check if there are available messages. It will only check a few flags and takes only 1 parameter compared to 5 parameters of peekmessage. It will give a quick hint if there are available messages, it will not process the message in any way.
GetQueueStatus and GetInputStatus are related functions.
I think this is what PeekMessage is supposed to do. The only difference between it and GetMessage is that GetMessage blocks until a message arrives, where as PeekMessage will return TRUE or FALSE depending on whether a message matching the filter was found. It will still process the messages if they are found.
PeekMessage processes messages because that's what PeekMessage does.
Maybe it's badly named, but PeekMessage do remove the message from the queue if there are any available.
Just modified the PM_REMOVE flag for the PM_NOREMOVE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PROJECT_NAME
{
class cUtil
{
//===============================
cUtil()
{
}
//================================
~cUtil()
{
}
//=================================
public struct Message
{
public IntPtr handle;
public uint msg;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public System.Drawing.Point p;
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool PeekMessage(out Message lpMsg, Int32 hwnd, Int32 wMsgFilterMin, Int32 wMsgFilterMax, uint wRemoveMsg);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool TranslateMessage(out Message lpMsg); //(ref Message lpMsg);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern Int32 DispatchMessage(out Message lpMsg); //(ref Message lpMsg);
//private static uint PM_NOREMOVE = 0x0000;
private static uint PM_REMOVE = 0x0001;
//private static uint PM_NOYIELD = 0x0002;
public static void Peek()
{
Message winMsg;
while (PeekMessage(out winMsg, (Int32)0, (Int32)0, (Int32)0, PM_REMOVE))
{
TranslateMessage(out winMsg);
DispatchMessage(out winMsg);
}
}
}
}
//================================
//================================
//===============================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace PROJECT_NAME
{
public partial class foNAME : Form
{
//===================================
public foRAMQ()
{
InitializeComponent();
}
//===================================
private void Job()
{
int cnt = 0;
while( reading_DBMS() )
{
cUtil.Peek();
.
.
.
.
.
cnt++;
lable_count.Text = string.Format("Count: {0}", cnt )
}
}
}
}