Is there a function like PeekMessage that doesn't process messages? - windows

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 )
}
}
}
}

Related

Not receiving messages after sometime

I am using JNA to access User32 functions (I dont think it has got to do with Java here, more of concept problem). In my application, I have a Java process which communicates with the Canon SDK. To dispatch any messages I am using the below function:
private void peekMessage(WinUser.MSG msg) throws InterruptedException {
int hasMessage = lib.GetMessage(msg, null, 0, 0);
if (hasMessage != 0) {
lib.TranslateMessage(msg);
lib.DispatchMessage(msg);
}
Thread.sleep(1);
}
peekMessage is called in a loop and it all works well. Whenever an Image is taken from camera, I get the event and do the rest.
But I have observed, say after about 15 seconds (sometimes never or sometimes just at start) of no activity with camera, taking picture does not give me any download event. Later the whole application becomes unusable as it doesn't get any events from camera.
What can be the reason for this? Please let me know of any other info needed, I can paste the respective code along.
Edit:
Initialization:
Map<String, Integer> options = new HashMap<String, Integer>();
lib = User32.INSTANCE;
hMod = Kernel32.INSTANCE.GetModuleHandle("");
options.put(Library.OPTION_CALLING_CONVENTION, StdCallLibrary.STDCALL_CONVENTION);
this.EDSDK = (EdSdkLibrary) Native.loadLibrary("EDSDK/dll/EDSDK.dll", EdSdkLibrary.class, options);
private void runNow() throws InterruptedException {
while (!Thread.currentThread().isInterrupted()) {
Task task = queue.poll();
if (task != null) {
int taskResult = task.call();
switch (taskResult) {
case (Task.INITIALIZE_STATE):
break;
case (Task.PROCESS_STATE):
break;
case (Task.TERMINATE_STATE): {
//queue.add(new InitializeTask());
Thread.currentThread().interrupt();
break;
}
default:
;
}
}
getOSEvents();
}
}
WinUser.MSG msg = new WinUser.MSG();
private void getOSEvents() throws InterruptedException {
if (isMac) {
receiveEvents();
} else {
peekMessage(msg);
}
}
Above, whenever I get my camera event, it add's it to the queue and in each loop I check the queue to process any Task. One more important information: This is a process running on cmd and has no window. I just need the events from my camera and nothing else.
The code where I register callback functions:
/**
* Adds handlers.
*/
private void addHandlers() {
EdSdkLibrary.EdsVoid context = new EdSdkLibrary.EdsVoid(new Pointer(0));
int result = EDSDK.EdsSetObjectEventHandler(edsCamera, new NativeLong(EdSdkLibrary.kEdsObjectEvent_All), new ObjectEventHandler(), context).intValue();
//above ObjectEventHandler contains a function "apply" which is set as callback function
context = new EdSdkLibrary.EdsVoid(new Pointer(0));
result = EDSDK.EdsSetCameraStateEventHandler(edsCamera, new NativeLong(EdSdkLibrary.kEdsStateEvent_All), new StateEventHandler(), context).intValue();
//above StateEventHandler contains a function "apply" which is set as callback function
context = new EdSdkLibrary.EdsVoid(new Pointer(0));
result = EDSDK.EdsSetPropertyEventHandler(edsCamera, new NativeLong(EdSdkLibrary.kEdsStateEvent_All), new PropertyEventHandler(), context).intValue();
//above PropertyEventHandler contains a function "apply" which is set as callback function
}
You are getting ALL messages from ALL windows that belong to this thread, that includes all mouse moves, paints etc. if you aren't rapidly calling this function your message queue will overflow and cause the behavior you describe.
The sleep you definitely don't want as GetMessage yields if no message is waiting.
So if there exists a normal message pump(s) (i.e GetMessage/DispatchMessage) loop somewhere else for this threads window(s) then you should let that pump do most of the work, perhaps use wMsgFilterMin, wMsgFilterMax to just get the event message you require; or even better in this case use peekmessage with PM_NOREMOVE (then you will need your sleep
call as peekmessage returns immediately).
Alternatively provide the hWnd of the window that generates the event to reduce the workload.
Use spy++ to look into which windows this thread owns and what messages are being produced.
To take this answer further please provide answers to: what else is this thread doing and what windows does it own; also is this message pump the only one or do you call into the SDK API where it may be pumping messages too?
There is an OpenSource project wrapping EDSDK with JNA and it has a version of your code that is probably working better:
https://github.com/kritzikratzi/edsdk4j/blob/master/src/edsdk/api/CanonCamera.java#L436
Unfortunately this is not platform independent and specifically the way things work on windows. I am currently in the process of trying to get a MacOS version of things working at:
https://github.com/WolfgangFahl/edsdk4j

(MFC) How can a parent class receive a control's messages if the control is a private member?

Let's say my main class has a private member that is a class derived from a CTreeView control. How can I handle the messages from this tree view control on the main class itself?
This is similar to the MDI base application that Visual Studios builds for you, where you have two dockable tree view controls named CClassView and CFileView and each has a private member that's derived from CTreeView.
Can I pass the message from the child member control CViewTree to my CFileView class with like this?
void CViewTree::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
GetParent()->SendMessage(WM_NOTIFY, 0, (LPARAM)pNMHDR);
}
This code throws an exception, but if this does work, how would I handle the TVN_SELCHANGED message in the parent class?
Edit:
So I've tried the following suggestions but haven't had much luck with either one.
//First try, in the parent .h file:
afx_msg BOOL OnSelChange(NMHDR *pNMHDR, LRESULT *pResult);
//In the .cpp file:
ON_NOTIFY_REFLECT_EX(TVN_SELCHANGED, OnSelChange)
//and
BOOL ParentClass::OnSelChange(NMHDR *pNMHDR, LRESULT *pResult)
{
AfxMessageBox(L"in handler");
Return TRUE;
}
Second try:
//in the parent .h file:
afx_msg void OnSelChange(NMHDR *pNMHDR, LRESULT *pResult);
//In the .cpp file:
ON_NOTIFY(TVN_SELCHANGED, AFX_IDW_PANE_FIRST, OnSelChange)
//and
void ParentClass::OnSelChange(NMHDR *pNMHDR, LRESULT *pResult)
{
AfxMessageBox(L"in handler");
}
Not sure why you want to do this, you have less code reusability as you have a tight coupling between the view and the parent. If you want to reuse the selection logic, you can extract it out into a separate class like the DRAWCLI sample does.
TVN_SELCHANGED is already sent to the parent. However MFC's message reflection routes the notification to the child window's message map when ON_NOTIFY_REFLECT is present in the child.
If you want the parent to have a say in the message processing as well, you can change ON_NOTIFY_REFLECT to ON_NOTIFY_REFLECT_EX and return FALSE in the reflected message handler.
You will get a WM_NOTIFY at the parent so the way you handle the notification is to add a ON_NOTIFY macro to the parent of the tree view like you normally do for a tree control on a dialog. The view's id is likely AFX_IDW_PANE_FIRST if you haven't specified one.
Sheng was able to figure out my problem, which looking back now was quite trivial. Maybe this will help others who might have the same question.
In the MDI w/ visual studio style program that I generated from Visual Studio 2010, the CFileView has a child member instance of CViewTree. CViewTree was derived from CTreeCtrl.
By default, MFC is already passing the messages up the child-to-parent chain. The answer is determining the control ID to get notification messages from in your parent class.
So, first things first, we need to know the ID of the tree control. In the OnCreate method of CFileView, you can see this code:
if (!m_wndFileView.Create(dwViewStyle, rectDummy, this, 4))
MSDN has the following for the Create method:
virtual BOOL Create(
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID
);
In my example, the id is 4. Now in the parent (CFileView in this case), just create your ON_NOTIFY macro as such:
BEGIN_MESSAGE_MAP(CFileView, CDockablePane) //precreated for you
ON_NOTIFY(TVN_SELCHANGED, 4, OnSelChanged) //you create this
END_MESSAGE_MAP() //precreated for you
I had to type the line above by hand because the class wizard or message property for the parent didn't have a =TVN_SELCHANGED message. Next, make sure your handler method OnSelChanged is declared in the CFileView.h file as:
afx_msg void OnSelChanged(NMHDR *pNMHDR, LRESULT *pResult);
Now I'm able to handle the TVN_SELCHANGED message like this (back in the CFileView.cpp):
void CFileView::OnSelChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
HTREEITEM item = m_wndFileView.GetSelectedItem();
AfxMessageBox(m_wndFileView.GetItemText(item));
}
In the described case if you want to notify parent CFileView from control CViewTree with WM_NOTIFY TVN_SELCHANGED message, you should do it in virtual OnNotify function, not using message map. If OnNotify doesn't met correct handler, message would go to parent CMainFrame, and there you can use message map.
BOOL CFileView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
if (nmHdr->idFrom != 4)
return CDockablePane::OnNotify(wParam, lParam, pResult);
if (nmHdr->code == TVN_SELCHANGED)
{
OnItemsSelChanged((NMHDR*)lParam, pResult);
return TRUE;
}
return FALSE;
}

How to pass window handle to wndproc?

I have written this code in c# application for tracking messages ...
protected override void WndProc(ref Message m)
{
// Listen for operating system messages.
switch (m.Msg)
{
case WM_CHAR:
FileStream fs = new FileStream("d:/Type.txt",FileMode.Append,FileAccess.Write);
//set up a streamwriter for adding text
StreamWriter sw = new StreamWriter(fs);
sw.BaseStream.Seek(0, SeekOrigin.End);
int no=(int)m.WParam;
sw.Write(Convert.ToChar(no));
sw.Flush();
sw.Close();
break;
}
base.WndProc(ref m);
}
I want to track messages for different window so how can I pass different window handle to wndproc ? please help me...
You'd have to register global keyboard hook instead of passing different handle. This article shows how to do that. Basic idea behind that is that you register your function for polling all keyboard-related system events (for every message) and filter out only those you need.
The functionality is achieved with SetWindowsHookEx winapi function.
You can filter all the messages in the application by calling Application.AddMessageFilter(IMessageFilter filter) at the beginning of your program.
The IMessageFilter interface has just one method:
bool PreFilterMessage(ref Message m);
That is called for every message handled by the application. There you can use m.HWnd to identify the different windows of your program.

Callback using CustomWndProc for Message Only Window Handle

I am developing a NPAPI plugin using firebreath. I am using a third party dll to integrate to a gaming device.The inputs on the devices are propagated to the plugin through a message only window(HWND) registered while opening a channel to the device.
Initially, handshake with the device driver,
handshake(HWND,...) and after which on user input, a callback is made on CustomWinProc() to notify.
I did the following,
-Created an Header&CPP file under the WIN-CustomCallbackHandler.h ,
#include "Win\PluginWindowWin.h"
#include "Win\WindowContextWin.h"
class CustomCallbackHandler : public FB::PluginWindowWin
{
public:
CustomCallbackHandler (const FB::WindowContextWin& ctx);
protected:
virtual bool CustomWinProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM
lParamm,LRESULT & lRes);
};
-CustomCallbackHandler.cpp
[code]
#include "CustomCallbackHandler.h"
#include "PluginWindowForwardDecl.h"
#include "Win\WindowContextWin.h"
#include "Win\PluginWindowWin.h"
CustomCallbackHandler::CustomCallbackHandler(const FB::WindowContextWin& ctx) :
FB::PluginWindowWin(ctx){
}
bool CustomCallbackHandler::CustomWinProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM
lParamm,LRESULT & lRes){
//if WPARAM is something some operation has to be performed.
return false;
}
[/code]
-Factory.cpp - Added the following method to override the PluginWindowWin
FB::PluginWindowWin* createPluginWindowWin(const FB::WindowContextWin& ctx)
{
return new CustomCallbackHandler(ctx);
}
-MyFirstPluginAPI.cpp-(The auto generated JSAPIAuto subclass)- JS method.
bool MyFirstPluginAPI::handshake(FB::JSObjectPtr &callback)
{
FB::WinMessageWindow window;
thirdpartymethod(window.getHWND());
}
Now,When I debug I could see the customcallbackhandler being invoked a couple of times for the regular plugin events but the events generated by the devices are not available.I believe a different instance of message window is passed on to the dll.
-How do I get the handle of the PluginWindowWin?
-Once I receive a callback on the CustomCallbackHandler,How do I generate a custom sendEvent()?
Your help is highly appreciated.
I am a Java developer and don't have much experience in C++ programming. I believe I am missing something fundamental.
What you want is to use WinMessageWindow:
https://github.com/firebreath/FireBreath/blob/master/src/PluginCore/Win/WinMessageWindow.h
You don't want to use PluginWindowWin; that's too specific for other things. WinMessageWindow was created specifically to do the types of things you are trying to do, and it allows you to make a winproc handler on the containing class.
I recently posted an example of using WinMessageWindow in order to receive WM_DEVICENOTIFY messages; I'm sure you can use it as an example of how the class works to get you started.

Using WM_SHOWWINDOW to Show a Window instead of ShowWindow()

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);
}
}
}

Resources