News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Windows Explorer-style "browse for file" window

Started by raleeper, June 25, 2011, 08:49:58 PM

Previous topic - Next topic

raleeper

Quote from: dedndave on February 11, 2012, 03:53:56 AM
it isn't as simple as you might think   ::)

here is an article i found by Paul DiLascia
http://msdn.microsoft.com/en-us/magazine/cc164009.aspx

Quote...the list control isn't a direct child of the dialog, it's a grandchild. ... the main dialog has a child window whose class name is
SHELLDLL_DefView; this, in turn, contains the list control of files and folders ... The ID of the
SHELLDLL_DefView is lst2 (value 0x0461, defined in dlgs.h), but it's not a listbox or
list control. The real SysListView32 is a child of SHELLDLL_DefView, with child ID=1
.

shouldn't be too hard, from there
if i have time, i will see what i can do tomorrow   :P

So to get the handle of the dialog window you have to

invoke GetParent,[esp+4]
invoke GetParent,eax
?

Your code, tranfigured (mangled) by me, works, sort of - it (looks like it) moves the dialog window, but also destroys some of its features.

Empirical programming indeed.  But I would never have thought of any of the article stuff on my own.

Thanks, ral

raleeper

Quote from: raleeper on February 11, 2012, 10:44:42 AM
So to get the handle of the dialog window you have to

invoke GetParent,[esp+4]
invoke GetParent,eax
?

No, that gets the handle of the parent of the dialog (or at least, it is the parent of  the dialog, ie the original window, that is moved when the whole routine is run.)

Thanks, ral

dedndave

ok - it is a bit confusing - lol

when you install a hook for an Explorer-style Open File dialog, the hook is actually to a child window of the dialog box
so, you use GetParent to find the handle of the dialog box that appears on the screen
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646931%28v=vs.85%29.aspx
QuoteIf you provide a hook procedure for an Explorer-style common dialog box, the system creates a dialog box
that is a child of the default dialog box. The hook procedure acts as the dialog procedure for the child dialog.

Paul goes on to say that the listview control is a child of a child of that dialog   :P
so, we use GetParent, GetDlgItem, and GetDlgItem again, to get the handle to the listview control
however, to get that far, we have to wait for the listview to be created - lol

once you have the handle to the listview control,
you can just use GetWindowRect and assume the first file is near the upper left corner

Quoteit (looks like it) moves the dialog window, but also destroys some of its features.
this is just a matter of picking the right flags
the style you see is the one i prefer   :bg
the one you may be used to has a few network shortcut links on the left side

as for what is in the Dlgs.h file, Paul gives you that info
Quote...lst2 (value 0x0461...
that seems to be the only one that is pertinent to our code

Hutch has placed that EQUate in the windows.inc file
lst2 EQU 461h
i don't know if there is an EQUate for the listview ID (1) - if there were, i think Paul would have mentioned it
i don't see it in Dlgs.h

raleeper

Quote from: dedndave on February 11, 2012, 12:52:38 PM
ok - it is a bit confusing - lol
...
i don't see it in Dlgs.h

Your post is in digestion.

Thanks, ral


dedndave

didn't have time, yesterday
had some things to take cre of
maybe i'll have time, today   :P

dedndave

well - after looking at Paul's code a little more, i think there may be a better way
his code relies on the fact that messages sent via PostMessage are not handled until the queue is otherwise empty
and, while i like that plan for testing code or for playing around, i don't like it as much for a real-world application
i don't want to second-guess how and when messages are pulled from the queue   :P

i have searched around for more information on the SHELLDLL_DefView window class
in this case, MSDN doesn't seem to be the best source
but, there is plenty of material, as it is the same class as that used by the Desktop window
i suppose they use it for Open and Save File dialogs because the network shortcut links are probably handled much the same as Desktop icons

after doing some reading, i also found that the hierarchy may be different for win7, if using something like the Aero theme
so - we can avoid some potential problems by planning our code, accordingly

"normal" hierarchy
Open File dialog window
+ SHELLDLL_DefView (ID = lst2 = 461h)
  + listview control (ID = 1)


possible win 7 hierarchy
Open File dialog window
+ WorkerW window (ID unknown)
  + SHELLDLL_DefView (ID = lst2 = 461h)
    + listview control (ID = 1)


anyways, i think we can look for WM_NOTIFY messages sent from child to parent until we get one we want

raleeper

Quote from: dedndave on February 12, 2012, 07:18:05 PM
well - after looking at Paul's code a little more, i think there may be a better way
his code relies on the fact that messages sent via PostMessage are not handled until the queue is otherwise empty
and, while i like that plan for testing code or for playing around, i don't like it as much for a real-world application
i don't want to second-guess how and when messages are pulled from the queue   :P

i have searched around for more information on the SHELLDLL_DefView window class
in this case, MSDN doesn't seem to be the best source
but, there is plenty of material, as it is the same class as that used by the Desktop window
i suppose they use it for Open and Save File dialogs because the network shortcut links are probably handled much the same as Desktop icons

after doing some reading, i also found that the hierarchy may be different for win7, if using something like the Aero theme
so - we can avoid some potential problems by planning our code, accordingly

"normal" hierarchy
Open File dialog window
+ SHELLDLL_DefView (ID = lst2 = 461h)
  + listview control (ID = 1)


possible win 7 hierarchy
Open File dialog window
+ WorkerW window (ID unknown)
  + SHELLDLL_DefView (ID = lst2 = 461h)
    + listview control (ID = 1)


anyways, i think we can look for WM_NOTIFY messages sent from child to parent until we get one we want

And the one we want is CDN_INITDONE?

Thanks, ral

dedndave

well - not exactly
if we receive any notification from the listview control, we know it has been created and has size
at that point, we can use GetWindowRect to get it's location

thing is - we have to temporarily subclass any parent windows in the hierarchy   :'(
we will sublass the Open File dialog and wait for a notification from either a "WindowW" or "SHELLDLL_DefView" class window
if it's a WindowW class window, we subclass that until the SHELLDLL_DefView class window is created
then, we subclass that and wait for a notification from the listview control
once that happens, we can calculate and set the position of the Open File dialog   :P

at least - that's the plan, for now
i may come up with something a little simpler

raleeper

dedndave:
I ought to be able to figure this out, but I don't understand the first line below (from your SmallOFN.asm):


        cmp dword ptr [eax].OFNOTIFY.hdr.code,CDN_FILEOK
        jz      OHook1


As I read the documentation, eax (lParam from WM_NOTIFY) is a pointer to an NMHDR structure the members of which are:

   HWND   hwndFrom;
   UINT_PTR idFrom;
   UINT   code;

So I would expect the line to be:

        cmp dword ptr [eax].code,CDN_FILEOK

or

        cmp dword ptr [eax+8],CDN_FILEOK


Where am I going wrong?

Thanks , ral

dedndave

your code would also work
in fact, the assembler actually generates code that looks like your last example:
        cmp dword ptr [eax+8],5  ;CDN_FILEOK EQU 5
however, i try to follow the documentation   :P

the CDN_FILEOK notification passes a pointer to an OFNOTIFY structure
the first member of that structure is an NMHDR structure, named "hdr"

CDN_FILEOK:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646857%28v=vs.85%29.aspx
QuotelParam
    A pointer to an OFNOTIFY structure.
    The OFNOTIFY structure contains an NMHDR structure whose code
member indicates the CDN_FILEOK notification message.
    The OFNOTIFY structure also contains a pointer to an OPENFILENAME
structure whose lpstrFile member specifies the address of the selected file name.

OFNOTIFY:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646836%28v=vs.85%29.aspx
Quotetypedef struct _OFNOTIFY {
  NMHDR          hdr;
  LPOPENFILENAME lpOFN;
  LPTSTR         pszFile;
} OFNOTIFY, *LPOFNOTIFY;

the NMHDR structure is used this way for many notification messages
in some cases, they don't pretty it up with a structure definition   :bg
they just say "a pointer to an NMHDR structure, which is followed by..."

i haven't played with the GetOpenFile/GetSaveFile functions for a while
it could be that my code that parses the added extension is unnecessary   :P
these functions have a lot of variations, which explains the size of the OPENFILENAME structure - lol

for the lpstrDefExt member of the OPENFILENAME structure, i pass a pointer to the string: 'txt',0
my thinking there is; if the user enters no extension at all, the default will be used
i could probably avoid the problem by using a NULL value for that member

dedndave

well - it seems i may have found a better way   :P
not sure how well it will work under win 7, though

i wrote some test code that subclasses the Open File dialog box
the DlgProc looks like this
OfnDlgProc PROC hwndDlg:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

        cmp     uMsg,WM_NOTIFY
        mov     eax,nCount
        jnz     ODPr90

        inc     eax
        jz      ODPr90

        mov     nCount,eax
        INVOKE  GetDlgItem,hwndDlg,lst2
        or      eax,eax
        jz      ODPr90

        INVOKE  GetDlgItem,eax,1
        or      eax,eax
        jz      ODPr90

        push    ebx
        push    eax
        mov     ebx,ustr$(nCount)
        pop     eax
        mov     nCount,-1
        INVOKE  MessageBox,NULL,ebx,uhex$(eax),MB_OK
        pop     ebx

ODPr90: INVOKE  CallWindowProc,hDlgPrev,hwndDlg,uMsg,wParam,lParam
        ret

OfnDlgProc ENDP


while no WM_NOTIFY messages are received from either the lst2 control or the listview control,
those controls are present when the first WM_NOTIFY message is received   :P

dedndave

got it up and running
i need to do some clean-up - tomorrow   :P

dedndave

playing with this thing, this morning...

it seems to work ok, but...
if i move the main window down to the lower right corner of the screen
then, open file...
i can catch a brief glimpse of the open file dialog window as it is drawn in the upper-left corner of the screen, before it is moved
this happens when hwndOwner is set to NULL
if i use the main window as the owner, the box is drawn inside the client area (same coordinates - 0,0)
however, the box does not seem to like being moved to a location with negative client coordinates
i want to play with that some more - seems like it ought to work

i can use ShowWindowAsync to hide the window until it is moved, which helps a little, but does not eliminate it
i may be able to set hwndOwner to the main window, then change the parent to HWND_DESKTOP with SetParent   :P

in reading the SetParent documentation, i noticed a neat little trick...
QuoteIf this parameter is HWND_MESSAGE, the child window becomes a message-only window.
i can see where that could be useful   :U

dedndave

#43
ok - there is no problem with moving the window when hwndOwner is set to the main window
i had merely miscalculated the position   :P
that makes things kind of simple

this is a great technique
once you have the handle to the open file dialog listview control, you can do some fun stuff, like...
set the view mode (list, details, icons, tiles, thumbnails)
set the listview background colour
you can even put a background image in there, if you like   :bg
(no - not a picture of you, but a grey-shade logo might be cool)

we need someone to test it under windows 7 with aero glass theme
the open file dialog box is supposed to come up with the first listview item under the cursor

one thing i do in there, is un-subclass the dialog when done
that step could probably be skipped - there is no harm in leaving it subclassed, really
i set a flag (OfnFlag) to indicate the move has been done

Ral: thanks for starting this thread - i had fun and learned a lot   :U

EDIT: updated the attachment in post #52

jj2007

That looks cool, Dave :U

Minor suggestion: Details preselected, sorted by date (youngest files on top) :thumbu