[RESOLVED] Highlite entry in GetOpenFileName() list, programmatically.
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15

Thread: [RESOLVED] Highlite entry in GetOpenFileName() list, programmatically.

  1. #1
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Highlite entry in GetOpenFileName() list, programmatically.

    I'm using the GetOpenFileName() common dialog, with no problems. Now I want to add a feature of making the default filename be supplied (with the last opened filename). This is not an issue, per se, as the filename shows up in the File Name edit field. But I also would like to have that file entry in the list be automatically selected (highlited), scrolling the list as necessary to make the selected name visible.

    After looking through the VC8 help files on this topic, I don't see any way to make the OFN dialog select an entry by sending a message, or any other method. Can this be done?

    I really don't want to re-invent the OFN dialog just to accomplish this.
    Last edited by cosmicvoid; October 21st, 2012 at 12:10 AM. Reason: set to not resolved

  2. #2
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,024

    Re: Highlite entry in GetOpenFileName() list, programmatically.

    This is not a standard OFN feature, so you have to hook the dialog and operate with its list view within your hook proc.

    lpfnHook

    Type: LPOFNHOOKPROC

    A pointer to a hook procedure. This member is ignored unless the Flags member includes the OFN_ENABLEHOOK flag.

    If the OFN_EXPLORER flag is not set in the Flags member, lpfnHook is a pointer to an OFNHookProcOldStyle hook procedure that receives messages intended for the dialog box. The hook procedure returns FALSE to pass a message to the default dialog box procedure or TRUE to discard the message.

    If OFN_EXPLORER is set, lpfnHook is a pointer to an OFNHookProc hook procedure. The hook procedure receives notification messages sent from the dialog box. The hook procedure also receives messages for any additional controls that you defined by specifying a child dialog template. The hook procedure does not receive messages intended for the standard controls of the default dialog box.
    Best regards,
    Igor

  3. #3
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: Highlite entry in GetOpenFileName() list, programmatically.

    Hi Igor,
    I already have a hook established to the OFN dialog, as I am doing other things with it (keeping track of size & position). So I will have to find a way to get a handle to the list view control. Maybe Spy++ will be of some help there; or maybe you already know of an easier way to get that control's handle? I am a bit rusty at this, as I don't do much windows programming any more.

    Tom
    Last edited by cosmicvoid; October 15th, 2012 at 03:01 AM.

  4. #4
    Join Date
    Oct 2012
    Posts
    8

    Re: Highlite entry in GetOpenFileName() list, programmatically.

    I think you will get CDN_INITDONE from WM_NOTIFY in the FileOpenHookProcedure. As I remember, the relevant window is the first function parameter and you should be safe to post messages at that point.

  5. #5
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: Highlite entry in GetOpenFileName() list, programmatically.

    Thanks edpat,
    I tried trapping the CDN_INITDONE notification, and discovered some interesting results.

    At the time of CDN_INITDONE, the Spy++ listing for the OFN dialog shows a window with a "ListBox" class, and the VC8 help docs say that this is a child with control ID "lst1". So doing this:
    Code:
    hWlv = GetDlgItem(hWnd, lst1);
    gets a handle to that list box, but the list seems to be empty. Trying to fetch the count, using:
    Code:
    ListView_GetItemCount(hWlv);
    returns 0.

    If I let the code run to the point where the OFN dialog appears, and then look at the child window list in Spy++ again, there are items that weren't present earlier: a window with a "SHELLDLL_DefView" class, which has a child titled "FolderView" with a "SysListView32" class.

    I am assuming the "SysListView32" window (which has the identical coordinates as the empty "ListBox" window) is the one containing the actual file list. My problem is that these windows don't exist at the time of the CDN_INITDONE notification, so I am at a loss as to how to get a notification after they are created.

    Any ideas?
    Last edited by cosmicvoid; October 16th, 2012 at 03:14 AM.

  6. #6
    Join Date
    Oct 2012
    Posts
    8

    Re: Highlite entry in GetOpenFileName() list, programmatically.

    Maybe NM_SETFOCUS could be used to check / wait for SysListView32 (GetClassName(hwnd, classText, 128)), though it's becoming messy.

  7. #7
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: Highlite entry in GetOpenFileName() list, programmatically.

    Making progress...

    I discovered that a few other CDN_ notifications occured at the time the dialog became visible, but before any user interaction occured. So I trapped on the first occurance of CDN_SELCHANGE, at which time the "SysListView32" is created and populated. Trying
    Code:
    hWlv = FindWindowEx(hWnd, NULL, _T("SysListView32"), _T("FolderView"));
    fails for some reason, so I resorted to finding it by enumerating the children
    Code:
    EnumChildWindows(hWp, (WNDENUMPROC)EnumOFNChildProc, (LPARAM)&lvinfo);
    This succeeded, but I had to cheat to get it to work.

    In the EnumChild proc,
    Code:
    BOOL CALLBACK EnumOFNChildProc(HWND hwd, LPARAM plvi)
    {
    	WINDOWINFO wifo;
    	LVINFO *lvi = (LVINFO *)plvi;
    
    	wifo.cbSize = sizeof(WINDOWINFO);
    	GetWindowInfo(hwd, &wifo);
    	if (wifo.atomWindowType == lvi->lvatom)
    	{
    		lvi->hWlv = hwd;
    		return false;
    	}
    	return true;
    }
    the only parameter I saw to compare with was the window class ATOM value. But when I try to get the ATOM
    Code:
    lvatom = GlobalFindAtom(_T("SysListView32"));  // returns 0xC051
    I get 0xC051, which doesn't work. In the Spy++ properties for the "SysListView32" window, the class ATOM is shown as 0xC03F, and if I hard code that value to make the child match, it works fine. But I'm really not happy with hard coding that ATOM value, but I don't have an alternative window identifying method.

    So now I have the handle of the "SysListView32" window, and I can find the filename in the list, and set the highlite attribute, and force it to scroll into visibility. Strangely, the highlite on the list entry is the dull color that is used when the list is "out of focus", and not the color you get if you click on an entry. But I could fix that by explicitly doing a "SetFocus()" on the list control.

    So I guess I'm done, unless someone can suggest a reason that the GlobalFindAtom(_T("SysListView32")) is returning the wrong value.
    Last edited by cosmicvoid; October 16th, 2012 at 06:03 AM.

  8. #8
    Join Date
    Oct 2012
    Posts
    8

    Re: [RESOLVED] Highlite entry in GetOpenFileName() list, programmatically.

    I had thought that the window handle (of ->hdr.hwndFrom) as below would have been the "SysListView32" window, but no, presumably it is a copy of the dialog window.

    OFNOTIFY *of
    WM_NOTIFY
    of = (OFNOTIFY *) lParam
    of ->hdr.hwndFrom

  9. #9
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: [RESOLVED] Highlite entry in GetOpenFileName() list, programmatically.

    The window handle passed to the hook, and the handle in the WM_NOTIFYs, are that of the dialog. I am also guessing that the empty "ListBox" window is just a place-holder in the dialog template, used to locate the dynamic list; as this is a technique that I have used myself. Although I don't know why MS doesn't bother to destroy the "ListBox" after the other list window is co-located.

    Thanx for your ideas, though. Still don't know why I can't read the correct ATOM value for the "SysListView32" class.

  10. #10
    VictorN's Avatar
    VictorN is online now Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Wallisellen (ZH), Switzerland
    Posts
    17,471

    Re: [RESOLVED] Highlite entry in GetOpenFileName() list, programmatically.

    You may want to look at this thread.
    Victor Nijegorodov

  11. #11
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: [RESOLVED] Highlite entry in GetOpenFileName() list, programmatically.

    Thanks very much, Victor. That is just what I needed, and simplifies my code a lot.

  12. #12
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: [RESOLVED] Highlite entry in GetOpenFileName() list, programmatically.

    I've run into a snag while testing this code. The initial development was done in XP-sp3, and the code works as expected; however, testing in Win7HP-64 gives different results. Here is the relevant code
    Code:
    UINT CALLBACK OFNHookProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	HWND hWp, hWlv;
    	NMHDR *pnm;
    	static BOOL init;
    	LVFINDINFO lvfi;
    	int indx;
    
    	switch (msg)
    	{
    	< snip ... >
    	case WM_NOTIFY:
    		if (init) break;		// if already did highlite
    		pnm = (NMHDR *)lParam;
    		if (pnm->code == CDN_SELCHANGE)
    		{
    			init = true;			// first time notification after list view created
    			hWp = GetParent(hWnd);	// get parent
    			hWlv = GetDlgItem(hWp, lst2);	// get list view shell window
    			if (hWlv == NULL) break;
    			hWlv = GetDlgItem(hWlv, 1);		// get "SysListView32" window
    			if (hWlv == NULL) break;
    			lvfi.flags = LVFI_STRING;
    			lvfi.psz = path;
    			indx = ListView_FindItem(hWlv, -1, &lvfi);	// find filename in list
    			if (indx < 0) break;
    			ListView_SetItemState(hWlv, indx,			// if found, select it
    				LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
    			ListView_EnsureVisible(hWlv, indx, true);	// scroll into view
    			SetFocus(hWlv);
    			return true;
    		}
    		break;
    The first difference under Win7 is that there is no CDN_SELCHANGE message sent to the hook until the user actually interacts with the file list (unlike in XP, where the CDN_SELCHANGE occurs when the list view is initialized). At the time of the CDN_INITDONE message, the list view is not yet created, as is the case in XP. I discovered that a CDN_FOLDERCHANGE is sent after the list view is created, but at that point the list is not populated, as the ListView_FindItem() search fails.

    Also, in Win7, when I click on a filename to cause a CDN_SELCHANGE message, and step thru the WM_NOTIFY code, it executes but code that is supposed to highlite the filename entry and scroll it into view does not have any effect.

    One other clue: in XP, the filename supplied as the initial value is highlited in the list, but not in the "File Name" edit control; in Win7, the name is failing to highlite in the list, but it IS highlited in the "File Name" edit control.

    Any suggestions?

  13. #13
    VictorN's Avatar
    VictorN is online now Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Wallisellen (ZH), Switzerland
    Posts
    17,471

    Re: [RESOLVED] Highlite entry in GetOpenFileName() list, programmatically.

    Perhaps, you'll get some ideas from this MSDN article: Common Item Dialog
    Victor Nijegorodov

  14. #14
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: [RESOLVED] Highlite entry in GetOpenFileName() list, programmatically.

    Thanks Victor,
    The main idea that your linked article gave me was that the shell object method did not provide any of the notifications or actions that would do what I need. Also, it looks like a new programming 'trick' that this 'old dog' doesn't want to bother to learn. But it did make me think of a solution.

    I was able to solve my issue in both XP and Win7 by creating a thread in the WM_INITDIALOG message of the OFN hook. The thread tries periodically to get the ListView handle and find + highlite the filename. Then it terminates, or bails out after 1 sec if not successful.

    A bit Rube-Goldbergish perhaps, but it does what I need.

  15. #15
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,014

    Re: [RESOLVED] Highlite entry in GetOpenFileName() list, programmatically.

    Quote Originally Posted by cosmicvoid View Post
    I was able to solve my issue in both XP and Win7 by creating a thread in the WM_INITDIALOG message of the OFN hook. The thread tries periodically to get the ListView handle and find + highlite the filename. Then it terminates, or bails out after 1 sec if not successful.
    A similar but simpler approach would be to post a user message to the dialog from the WM_INITDIALOG message handler instead of creating a thread.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center