|
Hi --
I just built the Docking Demo project in Visual Studio 2005 Beta 2 (it built fine, except that the build environment did insist on substituting its own embedded Manifest and made me comment out the line in the RC file that references the manifest). The initial frame comes up fine, menu functionality seems to work fine, I can switch among the tabs in the TestDialog tabbed window at the bottom of the frame, I can even pin and unpin it, but as soon as I try to move this tabbed child I get the following message:
Debug Assertion Failed!
Program c:\wtl7.5\TabbingFramework\DockingDemo\Debug\DockingDemo.exe
File: c:\wtl7.5\tabbingframework\include\sergey klimov\wndfrmpkg.h
Line:781
Expression: m_ptr.get()!=0
I can certainly try to troubleshoot this, but as I haven't been doing WTL for about a year and a half now, I'm sure you could figure it out much quicker than I. Any insights? Or can you at least direct me to where this hwnd should be being set so that I can have half a chance at figuring it out?
Any help would be greatly appreciated. Much obliged!
Regards,
Mike
|
|
|
|
|
Hi Daniel --
I can give a little bit more insight into this problem. It apparently happens as a result of an empty ptr inside of an autoptr in the context of distance calculations with the m_separators collection in some ssection object. I see that CFrames in Serge's CWndFramesPackageBase class is a typedef for one of these section objects, so I'm imagining something is missing from the setup of frames in your demo. Beyond that, it's just too difficult for me at this point to understand what's going on, but maybe this clue will give you some insight. The package looks fantastic so I really want to get beyond this so I can use it in an app.
Regards,
Mike
|
|
|
|
|
Compile the DockingDemo project in Release version in VS.NET2002, and run the Release version from VS.NET2002 by pressing F5, then exit the application by clicking the Close button, the following exception happens:
HEAP[DockingDemo.exe]: Invalid Address specified to RtlFreeHeap( 00B50000, 00170C10 )
Unhandled exception at 0x7c901230 in DockingDemo.exe: User breakpoint.
what's the meaning of this exception? Is it harmful?
|
|
|
|
|
Interesting. I tried it out under VS.NET 2002 like you mention, and I see what you're talking about. It looks like its crashing in CSimpleArray::RemoveAll while doing
pWinModule->m_rgWindowClassAtoms.RemoveAll(); in
AtlWinModuleTerm .
I did the same test under VS.NET 2003, and this problem did not happen. Perhaps the problem in VS.NET 2002 is due to an ATL bug that was fixed for VS.NET 2003.
-Daniel
|
|
|
|
|
it looked great...the tabbed style is awesome...
my coding knowledge and experience is not enough to say anything about the coding.
I just want to suggest something:
with this interface you can easily adapt tabbed-browsing capability of the Firefox for IE Explorer. it's great. add an addressline, a couple of buttons...(and lots of coding )
thanks for sharing your knowledge.
Evren
"Try Not! Do. Or Do Not. There is no Try..." Master Yoda
|
|
|
|
|
That's completely off-topic, but there's a lot of tools for tabbed IE-ish browsing:
Maxthon (formerly MyIE2)
Avant browser
FastBrowser
etc.
For the article, I definitely gotta try that out. I am going to develop an attractive colored tabs implementation, will post there when it's completed.
--
...and if you believe in God, that's because of the Devil // MCMXC a.D.
|
|
|
|
|
I create a tab control and put it on a Rebar coontrol, then create a toolbar as
a tab sheet of the tab control, but I can not get the notificatins when I click
the button
|
|
|
|
|
Sorry for not responding earlier, I missed your message.
Be sure to look at the window hierarchy with Spy++. The direct parent window is the recipient of notifications and commands (by default). You might need to forward notifications and commands on if you want the "grandparent" to also receive these messages. You can use FORWARD_NOTIFICATIONS() in the message map to do this. You can also use Spy++ to trace which windows are receiving which messages.
-Daniel
|
|
|
|
|
excellent!
One problem found:
After building your DockingDemo project in VS.NET 2003 in Debug configuration, run the project by F5. If the bottom pane is autohidden, a memory leak problem is reported after the program is closed. If the bottom pane isnot hidden, no memory leak is reported when exit.
|
|
|
|
|
Max LI wrote:
After building your DockingDemo project in VS.NET 2003 in Debug configuration, run the project by F5. If the bottom pane is autohidden, a memory leak problem is reported after the program is closed. If the bottom pane isnot hidden, no memory leak is reported when exit.
Thanks for the report. It looks like that's a bug in Sergey Klimov's docking window framework. I'll try to take a look at it when I get a chance, but if you find and fix it before I do, please let me know
Thanks,
-Daniel
|
|
|
|
|
Daniel Bowen wrote:
Max LI wrote:
After building your DockingDemo project in VS.NET 2003 in Debug configuration, run the project by F5. If the bottom pane is autohidden, a memory leak problem is reported after the program is closed. If the bottom pane isnot hidden, no memory leak is reported when exit.
Thanks for the report. It looks like that's a bug in Sergey Klimov's docking window framework. I'll try to take a look at it when I get a chance, but if you find and fix it before I do, please let me know
Thanks,
-Daniel
This bug has already been fixed on
WTL Docking windows By Sergey Klimov
Later,
Al.
"Of all the things I've lost in life I miss my mind the most" - Ozzy Osbourne
|
|
|
|
|
I'll put the fix in when I update the code next.
-Daniel
|
|
|
|
|
I really like these components, but there are a few things I have come across:
1. When you have _[A/W]TL_NO_AUTOMATIC_NAMESPACE defined, the code fails to compile because CWindow, CListViewCtrl, etc. are not namespace qualified.
2. I have the ability to drag & drop files onto the MDI client area (even when there is a child window active with its own client. In order to support this, I implement WM_DROPFILES in my TabbedMDI frame class and add:
DragAcceptFiles( m_hWndClient, TRUE );
but this requires the following changes to work:
TabbedMDI.h(1532)
MESSAGE_HANDLER(WM_DROPFILES, OnDropFiles)
TabbedMDI.h(1568)
LRESULT OnDropFiles(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
return GetParent().SendMessage(uMsg, wParam, lParam);
}
3. I find it useful to access the tab control from the frame class, so in my frame class I have:
BaseClass::TClient::TTabCtrl & GetTabControl()
{
return m_tabbedClient.GetTabOwner().GetTabCtrl();
}
to save typing!
4. There is an issue with ListViewNoFlicker.h on Win2000 - if the listview header has items that don't extend the length of the listview control, the remaining area isn't drawn properly. This can be fixed by changing the DoPaint implementation:
void DoPaint(CDCHandle dc, RECT& rcClip)
{
T* pT = static_cast<t*>(this);
if(m_headerCtrl.IsWindow())
{
// Draw the header first...
m_headerCtrl.SendMessage(WM_ERASEBKGND, (WPARAM)(HDC)dc, 0);
m_headerCtrl.SendMessage(WM_PAINT, (WPARAM)(HDC)dc, 0);
m_headerCtrl.ValidateRect(&rcClip);
// Prevent the header being drawn over...
CRect rcHeader;
m_headerCtrl.GetClientRect(&rcHeader);
dc.ExcludeClipRect(&rcHeader);
}
// Now draw the listview...
pT->DefWindowProc( WM_ERASEBKGND, (WPARAM)(HDC)dc, 0);
pT->DefWindowProc( WM_PAINT, (WPARAM)(HDC)dc, 0);
}
Reece Haston Dunn
Software Engineer, Sophos
Web: www.sophos.com
Sophos - protecting businesses against viruses and spam
|
|
|
|
|
Thanks!
rhdunn wrote:
1. When you have _[A/W]TL_NO_AUTOMATIC_NAMESPACE defined, the code fails to compile because CWindow, CListViewCtrl, etc. are not namespace qualified.
Sure, I can namespace qualify those things. Do you use that setting(s)?
rhdunn wrote:
2. I have the ability to drag & drop files onto the MDI client area ...
So, it worked before, but using CTabbedMDIClient it doesn't work? If you were subclassing the MDI client to handle WM_DROPFILES, you could still subclass the MDI client after CTabbedMDIClient subclasses it, and handle WM_DROPFILES there (using CContainedWindow or something).
rhdunn wrote:
3. I find it useful to access the tab control from the frame class, so in my frame class I have: ...
I'll add a "GetMDITabCtrl" to CTabbedMDIFrameWindowImpl that does this.
rhdunn wrote:
4. There is an issue with ListViewNoFlicker.h on Win2000 - if the listview header has items that don't extend the length of the listview control, the remaining area isn't drawn properly. ...
If you just add
m_headerCtrl.SendMessage(WM_ERASEBKGND, (WPARAM)(HDC)dc, 0); before the paint message to the header, does it also work? Like so:
inline void DoPaint(CDCHandle dc, RECT& rcClip)
{
T* pT = static_cast<T*>(this);
pT->DefWindowProc( WM_ERASEBKGND, (WPARAM)(HDC)dc, 0);
pT->DefWindowProc( WM_PAINT, (WPARAM)(HDC)dc, 0);
if(m_headerCtrl.IsWindow())
{
m_headerCtrl.SendMessage(WM_ERASEBKGND, (WPARAM)(HDC)dc, 0);
m_headerCtrl.SendMessage(WM_PAINT, (WPARAM)(HDC)dc, 0);
m_headerCtrl.ValidateRect(&rcClip);
}
}
Or do you have to switch things around like you've done and redraw the header first, exclude the header from drawing, then redraw the list for the problem to be fixed?
Thanks!
-Daniel
|
|
|
|
|
Daniel Bowen wrote:
rhdunn wrote:
1. When you have _[A/W]TL_NO_AUTOMATIC_NAMESPACE defined, the code fails to compile because CWindow, CListViewCtrl, etc. are not namespace qualified.
Sure, I can namespace qualify those things. Do you use that setting(s)?
I use them quite regularly: I am not a huge fan of "using namespace ..." . Note that you may have to use _CSTRING_NS::CString instead of ATL::CString or WTL::CString.
Daniel Bowen wrote:
rhdunn wrote:
2. I have the ability to drag & drop files onto the MDI client area ...
So, it worked before, but using CTabbedMDIClient it doesn't work? If you were subclassing the MDI client to handle WM_DROPFILES, you could still subclass the MDI client after CTabbedMDIClient subclasses it, and handle WM_DROPFILES there (using CContainedWindow or something).
I ran into this problem a while back, so I can't remember the exact details. As far as I can remember you are correct, but I will have another look.
Daniel Bowen wrote:
rhdunn wrote:
4. There is an issue with ListViewNoFlicker.h on Win2000 - if the listview header has items that don't extend the length of the listview control, the remaining area isn't drawn properly. ...
If you just add
m_headerCtrl.SendMessage(WM_ERASEBKGND, (WPARAM)(HDC)dc, 0);
before the paint message to the header, does it also work?
I tried that and other things. Your suggestion causes the entire listview to be erased with the header control The way I posted was the only one that worked correctly
Thanks for a great library .
Regards,
Reece
|
|
|
|
|
Hi,
In the TabDemo there is an IE control used for a new tab window. But I have noticed that when you switch tabs or create a new tab, the focus does not go to the IE control? As in, on a long a page its not possible to use the mouse wheel straight away, you have to click inside the new tab window. How would I give the IE control focus in these two cases?
Thanks.
|
|
|
|
|
Anonymous wrote:
In the TabDemo there is an IE control used for a new tab window. But I have noticed that when you switch tabs or create a new tab, the focus does not go to the IE control? As in, on a long a page its not possible to use the mouse wheel straight away, you have to click inside the new tab window. How would I give the IE control focus in these two cases?
I looked into this a little, and it turns out to be an annoyance that a lot of other people have when hosting the IE web browser control. The problem essentially is that there are multiple windows involved, and IE doesn't forward the focus like it should. Take the TabDemo example. The hierarchy looks like this:
HTML Frame (MDI child window frame)
Tab Control (sibling to tab views, not the parent)
Source View (edit control)
HTML View (hosting the web browser control)
Shell Embedding
Shell DocObject View
Internet Explorer_Server
So the when you switch between the MDI tabs, the code will set focus to the MDI child frame. The MDI child frame happens to be using tabs as well, but it appropriately sets focus to the active tab view, which in this case is the HTML View. In the base class code for the HTML view is the ActiveX control hosting code that will in turn set focus on its child window that's the ActiveX control. This is the Shell Embedding window. However, the Shell Embedding window is not appropriately setting focus to the "Internet Explorer_Server" window. When you click on the web page, then the "Internet Explorer_Server" window will get focus like you'd expect.
So to deal with this, you take over forwarding the focus in response to WM_SETFOCUS in the HTML View. Here's 2 different approaches that seem to work. Each has a couple variations. It seems to me that 1b is generic enough that it could even be used in the generic control hosting base class. For all of them, add a WM_SETFOCUS handler to CHtmlView.
Option 1, via interface calls:
a. Explicitly use IHTML* interfaces:
LRESULT OnSetFocus(UINT , WPARAM , LPARAM , BOOL& bHandled)
{
CComPtr<IWebBrowser2> webBrowser;
this->QueryControl(&webBrowser);
if(webBrowser)
{
CComPtr<IDispatch documentDisp;
webBrowser->get_Document(&documentDisp);
CComQIPtr<IHTMLDocument2> htmlDocument2(documentDisp);
if(htmlDocument2)
{
bool handled = false;
CComPtr<IHTMLElement> activeElement;
htmlDocument2->get_activeElement(&activeElement);
CComQIPtr<IHTMLElement2> activeElement2(activeElement);
if(activeElement2)
{
handled = true;
activeElement2->focus();
}
if(!handled)
{
CComPtr<IHTMLWindow2> parentWindow;
htmlDocument2->get_parentWindow(&parentWindow);
if(parentWindow)
{
parentWindow->focus();
}
}
}
}
bHandled = FALSE;
return 0;
}
b. Use more generic ActiveX control interfaces
CComPtr<IOleObject> oleObject;
this->QueryControl(&oleObject);
if(oleObject)
{
CComPtr<IOleClientSite> oleClientSite;
this->QueryHost(&oleClientSite);
if(oleClientSite)
{
CRect rcControl;
this->GetClientRect(&rcControl);
oleObject->DoVerb(OLEIVERB_UIACTIVATE, NULL, oleClientSite, 0, m_hWnd, &rcControl);
}
}
Option 2, via Win32 calls:
a. Use the window names and hierarchy.
LRESULT OnSetFocus(UINT , WPARAM , LPARAM , BOOL& bHandled)
{
HWND hWndFocus = ::GetFocus();
HWND hWndShellEmbedding = ::FindWindowEx(m_hWnd, NULL, _T("Shell Embedding"), NULL);
if(hWndShellEmbedding)
{
HWND hWndShellDocObjectView = ::FindWindowEx(hWndShellEmbedding, NULL, _T("Shell DocObject View"), NULL);
if(hWndShellDocObjectView )
{
HWND hWndInternetExplorerServer = ::FindWindowEx(hWndShellDocObjectView, NULL, _T("Internet Explorer_Server"), NULL);
if(!::IsChild(hWndInternetExplorerServer, hWndFocus))
{
::SetFocus(hWndInternetExplorerServer);
}
}
}
bHandled = FALSE;
return 0;
}
b. Use the window hierarchy
HWND hWndFocus = ::GetFocus();
HWND hWndShellEmbedding = ::GetWindow(m_hWnd, GW_CHILD);
if(hWndShellEmbedding)
{
HWND hWndShellDocObjectView = ::GetWindow(hWndShellEmbedding, GW_CHILD);
if(hWndShellDocObjectView )
{
HWND hWndInternetExplorerServer = ::GetWindow(hWndShellDocObjectView, GW_CHILD);
if(!::IsChild(hWndInternetExplorerServer, hWndFocus))
{
::SetFocus(hWndInternetExplorerServer);
}
}
}
In the next updates I do, I'll update the sample code to deal with this situation.
HTH,
-Daniel
|
|
|
|
|
As a follow up to this, atlhost.h seems to have some kind of a bug, because it already has the code to do the OLEIVERB_UIACTIVATE in response to WM_SETFOCUS (essentially like the 1b option I posted). The thing that's failing it seems to be that the OLEIVERB_UIACTIVATE is not done if m_bUIActive is on. The very first WM_SETFOCUS call ends up doing the activate, but then the de-activate never happens until the window goes away. So subsequent WM_SETFOCUS handling does not do the OLEIVERB_UIACTIVATE again.
It seems that the check for m_bUIActive during OnSetFocus could be removed so that the activate always happens (which is essentially what I had for the code above). I'm not sure what that might break for other ActiveX controls though.
-Daniel
|
|
|
|
|
Hello
First thanks for the good job .
I tried to have a docking window in a MDI child window (as well as in the main frame) and started to change CChildFrame accordingly. After a lot of blood sweat and tears I got my code compiled but it brought up lots of assertions. The first was caused by the static pThis in the CDockingFocusHandler class. But it did not end there...
My question: Is it possible to have docking windows in MDI childs or not? If yes could somebody please give me a hint of how to proceed?
Thanks in advance
Thomas
|
|
|
|
|
Thomas Mx. wrote:
Is it possible to have docking windows in MDI childs or not? If yes could somebody please give me a hint of how to proceed?
In theory, yes it's possible to have docking windows in MDI children. But in practice, with Sergey's code, I don't know how much success you'll have. If you search the comments here (and on his article), I think there was at least one other person that tried to do this, but with the code as it stands it didn't work right. I've never personally tried though.
However, Sergey's code is not the only docking window code. If you're interested in starting from scratch, take a look at this tutorial for doing "docking toolbars" with straight Win32 code on http://www.catch22.net[^] - part 1[^], part 2[^]. Also, follow the links in part 2 for other people's take on his code. If you end up with something good, I'm sure there's lots of people that would be interested.
-Daniel
|
|
|
|
|
I've just managed to do this ... the upshot is that you need to make an intermediate window derived from CDockingSiteImpl. This becomes the client of the MDI window, and then you put the actual view window (or whatever) as the child of the intermediate window.
The code I have (in a very abbreviated form) is this:
DOCKING INTERMEDIARY:
class CDockingIntermediary
: public dockwins::CDockingSiteImpl<CDockingIntermediary>
{
typedef dockwins::CDockingSiteImpl<CDockingIntermediary> baseClass;
public:
DECLARE_WND_CLASS(_T("CDockingIntermediary"))
BEGIN_MSG_MAP(CCPDockView)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
CHAIN_MSG_MAP(baseClass)
END_MSG_MAP()
public:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
InitializeDockingFrame(CStyle::sIgnoreSysSettings | CStyle::sGhostDrag);
return 0;
}
void setClientWnd(HWND hWnd)
{
m_hWndClient = hWnd;
}
};
MDI FRAME WINDOW:
class CMyFrame
: public CTabbedMDIChildWindowImpl<CAppointmentsFrame, CMDIWindow>
/* other bases */
{
public:
CDockingIntermediary dockSite;
CMyView viewWnd;
CalendarDock miniCal;
BEGIN_MSG_MAP(CAppointmentsFrame)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
/* chaining, etc */
END_MSG_MAP()
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
m_hWndClient = dockSite.Create(m_hWnd,
rcDefault,
NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
UpdateLayout();
CRect rcDef(0,0,400,100);
m_view.Create(dockSite,
rcDef,
NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
dockSite.setClientWnd(m_view);
miniCal.Create(dockSite, rcDef, "Calendar", dwStyle);
SIZE sz = _miniCal._cal.GetMaxSize(1, 3);
m_dockSite.DockWindow(miniCal,
dockwins::CDockingSide(dockwins::CDockingSide::sLeft),
0, /*nBar*/
float(0.0), /*fPctPos*/
sz.cx, /*nWidth*/
sz.cy); /* nHeight*/
return 0;
}
};
I haven't included the view window, but if you've built a project using a wizard, you should already have one.
This is OK as far as it goes, but the CWindowStateMgr I'm using (from Sergey's library) is crashing when I try to Restore after closing and storing. So maybe it's not an ideal solution ... but it's working well enough for the moment.
Phil.
--
All things considered, you can't really consider all things ...
|
|
|
|
|
in dockingframe.h locate like that:
public:
CDockingFrameImplBase()
:m_vPackage(false),m_hPackage(true)
{
}
change: m_vPackage(false),m_hPackage(true)
to: m_vPackage(true),m_hPackage(false)
maybe can solved your question.
|
|
|
|
|
Hi
I wonder if you have any idea how your tabs could be converted to do the mouseover tricks (orange hilight) that XP tabs normally do
I had a (quick) look at UxTheme.dll but couldn't find an obvious way to do this with tabs
thanks
nikos
|
|
|
|
|
umeca74 wrote:
I wonder if you have any idea how your tabs could be converted to do the mouseover tricks (orange hilight) that XP tabs normally do
I do have the tabs setup to do "hot tracking" so that you can do special drawing for the tab under the mouse as the mouse moves over the tabs. However, since the tabs do things from scratch instead of customizing the common controls' tab control, you don't get the orange highlight thing for free.
To see the hot tracking in action, run the TabDemo or DockingDemo example, bring up a document window, then check out the tabs at the bottom for "HTML" and "Source". Move your mouse over them, and notice how the text changes color.
To do hot tracking, you first need to give the tab control the style "CTCS_HOTTRACK". You can then either use custom draw in the tab owner class, or inherit from one of the tab controls like CDotNetTabCtrlImpl and override the drawing. You can just handle the case when the item state has CDIS_HOT set, and let the default happen for other times. You can then draw the orange highlight, and maybe even using something like DrawThemeBackground with TABP_TABITEM and TIS_HOT (I'm not sure which "part" is the right one though if you do this). If you use custom draw, you could just draw on top of what's there for the item during the CDDS_ITEMPOSTPAINT draw stage.
HTH,
-Daniel
|
|
|
|
|
I've made a little modification of this framework in order to get the Visual 2005 tab look:
Screenshot here...[^]
Please mail for any critics:
rlesavre[at]ece.fr
|
|
|
|
|