In a Win32 app is there a Windows message or some other notification that will get sent to a child window when it is placed into a different parent
This is easy to test in a Windows Forms app. This is what I saw:
msg=0x18 (WM_SHOWWINDOW) hwnd=0x60c60 wparam=0x1 lparam=0x0 result=0x0
msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x60c60 wparam=0x0 lparam=0x563e01c result=0x0
msg=0x85 (WM_NCPAINT) hwnd=0x60c60 wparam=0x1 lparam=0x0 result=0x0
msg=0x14 (WM_ERASEBKGND) hwnd=0x60c60 wparam=0xffffffff930119e8 lparam=0x0 result=0x0
msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x60c60 wparam=0x0 lparam=0x563e01c result=0x0
msg=0xf (WM_PAINT) hwnd=0x60c60 wparam=0x0 lparam=0x0 result=0x0
msg=0xe (WM_GETTEXTLENGTH) hwnd=0x60c60 wparam=0x0 lparam=0x0 result=0x0
msg=0xd (WM_GETTEXT) hwnd=0x60c60 wparam=0x6 lparam=0x3fd7928 result=0x0
WM_SHOWWINDOW would be a good time to check if the parent changed. Not 100% sure if this is a side effect of the WF code taking care of the changed parent, the odds are fairly high. There is otherwise no dedicated message for it, the assumption is that the program already knows since it called SetParent or SetWindowLongPtr explicitly.
There is no single notification specifically for this. However, some frameworks, like Borland's VCL, wrap windows in classes, and thus issue their own notifications when the class objects are moved around from one parent to another (for example, VCL has CM_CONTROLLISTCHANGING, CM_CONTROLLISTCHANGE, and CM_CONTROLCHANGE notifications).
Can you provide more information about what exactly you want to accomplish by detecting a change in parent window?
Sort-of... I've done this before using messaging between Windows, and a thread to listen on them. Remember, you do NOT want to modify the UI from any thread then the one that CREATED it...
Here is some example code of a Parent Window, which gets notified of a change by one of its children Windows. The same principle applies when doing what you are talking about. The parent Windows isn't really pumping messages while the child is open, (it IS, but I forget what is going through its mind at the time)... It's been 10 years since I had to do anything like this... But the code below is designed for a parent Window with a grid, and a child "Add/Edit" window that opens, and when you add or edit an item, it will update the parent GRID behind the Modal Edit window. This was designed in MFC, so you an imagine, you just need to add some HWND vars to the function calls to make it work under Win32, since Win32 and MFC are so inter-related.
First, in the parent Window, I setup a thread:
DWORD WINAPI PopulateGridThread(void *ptr)
{
CMeterReadings *pThis = (CMeterReadings*)ptr;
pThis->hGridMutex = CreateMutex(NULL, FALSE, "Wims.MeterReadingGridUpdateMutex");
WaitForSingleObject(pThis->hGridMutex, 0);
if(WaitForSingleObject(pThis->hGridMutex, 0) != WAIT_OBJECT_0) {
return -2;
}
try {
if(pThis->m_Get.GetCheck() == FALSE)
{
if(pThis->m_Grid.IsEmpty())
{
CloseHandle(pThis->hGridMutex);
CloseHandle(pThis->hThreadHandle);
pThis->hThreadHandle = INVALID_HANDLE_VALUE;
pThis->m_DateFilter.EnableWindow(pThis->m_UseDate.GetCheck());
pThis->m_UseDate.EnableWindow(TRUE);
pThis->m_MeterFilter.EnableWindow(TRUE);
return -3;
}
}
pThis->hCursor = LoadCursor(NULL, IDC_APPSTARTING);
pThis->m_Get.SetCheck(FALSE);
pThis->m_DateFilter.EnableWindow(FALSE);
pThis->m_UseDate.EnableWindow(FALSE);
pThis->m_MeterFilter.EnableWindow(FALSE);
pThis->m_Grid.PushRow();
pThis->m_Grid.ResetContent();
bool bSuccess = false;
long nId = CCommonDialog::GetItemData(pThis->m_MeterFilter);
bool bUseDate = pThis->m_UseDate.GetCheck() == TRUE;
CProDate dtFilterDate;
pThis->m_DateFilter.GetTime(dtFilterDate);
if(nId == NULLCONSTANT || nId == LB_ERR)
{
bSuccess = pThis->m_EquipmentPtr.LoadFirstMeterReading(bUseDate ? CProDate::GetDateOnly(dtFilterDate) : CProDate::NullDate(), true);
}
else
{
bSuccess = pThis->m_EquipmentPtr.LoadFirstMeterReadingByMeterId(nId, bUseDate ? CProDate::GetDateOnly(dtFilterDate) : CProDate::NullDate());
}
if(pThis->m_EquipmentPtr.GetRecordsReturned() > 5000)
{
if(ThrowQuestion("This expansion could take a long time. Do you wish to continue?", pThis) == IDNO)
{
bSuccess = false;
}
}
pThis->m_Get.SetWindowText("&Stop");
if(bSuccess)
{
pThis->m_Grid.Redraw(false);
do
{
pThis->m_Grid.AddGridRow();
pThis->m_Grid.SetCellFormat(COLUMN_ADJUSTMENT, "Yes;No");
pThis->m_Grid.SetCheck(COLUMN_ADJUSTMENT, pThis->m_EquipmentPtr.AdjustmentIndc);
pThis->m_Grid.AddDatesToGrid(pThis->m_EquipmentPtr.ReadingDate, pThis->m_EquipmentPtr.EffectiveDate);
pThis->m_Grid.AddTextToGrid(COLUMN_METER, pThis->m_EquipmentPtr.MeterDesc);
/* Cut the rest of the fields, as they aren't important... */
}
while(pThis->m_EquipmentPtr.LoadNextMeterReading());
}
pThis->m_Grid.FinishGrid();
pThis->m_Grid.Redraw(true);
pThis->m_Grid.PopRow();
pThis->m_Grid.RedrawWindow();
}
CATCH_COM_ERROR("CMeterReadings::PopulateGridThread()")
CloseHandle(pThis->hGridMutex);
CloseHandle(pThis->hThreadHandle);
pThis->hThreadHandle = INVALID_HANDLE_VALUE;
pThis->m_DateFilter.EnableWindow(pThis->m_UseDate.GetCheck());
pThis->m_UseDate.EnableWindow(TRUE);
pThis->m_MeterFilter.EnableWindow(TRUE);
pThis->hCursor = LoadCursor(NULL, IDC_ARROW);
pThis->m_Get.SetWindowText("&Get");
return 1;
}
Then, in the child Window, I would send a message back to the parent, when it was time to update. I did this by creating a thread that simply sent the message, so that the rest of the dialog would continue to function... (Or in your case, you could send a message directly to the Child Windows HWND to make it update...)
void _cdecl GridUpdateThread(void *ptr)
{
CEnterMeterReadingsDlg *pthis = (CEnterMeterReadingsDlg*)ptr;
if(pthis->NotifyParent())
{
pthis->NotifyParent()->SendMessage(CMeterReadings::GRID_UPDATE_MESSAGE, 0, 0);
}
}
Then, all this was set into motion when the user selected "NEXT" on the dialog, instead of OK, or CANCEL...
_beginthread(GridUpdateThread, NULL, this);
Well, hopefully this will help you some, or give you some ideas...
Related
How can I know that for a particular ComboBox which Dialog Style is being used? Is there any Win32 API which can give me that information?
I am using CDialog for a few ComboBox, CDialogEx for some, and an in-house Dialog class, let's say Ctl3dDialogEx, for others. GetClassName() will return the Class name of the ComboBox (if I am passing a ComboBox Handler) which can be "CComboBox".
Is there any Win32 API where I will pass the ComboBox Handler and it will return back to me the Dialog class name, for eg : "CDialog", "CDialogEx", "Ctl3dDialogEx", etc?
Below code will help to understand maybe:
void ComboBox_DoSomeManipulation( HWND hldg , int n )
{
/*"hldg" is the handler of the Current ComBobox */
LPTSTR lpClassName;
int nMaxCount = 256;
/*This will return "CComboBox" as value in lpClassName */
GetClassName(hldg , lpClassName , _count_of(nMaxCount));
/*Is there any WIN API like above which can give */
/* Dialog class information like CDialog, CDialogEx */
/* which the ComboBox is using ? */
}
If your combo-box can somehow get hold of a genuine pointer to its parent window, then you can use dynamic_cast<CDialogEx*>(pParent) to see if it's CDialogEx (returns nullptr if not). You will need several separate checks, starting from the most derived class! So, if your Ctl3dDialogEx is derived from CDialogEx, then:
. . .
CWnd *pParent = pCombo->GetParent(); // This, as is, is not valid code!
if (dynamic_cast<Ctl3dDialogEx*>(pParent) != nullptr) {
// It's a Ctl3dDialogEx parent
}
else if (dynamic_cast<CDialogEx*>(pParent) != nullptr) {
// It's a CDialogEx
}
else { // Assuming no other options …
// It's a CDialog
}
I would recommend making an accessible (static?) copy of the parent window's this pointer during initialisation, if you can. But there are other ways …
For example, assuming you have control over the definition of ComboBox_DoSomeManipulation and when it's called, change the first argument from an HWND to a CWnd* and, when you call it, use this rather than this->m_hwnd. (But this depends on the structure of your code!)
There is no Windows API help since all those dialogs will be subclassing the Windows DIALOG class. If this is all in process, and you are using the same MFC instance, you might be able to do this:
CWnd* pWnd = CWnd::FromHandlePermanent(hdlg);
if (pWnd != NULL)
{
if (pWnd->GetRuntimeClass() == RUNTIME_CLASS(CDialog))
{
}
else if (pWnd->GetRuntimeClass() == RUNTIME_CLASS(CDialogEx))
{
}
else if (pWnd->GetRuntimeClass() == RUNTIME_CLASS(CDialogxyz))
{
}
}
Back in the old days, MS compilers used with MFC didn't play well with dynamic_cast<>, so generally, when using MFC, I don't use it. I probably should have more trust in it, but I was stuck using Visual C++ 6 until 2008, so I am probably a little jaded. The more "standard" "MFC way" is to use the MFC macros...
Another possible ways is something like:
if (CDialogxyz* pDlgxyz = DYNAMIC_DOWNCAST(CDialogxyz, pWnd))
{
}
else if (CDialogEx* pDlgEx = DYNAMIC_DOWNCAST(CDialogEx, pWnd))
{
}
else if (CDialog* pDlg = DYNAMIC_DOWNCAST(CDialog, pWnd))
{
}
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
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.
I'm using CGEventTapCreate to "steal" media keys from iTunes when my app is running. The code inside of the callback that I pass to CGEventTapCreate examines the event, and if it finds that it's one of the media keys, posts an appropriate notification to the default notification center.
Now, this works fine if I post a notification for the "key up" event. If I do that for "key down" events, eventually my app stops getting media key events and iTunes takes over. Any ideas on what can be causing this? The relevant part of the code is below
enum {
...
PlayPauseKeyDown = 0x100A00,
PlayPauseKeyUp = 0x100B00,
...
};
static CGEventRef event_tap_callback(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void *refcon)
{
if (!(type == NX_SYSDEFINED) || (type == NX_KEYUP) || (type == NX_KEYDOWN))
return event;
NSEvent* keyEvent = [NSEvent eventWithCGEvent: event];
if (keyEvent.type != NSSystemDefined) return event;
switch(keyEvent.data1)
{
case PlayPauseKeyUp: // <--- this works reliably
//case PlayPauseKeyDown: // <--- this will break eventually
post_notification(#"PlayPauseMediaKeyPressed", nil, nil);
return NULL;
... and so on ...
Does something kill my event tap if the callback takes too long?
Some people suspect that Snow Leopard has a bug that sometimes disables event taps even if they don't take too long. To handle that, you can watch for the event type kCGEventTapDisabledByTimeout, and respond by re-enabling your tap with CGEventTapEnable.
First of all, why is your first "if" allowing key-down and key-up events to pass? Your second "if" only lets system events pass through anyway. So for all key-down/-up events you create a NSEvent, just to drop the event one line further downwards. That makes little sense. An Event Tap should always be as fast as possible, otherwise it will slow down all event processing of the whole system. Your callback should not even be called for key-down/-up events, since system events are not key-down/-up events, they are system events. If they were key events, you would for sure never access data1, but instead use the "type" and "keyCode" methods to get the relevant information from them.
static CGEventRef event_tap_callback(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void *refcon)
{
NSEvent * sysEvent;
// No event we care for? return ASAP
if (type != NX_SYSDEFINED) return event;
sysEvent = [NSEvent eventWithCGEvent:event];
// No need to test event type, we know it is NSSystemDefined,
// becuase that is the same as NX_SYSDEFINED
Also you cannot determine if that is the right kind of event by just looking at the data, you must also verify the subtype, that must be 8 for this kind of event:
if ([sysEvent subtype] != 8) return event;
The next logical step is to split the data up into its components:
int data = [sysEvent data1];
int keyCode = (data & 0xFFFF0000) >> 16;
int keyFlags = (data & 0xFFFF);
int keyState = (keyFlags & 0xFF00) >> 8;
BOOL keyIsRepeat = (keyFlags & 0x1) > 0;
And you probably don't care for repeating key events (that is when I keep the key pressed and it keeps sending the same event over and over again).
// You probably won't care for repeating events
if (keyIsRepeat) return event;
Finally you should not define any own constant, the system has ready to use constants for those keys:
// Analyze the key
switch (keyCode) {
case NX_KEYTYPE_PLAY:
// Play/Pause key
if (keyState == 0x0A) {
// Key down
// ...do your stuff here...
return NULL;
} else if (keyState == 0x0B) {
// Key Up
// ...do your stuff here...
return NULL;
}
// If neither down nor up, we don't know
// what it is and better ignore it
break;
case NX_KEYTYPE_FAST:
// (Fast) Forward
break;
case NX_KEYTYPE_REWIND:
// Rewind key
break;
}
// If we get here, we have not handled
// the event and want system to handle it
return event;
}
And if this still not works, my next question would be what your post_notification function looks like and do you also see the described problem if you don't call post_notification there, but just make a NSLog call about the event you just saw?
In your handler, check for the following type, and just re-enable the listener.
if (type == kCGEventTapDisabledByTimeout) {
NSLog(#"Event Taps Disabled! Re-enabling");
CGEventTapEnable(eventTap, true);
return event;
}