There are 2 ways you can modify the open dialog:
1. Create controls with CreateWindowEx and set the parent of the control to the open dialog.
2. Create a dialog "template" that will be added to the open dialog.
I will show how to use #2.
Create a dialog with:
No Border, is a child, clip siblings, no sysmenu, no min/max buttons, no scroll bar, not a popup, DS_3DLOOK, DS_CONTROL.
And for this sample 2 controls:
A listview control with the style LVS_ICON
and a "Secret" control that the open dialog will use to position our dialog.
Whatever control you use make sure it is NOT visible and the ID is 1119 this is important as windows will look for a control with this ID and place our control(s) accordingly. This secret control is defined in dlgs.h as stc32.
This control will also dictate the width or height of the open dialog. In the following pics, I made the stc32 control red to show what its placement does.
If you place stc32 at the top of your dialog, our controls will be at the bottom of the open dialog:

If at the bottom, controls will be at top:

If at the left, controls will be on the right, if on right, controls will be on left:

This gives us a very easy way to place our child dialog. You can also hide/position the default controls, change the text, modify explorers listview MANY things can be done. We will hide a few controls we dont' need.
For this tutorial, besides the child dialog for the open dialog, we will need a main dialog with 2 static controls to display our selected icons.
This is our proc for our main dialog (Got a bit lazy and decided to use dialogs
MainDlg proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
mov eax,uMsg
.if eax==WM_INITDIALOG
invoke GetDlgItem, hWin, IDC_IMG_LRG
mov hImg32, eax
invoke GetDlgItem, hWin, IDC_IMG_SM
mov hImg16, eax
.elseif eax==WM_COMMAND
mov edx,wParam
movzx eax,dx
shr edx,16
.if edx==BN_CLICKED
.if eax==IDC_OK
invoke RtlZeroMemory, addr ofn, sizeof ofn
mov ofn.lStructSize, sizeof OPENFILENAME
push hWin
pop ofn.hwndOwner
push hInst
pop ofn.hInstance
mov ofn.lpstrFilter, offset DlgFilter
mov ofn.lpstrTitle, offset DlgTitle
mov ofn.Flags, OFN_EXPLORER or OFN_ENABLETEMPLATE \
or OFN_ENABLEHOOK or OFN_HIDEREADONLY
mov ofn.lpfnHook, offset DlgHook
mov ofn.lpTemplateName, IDD_DLG
invoke GetOpenFileName, addr ofn
.elseif eax==IDC_CANCEL
invoke SendMessage,hWin,WM_CLOSE,NULL,NULL
.endif
.endif
.elseif eax==WM_CLOSE
invoke SendMessage, hImg32, STM_GETICON, 0, 0
invoke DestroyIcon, eax
invoke SendMessage, hImg16, STM_GETICON, 0, 0
invoke DestroyIcon, eax
invoke EndDialog,hWin,0
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
MainDlg endp
WM_INITDIALOG
Here we get the handles to our static controls that will display our 32x32 and 16x16 icons.
WM_COMMAND
When you click the choose icon button, we will fill the OPENFILENAME structure then call GetOpenFileName.
lStructSize = as most windows structure, the OS uses this to know how many members to expect.
hwndOwner = the parent of the Open Common Dialog - our main dialog
hInstance = the instance of our app which windows will load our dialog template from.
lpstrFilter = pointer to our string to use as the file filter
lpstrTitle = The caption of the open dialog
Flags = bits to initialize the dialog. Here we will use:
OFN_EXPLORER <---- Need this to use a template
OFN_HIDEREADONLY <---- Hide the read only check box
OFN_ENABLETEMPLATE <---- Tells the OS to use a template
OFN_ENABLEHOOK <---- Need this to use a template
lpfnHook = the address of our hook procedure to process the open dialog and our listview messages
lpTemplateName = the ID of our dialog that we are going to use
Now, the "magic" happens in our DlgHook procedure:
DlgHook proc uses esi edi ebx hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
mov eax,uMsg
.if eax==WM_INITDIALOG
; Image list for browse for icons dialog
invoke ImageList_Create, 32, 32, ILC_MASK or ILC_COLORDDB, 2, 500
mov himlDlg, eax
; Get handle to open file dialog
invoke GetParent, hWin
mov ebx, eax
mov hParent, eax
; I don't want these 3 controls, so hide em
; Hide file name static control
invoke SendMessage, eax, CDM_HIDECONTROL, stc3, 0
; Hide file name edit control
invoke SendMessage, ebx, CDM_HIDECONTROL, edt1, 0
; Hide ok button
invoke SendMessage, ebx, CDM_HIDECONTROL, IDOK, 0
; Now move the next 3 controls up
; Adjust file type static top
invoke memfill, offset tTR, sizeof RECT, NULL
invoke memfill, offset wLp, sizeof POINT, NULL
invoke GetDlgItem, ebx, stc2
mov edi, eax
invoke GetWindowRect, edi, offset tTR
invoke ScreenToClient, ebx, offset wLp
mov eax, wLp.x
add eax, tTR.left
mov esi, wLp.y
add esi, tTR.top
sub esi, 30
invoke SetWindowPos, edi, 0, eax, esi, 0, 0, SWP_NOSIZE
; Adjust file type combo top
invoke GetDlgItem, ebx, cmb1
mov edi, eax
invoke GetWindowRect, edi, offset tTR
mov eax, wLp.x
add eax, tTR.left
sub esi, 4
invoke SetWindowPos, edi, 0, eax, esi, 0, 0, SWP_NOSIZE
; Adjust cancel button top
invoke GetDlgItem, ebx, IDCANCEL
mov edi, eax
invoke GetWindowRect, edi, offset tTR
mov eax, wLp.x
add eax, tTR.left
sub esi, 4
invoke SetWindowPos, edi, 0, eax, esi, 0, 0, SWP_NOSIZE
; Get handle to our listview
invoke GetDlgItem, hWin, IDC_LSV1
mov hLVDlg, eax
; Set image list to listview
invoke SendMessage, eax, LVM_SETIMAGELIST, LVSIL_NORMAL, himlDlg
.elseif eax==WM_COMMAND
mov edx,wParam
movzx eax,dx
shr edx,16
.if edx==BN_CLICKED
.if eax==IDOK
.elseif eax==IDCANCEL
invoke SendMessage, hWin, WM_CLOSE, NULL, NULL
.endif
.endif
.elseif eax == WM_NOTIFY
.if wParam == IDC_LSV1
mov eax, lParam
.if dword ptr(NMHDR ptr [eax]).code == LVN_ITEMCHANGING
.if dword ptr(NMLISTVIEW ptr [eax]).uNewState == LVIS_FOCUSED or LVIS_SELECTED
invoke ImageList_GetIcon, himlDlg, dword ptr(NMLISTVIEW ptr [eax]).iItem, ILD_TRANSPARENT
push eax
invoke SendMessage, hImg32, STM_SETICON, eax, 0
invoke DestroyIcon, eax
pop eax
invoke CopyImage, eax, IMAGE_ICON, 16, 16, LR_COPYFROMRESOURCE
invoke SendMessage, hImg16, STM_SETICON, eax, 0
invoke DestroyIcon, eax
invoke PostMessage, hParent, WM_CLOSE, 0, 0
ret
.else
jmp PassThrough
.endif
.else
jmp PassThrough
.endif
.else
mov eax, lParam
.if dword ptr(NMHDR ptr [eax]).code == CDN_SELCHANGE
; Get path of selected file
mov byte ptr [DlgFilePath], 0
invoke memfill, offset DlgFilePath, MAX_PATH + 1, NULL
invoke SendMessage, hParent, CDM_GETFILEPATH, MAX_PATH + 1, offset DlgFilePath
invoke PathFindExtension, offset DlgFilePath
invoke Cmpi, eax, offset szExtIco
test eax, eax
jz @F
call ShowIcons
@@:
jmp PassThrough
.elseif dword ptr(NMHDR ptr [eax]).code == CDN_FILEOK
invoke PathFindExtension, offset DlgFilePath
invoke Cmpi, eax, offset szExtIco
.if eax == 0
; Icon was selected, show 32 and 16 sizes
invoke LoadImage, NULL, offset DlgFilePath, IMAGE_ICON, 32, 32, LR_LOADFROMFILE
push eax
invoke SendMessage, hImg32, STM_SETICON, eax, 0
invoke DestroyIcon, eax
pop eax
invoke CopyImage, eax, IMAGE_ICON, 16, 16, LR_COPYFROMRESOURCE
invoke SendMessage, hImg16, STM_SETICON, eax, 0
invoke DestroyIcon, eax
; close the dialog
invoke SetWindowLong, hWin, DWL_MSGRESULT, FALSE
.else
; not an ico file, leave dialog open
invoke SetWindowLong, hWin, DWL_MSGRESULT, TRUE
.endif
.else
jmp PassThrough
.endif
.endif
.elseif eax==WM_CLOSE
invoke ImageList_Destroy, himlDlg
invoke DestroyWindow, hWin
.else
PassThrough:
mov eax, FALSE
ret
.endif
mov eax, TRUE
ret
DlgHook endp
WM_INITDIALOG
We create an Image List for our List view, and get the parent of our child dialog which is the Open Dialog.
Next I hide the Ok button and file name static and edit controls, and move the file type static and combo, and cancel buttons up.
WM_NOTIFY
This is where the fun happens! We check wParam to see where the message is from, if it is from our listview we check to see if the message is LVN_CHANGING, if it is, we then check the state of the item (this way we know something was selected) if an item is selected we:
Get the icon from the image list using the index of the listview item, then we take that icon and display it in our 32x32 and 16x16 controls on our main dialog and then close the open dialog. If it is not of those messages, we pass them on so the OS can handle them.
If wParam isn't our listview ID, then it must be from the Open dialog. We are interested in CDN_SELCHANGE and CDN_FILEOK otherwise we pass the message on to the OS.
CDN_SELCHANGE
We send the message CDM_GETFILEPATH telling the open dialog that we want the path of the selected item in explorers listview, then we get the extenstion and check to see if it is .ico and if it is pass CDM_GETFILEPATH on. If it is not .ico, we process and show the icons with ShowIcon and EnumResNamesProc.
CDN_FILEOK
Here we check to see if the extension is ico, and if it is we load the icon and display it then close the open dialog with: invoke SetWindowLong, hWin, DWL_MSGRESULT, FALSE if the extension is not .ico we keep the open dialog open with: invoke SetWindowLong, hWin, DWL_MSGRESULT, TRUE
ShowIcons proc
LOCAL hLib:DWORD
; Clear imagelist
invoke ImageList_Remove, himlDlg, -1
; Clear listview
invoke SendMessage, hLVDlg, LVM_DELETEALLITEMS, 0, 0
; is the path a directory? If yes, leave
invoke PathIsDirectory, offset DlgFilePath
test eax, eax
jnz Done
; Get icon count
invoke ExtractIcon, hInst, offset DlgFilePath, -1
test eax, eax
jnz @F
invoke SetDlgItemInt, hMainDlg, 2002, eax, FALSE
jmp Done
@@:
invoke SetDlgItemInt, hMainDlg, 2002, eax, FALSE
; We have icons! load the file
invoke LoadLibraryEx, offset DlgFilePath, 0, LOAD_LIBRARY_AS_DATAFILE
test eax, eax
jz Done
mov hLib, eax
; Now get all the icon names
invoke EnumResourceNames, eax, RT_GROUP_ICON, offset EnumResNamesProc, 0
invoke FreeLibrary, hLib
Done:
ret
ShowIcons endp
We made it here, so the file is not an ico file but an executable. First thing we do is delete all icons from the image list and listview.
Then we check to see if the selected item is a directory, if it is we leave, otherwise we get the count of icons in the file, we do that by passing a -1 to ExtractIcon, if the count is 0, we display 0 for our total and leave. Otherwise we display the total and use LoadLibraryEx with the flag - LOAD_LIBRARY_AS_DATAFILE, what that does well what it doesn't do is "execute" the dll, instead it loads the file as it were a data file.
We then pass the returned handle to EnumResourceNames and the address of our callback proc
invoke EnumResourceNames, eax, RT_GROUP_ICON, offset EnumResNamesProc, 0
What EnumResourceNames will do is, enumerate all resources of RT_GROUP_ICON call our callback proc with either the string name or ordinal of the icon.
EnumResNamesProc proc uses esi hModule:DWORD,lpszType:DWORD, lpszName:DWORD, lParam:DWORD
LOCAL IconTemp:DWORD
LOCAL LVParam:DWORD
invoke LoadImage, hModule, lpszName, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR
mov IconTemp, eax
invoke ImageList_ReplaceIcon, himlDlg, -1, IconTemp
invoke DestroyIcon, IconTemp
invoke ImageList_GetImageCount, himlDlg
sub eax, 1
mov lvi.imask, LVIF_IMAGE or LVIF_TEXT
mov lvi.iItem, eax
mov lvi.iSubItem, 0
mov lvi.iImage, eax
invoke HeapAlloc, hMainHeap, HEAP_ZERO_MEMORY, 50
mov LVParam, eax
invoke memfill, LVParam, 50, 0
invoke IS_INTRESOURCE, lpszName
test eax, eax
jz @F
invoke StrLen, lpszName
invoke MemCopy, lpszName, LVParam, eax
jmp Continue
@@:
invoke dwtoa, lpszName, LVParam
Continue:
mov eax, LVParam
mov lvi.pszText, eax
invoke SendMessage, hLVDlg, LVM_INSERTITEM, 0, addr lvi
invoke HeapFree, hMainHeap, 0, LVParam
mov eax, TRUE
ret
EnumResNamesProc endp
Lines 4 - 14 we load the current icon and add it to the image list and add it to the LVITEM structure.
Line 20, we check to see if the icon resource name is either a string or ordinal. If ordinal we convert it to a string. Then we add it to our listview.
Put it all together and we have:

Modify, experiment and have fun with MASM Assembly!
App and complete source attached.
Attached File(s)
-
Custom Open File Dialog.zip (7.47K)
Number of downloads: 121







MultiQuote


|