Can anyone tell me how to find the control IDs for the "Name","size","type", and "Modified" buttons that come up in an Open/Save dialog box when the Details button is pressed? Or does anyone know these control IDs?
Thanks!
Printable View
Can anyone tell me how to find the control IDs for the "Name","size","type", and "Modified" buttons that come up in an Open/Save dialog box when the Details button is pressed? Or does anyone know these control IDs?
Thanks!
Do you mean the header control titles of a ListCtrl?
I think there is no Control ID for a column header. :ehh:
I don't know what they are called. they are the buttons that appear when you press the Details button in any Open/Save dialog. They are the ones that allow you to sort the files by name, type, size, or modified. What I want to do is have the list of files sorted by one of these before the open/save dialog opens to the user. I already know how to simulate a button being pressed but i need the control id.
See the post #2.
These "buttons" are not the Buttons. They are the part (parts) of the Header control, not the controls themselves! :wave:
So does that mean there is no way to access or control them?
I dont know. I am a beginner at this stuff. Why did you get mad at me and give me a bad reputation. I am learning. Thanks a lot.
What? now my reputation is green. Before it was red. What happened? Who controls the reputations?
Well I have never tried it myself but you can something like
- Use FindWindow/EnumChildWindow to find a widow with class "SysListView32".
- Send message LVM_GETHEADER or use macro ListView_GetHeader to get the handle of headerctrl of the ListView.
- Now you need to know against which HeaderItem i.e. size, date, name etc you want to sort. Either hardcode the index (i think it is always the same) or move on the HeaderControl to get the correct index with messages like HDM_GETITEMCOUNT or HDM_GETITEMCOUNT.
- Now send a notify-message to HeaderCtrl's Parent like...
Look into MSDN for how you should fillout the NMHeader struct.Code:SendMessage(GetParent(hHeaderCtrl), WM_NOTIFY, NULL, (LPARAM)&NMHeader);
May be there is anyother easier way to do the same, but sorry i am not aware of it.
Hope this helps,
Regards,
Usman.
Btw, your repo is still green ;)
Thanks for the post. I know, my rep is now green but for a while there is was showing red.
I think I am following you on your explanation but where does the list get sorted by the specified header? Is there a function call or do I put the header items in a specific order with the item that i want to sort by first? thanks again!
Well to sort a ListView you click on the ListView HeaderItem and that Item tells its PARENTWINDOW that a click has happened and do whatever needs to be done. What i told you to is the get HeaderCtrl handle (with handle you can get the info about the HeaderItem, that you can use to fillin the struct NMHEADER, and after filling that struct you do the same (by sending the WM_NOTIFY to parentwnd) that a click even has happened. The ListView should then sort itself. Hope its clear enough.
Regards,
Usman.
Btw I wouldn't mind if you would like to add something to my repo ;).
Take a look at these (and, perhaps, you will find some more) usefull Paul DiLascia's articles:Quote:
Originally Posted by senkyoshi
http://msdn.microsoft.com/msdnmag/issues/0800/c/
http://msdn.microsoft.com/msdnmag/issues/02/01/c/
Hey Usman,
I think that is going to work. I am going to go ahead and try it now but if I have any problems I will add another reply. thanks to both of you. You both should now have a reputation point added to your names!
thanks again
usman,
After I get the handle to the HeaderCtrl, how do I get the information that I need for the NMHEADER struct?
Hi!
Please don't create new threads for the same problem. Now you want to fill in the NMHEADER struct. Its defined in MSDN like...
The first three members of the struct should be pretty straight forward, for the last one use HDM_GETITEM that message will give the HDITEM for the item you are interested in then u can assing the address of the returned HDITEM to the last member of the struct and send the WM_NOTIFY. So you have all the four params filled in.Code:typedef struct tagNMHEADER {
NMHDR hdr;
int iItem;
int iButton;
HDITEM *pitem;
} NMHEADER, *LPNMHEADER
Hope this helps,
Regards,
Usman.
Problem: i am trying to use FindWindow with class "SysListView32" but it isnt returning anything. any other way to get a reference to CListCtrl in the CFileDialog?
thanks
Sorry my mistake, use FindWindowEx. Its a childwindow and FindWindow only searches for Top-Level Windows.
Hope this helps,
Regards,
Usman.
I'm still having problems. here is what i am doing.
BOOL CMyFileDialog::OnInitDialog() // Override
{
...
CFileDialog::OnInitDialog();
// Get a pointer to the original dialog box.
CWnd *wndDlg = GetParent();
CListView *pListView = (CListView *)FindWindowEx(wndDlg->m_hWnd,m_hWnd,"SysListView32", NULL);
...
return true;
}
Try this...
Hope this helps.Code:::FindWindowEx(m_hWnd, NULL, "SysListView32", NULL);
Regards,
Usman.
Ok, that didnt seem to work either. Here is what I did.
HWND hWnd = ::FindWindowEx(m_hWnd, NULL, "SysListView32", NULL);
CListCtrl * pListCtrl = (CListCtrl *)FromHandle(hWnd);
the first line set hWnd to 0x00000000. the second line I use to get a pointer to the object and that isnt working because the hWnd handle is bad. anything else you can think of? thanks so much for your time and help
Have you already read this ( http://msdn.microsoft.com/msdnmag/issues/02/01/c/ ) article?Quote:
Originally Posted by senkyoshi
Paul DiLascia pointed out how you could do this:Quote:
............
Many of the common dialogs have controls with documented IDs like stc1 for a static text control and lst1 for a listbox; these symbols are #defined in <dlgs.h>. You might think the list control would be lst1, but spelunking with Spy (see Figure 1) reveals that the list control is actually contained in another window of class, SHELLDLL_DefView. The SHELLDLL_DefView window has ID lst2; the list control inside it has child ID 1. So to get the list control, you can write:
// from your CFileDialog derivate
CListCtrl* plc = (CListCtrl*)GetParent()->
GetDlgItem(lst2)->GetDlgItem(1);
Remember, when you customize the open file dialog, your CFileDialog is actually a child of the real dialog, which explains why you must use GetParent. (For details see my article "Give Your Applications the Hot New Interface Look with Cool Menu Buttons" in the January 1998 issue of MSJ.) The cast to CListCtrl* works as per the usual MFC trick, because CListControl has neither data members nor virtual functions; it's a pure wrapper class. (Since GetDlgItem returns a pointer to a temporary CWnd, not a CListCtrl, downcasting would normally be a major booboo.)
Once you have a pointer to the list control, you can do whatever you like—within reason.........
Thanks VictorN! When I compile
CListCtrl* plc = (CListCtrl*)GetParent()->GetDlgItem(lst2)->GetDlgItem(1);
it says: error C2065: 'lst2' : undeclared identifier
do you know why this is happening? do I need to add it or the library it is in?
thanks
...nevermind. I had to include <dlgs.h>. I thought that I had already added it
Once again:Have you #included <dlgs.h>?Quote:
Many of the common dialogs have controls with documented IDs like stc1 for a static text control and lst1 for a listbox; these symbols are #defined in <dlgs.h>....
Yes, I actually saw that and it works fine now.
But now, compiling works fine but when I run it and when it gets to that line I get an Unhandled Exception (MFC42D) 0x00000005 Access Violation. Here is my code:
BOOL CMyFileDialog::OnInitDialog() // Override
{
CFileDialog::OnInitDialog();
// Get a pointer to the original dialog box.
CWnd *wndDlg = GetParent();
if ( wndDlg != NULL ) {
wndDlg->PostMessage(WM_COMMAND, 40964, NULL);
}
CListCtrl* plc = (CListCtrl*)wndDlg->GetDlgItem(lst2)->GetDlgItem(1);
return true;
}
any ideas?
thanks
The problem seems to be the List Control is yet not created while OnInitDialog is being called... :confused:
Post user defined Message to your dialog and try to retrieve list control pointer in the handler of this message:Code:// .cpp
#define MY_MESSAGE (WM_APP + 1)
.......
BEGIN_MESSAGE_MAP(CMyFileDialog, CDialog)
//{{AFX_MSG_MAP(CMyFileDialog)
..............
//}}AFX_MSG_MAP
ON_MESSAGE(MY_MESSAGE, OnMyMessage)
END_MESSAGE_MAP()
.........
BOOL CMyFileDialog::OnInitDialog() // Override
{
CFileDialog::OnInitDialog();
// Get a pointer to the original dialog box.
CWnd *wndDlg = GetParent();
if ( wndDlg != NULL ) {
wndDlg->PostMessage(WM_COMMAND, 40964, NULL);
}
PostMessage(MY_MESSAGE);
return true;
}
LRESULT CMyFileDialog::OnMyMessage(WPARAM, LPARAM)
{
ListCtrl* plc = (CListCtrl*)GetParent()->GetDlgItem(lst2)->GetDlgItem(1);
return 0;
}
..........
.........
// .h
//{{AFX_MSG(CMyFileDialog)
..............
//}}AFX_MSG
afx_msg LRESULT OnMyMessage(WPARAM, LPARAM);
DECLARE_MESSAGE_MAP()
.........
senkyoshi!
Take a look at this article: List View Mode, SetForegroundWindow, and Class Protection
PS:
however (in contrary to the author of this article), you should newer use (WM_USER + < n >) as ID for the user defined messages in MFC aoolications. Use (WM_APP + < n >) instead!
Wonderful!
things are working great now. Now on to another problem. On page one of this post usman999_1 says to use
SendMessage(GetParent(hHeaderCtrl), WM_NOTIFY, NULL, (LPARAM)&NMHeader);
to get the list to be sorted by the desired column. however, SendMessage only takes 3 parameters.
So this is what I try and my program crashes when it tries the SendMessage line.
LRESULT CMyFileDialog::OnMyMessage(WPARAM, LPARAM)
{
CListCtrl* plc = (CListCtrl*)GetParent()->GetDlgItem(lst2)->GetDlgItem(1);
CHeaderCtrl *pHCtrl = plc->GetHeaderCtrl();
HWND hHeaderCtrl = pHCtrl->m_hWnd;
NMHDR pNMHDR;
pNMHDR.hwndFrom = hHeaderCtrl;
pNMHDR.idFrom = pHCtrl->GetDlgCtrlID();
NMHEADER * NMHeader;
NMHeader->hdr = pNMHDR;
NMHeader->iItem = 3;
NMHeader->iButton = 0;
SendMessage(WM_NOTIFY, NULL, (LPARAM)&NMHeader);
return 0;
}
Can you see where I am having a problem?
thanks
Try this:Quote:
HWND hHeaderCtrl = pHCtrl->m_hWnd;
NMHDR pNMHDR;
pNMHDR.hwndFrom = hHeaderCtrl;
pNMHDR.idFrom = pHCtrl->GetDlgCtrlID();
NMHEADER * NMHeader;
NMHeader->hdr = pNMHDR;
NMHeader->iItem = 3;
NMHeader->iButton = 0;
SendMessage(WM_NOTIFY, NULL, (LPARAM)&NMHeader);
Code:HWND hHeaderCtrl = pHCtrl->m_hWnd;
NMHDR nmHDR;
nmHDR.hwndFrom = hHeaderCtrl;
nmHDR.idFrom = pHCtrl->GetDlgCtrlID();
NMHEADER NMHeader;
NMHeader.hdr = nmHDR;
NMHeader.iItem = 3;
NMHeader.iButton = 0;
SendMessage(WM_NOTIFY, NULL, (LPARAM)&NMHeader);
OK, it isn't crashing anymore but nothing is happening. The following line:
NMHeader->iItem = 3;
should be telling it to click the Modified area correct (since it is zero based and we have Name, size, type, Modified) Well, nothing is being clicked. Am I missing something in the code I last posted?
Try to check if the header with the text "Modified" is the item 3:Code:HDITEM hdi;
TCHAR lpBuffer[256];
hdi.mask = HDI_TEXT;
hdi.pszText = lpBuffer;
hdi.cchTextMax = 256;
bool bFound = false;
for (int iCol = 0; i < pHCtrl->GetItemCount(); iCol++)
{
pHCtrl->GetItem(iCol, &hdi);
if (strcmp(hdi.pszText, _T("Modified") == 0)
{
bFound = true;
break;
}
}
if(bFound)
{
// now iCol - item number
// send your message
}
Yes, "Modified" is column(item) 3
I didnt set the HDITEM in the NMHEADER struct. Do I need to do this? usman999_1 said to use HDM_GETITEM message to get this. Could this be my problem?
Instead I use pHCtrl->GetItem(3, &hdi). Here is what I have so far:
LRESULT CMyFileDialog::OnMyMessage(WPARAM, LPARAM)
{
CListCtrl* plc = (CListCtrl*)GetParent()->GetDlgItem(lst2)->GetDlgItem(1);
CHeaderCtrl *pHCtrl = plc->GetHeaderCtrl();
HWND hHeaderCtrl = pHCtrl->m_hWnd;
NMHDR nmHDR;
nmHDR.hwndFrom = hHeaderCtrl;
nmHDR.idFrom = pHCtrl->GetDlgCtrlID();
HDITEM hdi;
pHCtrl->GetItem(3, &hdi);
NMHEADER NMHeader;
NMHeader.hdr = nmHDR;
NMHeader.iItem = 3;
NMHeader.iButton = 0;
NMHeader.pitem = &hdi;
::SendMessage(::GetParent(hHeaderCtrl),WM_NOTIFY,NULL,(LPARAM)&NMHeader);
return 0;
}
Anyways, the dialog comes up great but it still doesnt sort by the modified column
Just in case anyone cared I just figured out how to do it.
I made the Modified item the first in the header and then found the bounding rectangle for that item. Then, I did a PostMessage to simulate a button press. I couldnt get sendmessage to work at all. Anyways, I am so happy to finally have this case closed. Thanks to those that helped me! here is my code:
LRESULT CMyFileDialog::OnMyMessage(WPARAM, LPARAM)
{
CListCtrl* plc = (CListCtrl*)GetParent()->GetDlgItem(lst2)->GetDlgItem(1);
CHeaderCtrl *pHCtrl = plc->GetHeaderCtrl();
HDITEM hdi;
pHCtrl->GetItem(3, &hdi);
int iArray[] = {3,0,1,2};
pHCtrl->SetOrderArray(4, iArray);
CPoint point;
RECT pRect;
pHCtrl->GetItemRect(3, &pRect);
pHCtrl->PostMessage(WM_LBUTTONDOWN, MK_LBUTTON,MAKELONG((WORD) (pRect.left + 5),(WORD) (pRect.top + 5)));
pHCtrl->PostMessage(WM_LBUTTONUP, MK_LBUTTON,MAKELONG((WORD) (pRect.left + 5),(WORD) (pRect.top + 5)));
return 0;
}
Congratulation! :thumb: :)
With the best regards,
Victor