Link to home
Start Free TrialLog in
Avatar of Shami
Shami

asked on

Property page activation

I have a modeless property sheet that I use to display properties for selected items in a tree view. Whenever the tree view selection changes, the pages in the sheet are updated. (New pages may be added and irrelevant pages may be removed)
Because of the dynamic nature of the sheet pages, sometimes an active page may be removed when the user changes the selection.
This causes the sheet to make another page active. When this happens, the sheet window is made active.
This is not what I want because the user still expects to have the focus in the tree view.
I tried to prevent the sheet window activation by handling the WM_WINDOWPOSCHANGING message but it didn't work (I added the SWP_NOACTIVATE flag).
Using Spy++ I see that the sheet gets the WM_WINDOWPOSCHANGING and WM_ACTIVATE messages.

Do you know of a way I can prevent window activation? Or is there another way to work arround tis property sheet behaviour?
Avatar of guruprasad031298
guruprasad031298

Let's say the tree control member of your tree view is m_pTreeCtrl, then after finishing the processing of updating the property sheet, just call m_pTreeCtrl->SetActiveWindow(). This should reclaim the activity back to the tree view.

Hope this helps !!!
Avatar of Shami

ASKER

I already thought of this and actually this is my workarround currently but this causes window flashes as the sheet window gets focus and then I return the focus to the view (The window title flashes).
I'm looking for a way to prevent activation of the sheet window.
Try to handle OnActivate() in your property page derived class.
void YourProertyPage::OnActivate( UINT nState, CWnd* pWnd, ... )
{
    if (WA_ACTIVE == nState )
    {
      // set focus back
      SetFocus( pWnd );
    }
    .......
}
Avatar of Shami

ASKER

Setting the focus back to the old active window will flash the window titles. This workarround is not acceptable.
You may solve the problem by preventing the property sheet window from receiving the deactivate message WM_NCACTIVATE.

Override the WM_NCACTIVATE message in you property sheet class.
Add a bool (m_bAllowNcActivate) that determines if the base-class handler for WM_NCACTIVATE should be called.

BOOL CMySheet::OnNcActivate(BOOL bActive)
{
    if(m_bAllowNcActivate)
        return CPropertySheet::OnNcActivate(bActive);
    return 0;
}

Set this bool to TRUE as default (in the constructor).

Now, when you modify the page-layout (where you have the problem) set the m_bAllowNcActivate to FALSE. before adding or removing pages and back to true after.

I tried to handle the WM_NCACTIVATE the way you offered.
Sometimes the title bar does not repaint and sometimes it does.
Anyway, this workarround still leaves me with a focus problem so I had to call SetActiveWindow for the old window, which caused the title to be repainted. I tried to handle WM_NCACTIVATE for the window that loses the focus as well, but sometimes the focus still goes to the sheet (This maybe happens after I finish changing the pages).
Avatar of Shami

ASKER

OK. If you could create a sample app and E-mail it to me it would be at lot easier for me to help you. (You can se my E-mail by clicking on piano_boxer).
Have you considered using a thread-specific Windows event hook?  Installing a CBT hook that processes HCBT_ACTIVATE and HCBT_SETFOCUS events should give you absolute control over input focus and window activation.

See "Win32 Platform SDK \ Windows Base Services \ Interprocess Communication \ Hooks" for more information.

Read the documentation for the following:
SetWindowsHookEx()
WH_CBT
CBTProc

Good luck,

Forest

Did something go wrong when you sent the answer? Why is it empty?
Avatar of Shami

ASKER

[Upon returning here, the answer I sent appears intact.  I don't know why it showed up empty for you, but here it is again.  -Forest]

Have you considered using a thread-specific Windows event hook?  Installing
a CBT hook that processes HCBT_ACTIVATE and HCBT_SETFOCUS events
should give you absolute control over input focus and window activation.

For more information, see Win32 Platform SDK: Windows Base
Services / Interprocess Communication / Hooks.

Read the documentation for the following:
SetWindowsHookEx()
WH_CBT
CBTProc

Good luck,

Forest
ASKER CERTIFIED SOLUTION
Avatar of fwilkinson
fwilkinson

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
The CBTProc documentation specify that CBTProc must be in a DLL (in the remarks section).
Do you have an idea if this is true only for global CBT hooks or for any CBTProc? (I really don't want to write a DLL because I need to monitor messages only for one thread).
Avatar of Shami

ASKER

The CBTProc doesn't have to be in a DLL if you're only going to hook your own application's messages.  If your CBTProc is in your EXE, and you want to hook the current thread, you can do something like this:

hook_handle = SetWindowsHookEx( WH_CBT, CBTProc, NULL,
        AfxGetThread()->m_nThreadID);