Use DrawFrameControl instead of bitmaps in certain cases.
[wine] / dlls / commdlg / filedlg95.c
1 /*
2  * COMMDLG - File Open Dialogs Win95 look and feel
3  *
4  * FIXME: The whole concept of handling unicode is badly broken.
5  *      many hook-messages expecting a pointer to a
6  *      OPENFILENAMEA or W structure. With the current architecture
7  *      we would have to convert the beast at every call to a hook.
8  *      we have to find a better solution but if would likely cause
9  *      a complete rewrite with after we shouldhandle the
10  *      OPENFILENAME structure without any converting (jsch).
11  *
12  * FIXME: any hook gets a OPENFILENAMEA structure
13  *
14  * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too
15  *
16  * FIXME: old style hook messages are not implemented (except FILEOKSTRING)
17  *
18  * FIXME: lpstrCustomFilter not handled
19  *
20  * FIXME: if the size of lpstrFile (nMaxFile) is too small the first
21  * two bytes of lpstrFile should contain the needed size
22  *
23  * FIXME: algorithm for selecting the initial directory is too simple
24  *
25  * FIXME: add to recent docs
26  *
27  * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT,
28  * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING, OFN_EXTENSIONDIFFERENT,
29  * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN,
30  * OFN_NOTESTFILECREATE, OFN_OVERWRITEPROMPT, OFN_USEMONIKERS
31  *
32  * FIXME: lCustData for lpfnHook (WM_INITDIALOG)
33  *
34  *
35  */
36 #include <ctype.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40
41 #include "winbase.h"
42 #include "ntddk.h"
43 #include "winnls.h"
44 #include "wine/unicode.h"
45 #include "commdlg.h"
46 #include "dlgs.h"
47 #include "cdlg.h"
48 #include "debugtools.h"
49 #include "cderr.h"
50 #include "shellapi.h"
51 #include "shlguid.h"
52 #include "filedlgbrowser.h"
53 #include "shlwapi.h"
54 #include "wine/obj_contextmenu.h"
55
56 DEFAULT_DEBUG_CHANNEL(commdlg);
57
58 #define UNIMPLEMENTED_FLAGS \
59 (OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\
60 OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING | OFN_EXTENSIONDIFFERENT |\
61 OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\
62 OFN_NOTESTFILECREATE | OFN_OVERWRITEPROMPT /*| OFN_USEMONIKERS*/)
63
64 #define IsHooked(fodInfos) \
65         ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook)
66 /***********************************************************************
67  * Data structure and global variables
68  */
69 typedef struct SFolder
70 {
71   int m_iImageIndex;    /* Index of picture in image list */
72   HIMAGELIST hImgList;
73   int m_iIndent;      /* Indentation index */
74   LPITEMIDLIST pidlItem;  /* absolute pidl of the item */ 
75
76 } SFOLDER,*LPSFOLDER;
77
78 typedef struct tagLookInInfo
79 {
80   int iMaxIndentation;
81   UINT uSelectedItem;
82 } LookInInfos;
83
84
85 /***********************************************************************
86  * Defines and global variables
87  */
88
89 /* Draw item constant */
90 #define ICONWIDTH 18
91 #define XTEXTOFFSET 3
92
93 /* AddItem flags*/
94 #define LISTEND -1
95
96 /* SearchItem methods */
97 #define SEARCH_PIDL 1
98 #define SEARCH_EXP  2
99 #define ITEM_NOTFOUND -1
100
101 /* Undefined windows message sent by CreateViewObject*/
102 #define WM_GETISHELLBROWSER  WM_USER+7
103
104 /* NOTE
105  * Those macros exist in windowsx.h. However, you can't really use them since
106  * they rely on the UNICODE defines and can't be used inside Wine itself.
107  */
108
109 /* Combo box macros */
110 #define CBAddString(hwnd,str) \
111   SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str);
112
113 #define CBInsertString(hwnd,str,pos) \
114   SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str);
115
116 #define CBDeleteString(hwnd,pos) \
117   SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0);
118
119 #define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \
120   SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr);
121
122 #define CBGetItemDataPtr(hwnd,iItemId) \
123   SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0)
124
125 #define CBGetLBText(hwnd,iItemId,str) \
126   SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str);
127
128 #define CBGetCurSel(hwnd) \
129   SendMessageA(hwnd,CB_GETCURSEL,0,0);
130
131 #define CBSetCurSel(hwnd,pos) \
132   SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0);
133
134 #define CBGetCount(hwnd) \
135     SendMessageA(hwnd,CB_GETCOUNT,0,0);
136 #define CBShowDropDown(hwnd,show) \
137   SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0);
138 #define CBSetItemHeight(hwnd,index,height) \
139   SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height);
140
141
142 const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */
143 const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */
144
145 static const char defaultFilter[] = "*.*";
146
147 /***********************************************************************
148  * Prototypes
149  */
150
151 /* Internal functions used by the dialog */
152 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam);
153 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam);
154 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd);
155        BOOL    FILEDLG95_OnOpen(HWND hwnd);
156 static LRESULT FILEDLG95_InitControls(HWND hwnd);
157 static void    FILEDLG95_Clean(HWND hwnd);
158
159 /* Functions used by the shell navigation */
160 static LRESULT FILEDLG95_SHELL_Init(HWND hwnd);
161 static BOOL    FILEDLG95_SHELL_UpFolder(HWND hwnd);
162 static BOOL    FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb);
163 static void    FILEDLG95_SHELL_Clean(HWND hwnd);
164 static BOOL    FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd);
165
166 /* Functions used by the filetype combo box */
167 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd);
168 static BOOL    FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode);
169 static int     FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCSTR lpstrExt);
170 static void    FILEDLG95_FILETYPE_Clean(HWND hwnd);
171
172 /* Functions used by the Look In combo box */
173 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo);
174 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct);
175 static BOOL    FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode);
176 static int     FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId);
177 static int     FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod);
178 static int     FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl);
179 static int     FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd);
180        int     FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl);
181 static void    FILEDLG95_LOOKIN_Clean(HWND hwnd);
182
183 /* Miscellaneous tool functions */
184 HRESULT       GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName);
185 HRESULT       GetFileName(HWND hwnd, LPITEMIDLIST pidl, LPSTR lpstrFileName);
186 IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs);
187 LPITEMIDLIST  GetParentPidl(LPITEMIDLIST pidl);
188 LPITEMIDLIST  GetPidlFromName(IShellFolder *psf,LPCSTR lpcstrFileName);
189
190 /* Shell memory allocation */
191 static void *MemAlloc(UINT size);
192 static void MemFree(void *mem);
193
194 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos);
195 HRESULT WINAPI FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
196 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode);
197 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
198 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPSTR lpstrFileList, UINT nFileCount, UINT sizeUsed);
199 static BOOL BrowseSelectedFolder(HWND hwnd);
200
201 /***********************************************************************
202  *      GetFileName95
203  *
204  * Creates an Open common dialog box that lets the user select 
205  * the drive, directory, and the name of a file or set of files to open.
206  *
207  * IN  : The FileOpenDlgInfos structure associated with the dialog
208  * OUT : TRUE on success
209  *       FALSE on cancel, error, close or filename-does-not-fit-in-buffer.
210  */
211 BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos)
212 {
213
214     LRESULT lRes;
215     LPCVOID template;
216     HRSRC hRes;
217     HANDLE hDlgTmpl = 0;
218
219     /* test for missing functionality */
220     if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS)
221     {
222       FIXME("Flags 0x%08lx not yet implemented\n",
223          fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS);
224     }
225
226     /* Create the dialog from a template */
227
228     if(!(hRes = FindResourceA(COMMDLG_hInstance32,MAKEINTRESOURCEA(NEWFILEOPENORD),RT_DIALOGA)))
229     {
230         COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
231         return FALSE;
232     }
233     if (!(hDlgTmpl = LoadResource(COMMDLG_hInstance32, hRes )) ||
234         !(template = LockResource( hDlgTmpl )))
235     {
236         COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
237         return FALSE;
238     }
239     
240     /* old style hook messages */
241     if (IsHooked(fodInfos))
242     {
243       fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA);
244       fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA);
245       fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA);
246       fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA);
247     }
248     
249     lRes = DialogBoxIndirectParamA(COMMDLG_hInstance32,
250                                   (LPDLGTEMPLATEA) template,
251                                   fodInfos->ofnInfos->hwndOwner,
252                                   (DLGPROC) FileOpenDlgProc95,
253                                   (LPARAM) fodInfos);
254
255     /* Unable to create the dialog */
256     if( lRes == -1)
257         return FALSE;
258     
259     return lRes;
260 }
261
262 /***********************************************************************
263  *      GetFileDialog95A
264  *
265  * Call GetFileName95 with this structure and clean the memory.
266  *
267  * IN  : The OPENFILENAMEA initialisation structure passed to
268  *       GetOpenFileNameA win api function (see filedlg.c)
269  */
270 BOOL  WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType)
271 {
272
273   BOOL ret;
274   FileOpenDlgInfos *fodInfos;
275   HINSTANCE hInstance;
276   LPCSTR lpstrInitialDir = (LPCSTR)-1;
277   LPSTR lpstrSavDir = NULL;
278   DWORD dwFlags = 0;
279   
280   /* Initialize FileOpenDlgInfos structure */
281   fodInfos = (FileOpenDlgInfos*)MemAlloc(sizeof(FileOpenDlgInfos));
282   ZeroMemory(fodInfos, sizeof(FileOpenDlgInfos));
283   
284   /* Pass in the original ofn */
285   fodInfos->ofnInfos = ofn;
286   
287   /* Save original hInstance value */
288   hInstance = ofn->hInstance;
289   fodInfos->ofnInfos->hInstance = MapHModuleLS(ofn->hInstance);
290
291   /* save current directory */
292   if (ofn->Flags & OFN_NOCHANGEDIR)
293   {
294      lpstrSavDir = MemAlloc(MAX_PATH);
295      GetCurrentDirectoryA(MAX_PATH, lpstrSavDir);
296   }
297
298   dwFlags = ofn->Flags;
299   ofn->Flags = ofn->Flags|OFN_WINE;
300
301   /* Initialize the dialog property */
302   fodInfos->DlgInfos.dwDlgProp = 0;
303   fodInfos->DlgInfos.hwndCustomDlg = (HWND)NULL;
304   
305   switch(iDlgType)
306   {
307     case OPEN_DIALOG :
308       ret = GetFileName95(fodInfos);
309       break;
310     case SAVE_DIALOG :
311       fodInfos->DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
312       ret = GetFileName95(fodInfos);
313       break;
314     default :
315       ret = 0;
316   }
317
318   if (lpstrSavDir)
319   {
320       SetCurrentDirectoryA(lpstrSavDir);
321       MemFree(lpstrSavDir);
322   }
323
324   if (lpstrInitialDir != (LPCSTR)-1)
325   {
326     MemFree((LPVOID)(ofn->lpstrInitialDir));
327     ofn->lpstrInitialDir = lpstrInitialDir;
328   }
329
330   ofn->Flags = dwFlags;
331   ofn->hInstance = hInstance;
332   MemFree((LPVOID)(fodInfos));
333   return ret;
334 }
335
336 /***********************************************************************
337  *      GetFileDialog95W
338  *
339  * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure.
340  * Call GetFileName95 with this structure and clean the memory.
341  *
342  * FIXME: lpstrCustomFilter has to converted back
343  *
344  */
345
346 /* converting IN arguments */
347 #define AllocInArgWtoA(arg, save) \
348   if(arg) \
349   { \
350     DWORD _len = WideCharToMultiByte( CP_ACP, 0, arg, -1, NULL, 0, NULL, NULL ); \
351     save = arg; \
352     arg =  MemAlloc(_len); \
353     WideCharToMultiByte( CP_ACP, 0, save, -1, (LPSTR)arg, _len, NULL, NULL ); \
354   }
355
356 #define FreeInArg(arg, save) \
357   if(arg) \
358   { \
359     MemFree((LPSTR)arg); \
360     arg = save; \
361   }
362
363 /* converting OUT arguments */
364 #define AllocOutArgWtoA(arg, save, len) \
365   if(arg) \
366   { \
367     save = arg; \
368     arg = MemAlloc(len); \
369   }
370
371 #define FreeOutArg(arg, save, len) \
372   if(arg) \
373   { \
374     MultiByteToWideChar( CP_ACP, 0, (LPCSTR)(arg), -1, (save), (len) ); \
375     MemFree(arg); \
376     arg = save; \
377   }
378
379 BOOL  WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType)
380 {
381   BOOL ret;
382   FileOpenDlgInfos *fodInfos;
383   HINSTANCE hInstance;
384   
385   /* out arguments */
386   LPWSTR lpstrFile = NULL;
387   LPWSTR lpstrFileTitle = NULL;
388
389   /* in/out arguments */
390   LPWSTR lpstrCustomFilter = NULL;
391
392   /* input arguments */
393   LPCWSTR lpstrFilter = NULL;
394   LPCWSTR lpstrInitialDir = NULL;
395   LPCWSTR lpstrTitle = NULL;
396   LPCWSTR lpstrDefExt = NULL;
397   LPCWSTR lpTemplateName = NULL;
398   DWORD dwFlags;
399
400   /* Initialize FileOpenDlgInfos structure */
401   fodInfos = (FileOpenDlgInfos*)MemAlloc(sizeof(FileOpenDlgInfos));
402   ZeroMemory(fodInfos, sizeof(FileOpenDlgInfos));
403
404   /*  Pass in the original ofn */
405   fodInfos->ofnInfos = (LPOPENFILENAMEA) ofn;
406
407   /* convert lpstrFilter */
408   if (ofn->lpstrFilter)
409   {
410     LPCWSTR  s;
411     LPSTR y;
412     int n, len;
413
414     lpstrFilter = ofn->lpstrFilter;
415
416     /* filter is a list...  title\0ext\0......\0\0 */
417     s = ofn->lpstrFilter;
418     
419     while (*s) s = s+strlenW(s)+1;
420     s++;
421     n = s - ofn->lpstrFilter; /* already divides by 2. ptr magic */
422     len = WideCharToMultiByte( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0, NULL, NULL );
423     y = (LPSTR)MemAlloc(len);
424     WideCharToMultiByte( CP_ACP, 0, ofn->lpstrFilter, n, y, len, NULL, NULL );
425     (LPSTR)ofn->lpstrFilter = y;
426   }
427
428   /* convert lpstrCustomFilter */
429   if (ofn->lpstrCustomFilter)
430   {
431     LPWSTR  s;
432     LPSTR y;
433     int n, len;
434
435     lpstrCustomFilter = ofn->lpstrCustomFilter;
436     /* filter is a list...  title\0ext\0......\0\0 */
437     s = ofn->lpstrCustomFilter;
438     while (*s) s = s+strlenW(s)+1;
439     s++;
440     n = s - ofn->lpstrCustomFilter;
441     len = WideCharToMultiByte( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0, NULL, NULL );
442     y = (LPSTR)MemAlloc(len);
443     WideCharToMultiByte( CP_ACP, 0, ofn->lpstrCustomFilter, n, y, len, NULL, NULL );
444     (LPSTR)ofn->lpstrCustomFilter = y;
445   }
446
447   /* convert string arguments, save others */
448   AllocOutArgWtoA(ofn->lpstrFile, lpstrFile, ofn->nMaxFile);
449   AllocOutArgWtoA(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
450   AllocInArgWtoA(ofn->lpstrInitialDir, lpstrInitialDir);
451   AllocInArgWtoA(ofn->lpstrTitle, lpstrTitle);
452   AllocInArgWtoA(ofn->lpstrDefExt, lpstrDefExt);
453   AllocInArgWtoA(ofn->lpTemplateName, lpTemplateName);
454   dwFlags = ofn->Flags;
455   hInstance = ofn->hInstance;
456
457   ofn->Flags = ofn->Flags|OFN_WINE|OFN_UNICODE;
458   ofn->hInstance = MapHModuleLS(ofn->hInstance);
459
460   switch(iDlgType)
461   {
462   case OPEN_DIALOG :
463       ret = GetFileName95(fodInfos);
464       break;
465   case SAVE_DIALOG :
466       fodInfos->DlgInfos.dwDlgProp |= FODPROP_SAVEDLG;
467       ret = GetFileName95(fodInfos);
468       break;
469   default :
470       ret = 0;
471   }
472       
473   /* restore saved IN arguments and convert OUT arguments back */
474   ofn->Flags = dwFlags;
475   ofn->hInstance = hInstance;
476   FreeInArg(ofn->lpstrFilter, lpstrFilter);
477   FreeInArg(ofn->lpstrCustomFilter, lpstrCustomFilter);
478   FreeOutArg(ofn->lpstrFile, lpstrFile, ofn->nMaxFile);
479   FreeOutArg(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle);
480   FreeInArg(ofn->lpstrInitialDir, lpstrInitialDir);
481   FreeInArg(ofn->lpstrTitle, lpstrTitle);
482   FreeInArg(ofn->lpstrDefExt, lpstrDefExt);
483   FreeInArg(ofn->lpTemplateName, lpTemplateName);
484
485   MemFree((LPVOID)(fodInfos));
486   return ret;
487 }
488
489 void ArrangeCtrlPositions( HWND hwndChildDlg, HWND hwndParentDlg)
490 {
491     HWND hwndChild,hwndStc32;
492     RECT rectParent, rectChild, rectCtrl, rectStc32, rectTemp;
493     POINT ptMoveCtl;
494     POINT ptParentClient;
495
496     TRACE("\n");
497
498     ptMoveCtl.x = ptMoveCtl.y = 0;
499     hwndStc32=GetDlgItem(hwndChildDlg,stc32);
500     GetClientRect(hwndParentDlg,&rectParent);
501     GetClientRect(hwndChildDlg,&rectChild);
502
503     if(hwndStc32)
504     {
505       GetWindowRect(hwndStc32,&rectStc32);
506       MapWindowPoints(0, hwndChildDlg,(LPPOINT)&rectStc32,2);
507       CopyRect(&rectTemp,&rectStc32);
508
509       SetRect(&rectStc32,rectStc32.left,rectStc32.top,rectStc32.left + (rectParent.right-rectParent.left),rectStc32.top+(rectParent.bottom-rectParent.top));
510       SetWindowPos(hwndStc32,0,rectStc32.left,rectStc32.top,rectStc32.right-rectStc32.left,rectStc32.bottom-rectStc32.top,SWP_NOMOVE|SWP_NOZORDER | SWP_NOACTIVATE);
511
512       if(rectStc32.right < rectTemp.right)
513       {
514         ptParentClient.x = max((rectParent.right-rectParent.left),(rectChild.right-rectChild.left));
515         ptMoveCtl.x = 0;
516       }
517       else
518       {
519         ptMoveCtl.x = (rectStc32.right - rectTemp.right);
520         ptParentClient.x = max((rectParent.right-rectParent.left),((rectChild.right-rectChild.left)+rectStc32.right-rectTemp.right));
521       }
522
523       if(rectStc32.bottom < rectTemp.bottom)
524       {
525         ptParentClient.y = max((rectParent.bottom-rectParent.top),(rectChild.bottom-rectChild.top));
526         ptMoveCtl.y = 0;
527       }
528       else
529       {
530         ptMoveCtl.y = (rectStc32.bottom - rectTemp.bottom);
531         ptParentClient.y = max((rectParent.bottom-rectParent.top),((rectChild.bottom-rectChild.top)+rectStc32.bottom-rectTemp.bottom));
532       }
533     }
534     else
535     {
536       if( (GetWindow(hwndChildDlg,GW_CHILD)) == (HWND) NULL) return;
537
538       SetRectEmpty(&rectTemp);
539       ptParentClient.x = max((rectParent.right-rectParent.left),(rectChild.right-rectChild.left));
540       ptParentClient.y = (rectParent.bottom-rectParent.top) + (rectChild.bottom-rectChild.top);
541       ptMoveCtl.y = rectParent.bottom-rectParent.top;
542       ptMoveCtl.x=0;
543     }
544     SetRect(&rectParent,rectParent.left,rectParent.top,rectParent.left+ptParentClient.x,rectParent.top+ptParentClient.y);
545     AdjustWindowRectEx( &rectParent,GetWindowLongA(hwndParentDlg,GWL_STYLE),FALSE,GetWindowLongA(hwndParentDlg,GWL_EXSTYLE));
546
547     SetWindowPos(hwndChildDlg, 0, 0,0, ptParentClient.x,ptParentClient.y, SWP_NOZORDER );
548     SetWindowPos(hwndParentDlg, 0, rectParent.left,rectParent.top, (rectParent.right- rectParent.left),
549         (rectParent.bottom-rectParent.top),SWP_NOMOVE | SWP_NOZORDER);
550         
551     hwndChild = GetWindow(hwndChildDlg,GW_CHILD);
552     if(hwndStc32)
553     {
554       GetWindowRect(hwndStc32,&rectStc32);
555       MapWindowPoints( 0, hwndChildDlg,(LPPOINT)&rectStc32,2);
556     }
557     else
558       SetRect(&rectStc32,0,0,0,0);
559
560     if (hwndChild )
561     {
562       do
563       {
564         if(hwndChild != hwndStc32)
565         {
566           if (GetWindowLongA( hwndChild, GWL_STYLE ) & WS_MAXIMIZE)
567                                 continue;
568           GetWindowRect(hwndChild,&rectCtrl);
569           MapWindowPoints( 0, hwndParentDlg,(LPPOINT)&rectCtrl,2);
570                                   
571           /*
572             Check the initial position of the controls relative to the initial
573             position and size of stc32 (before it is expanded).
574           */
575           if (rectCtrl.left >= rectTemp.right && rectCtrl.top >= rectTemp.bottom)
576           {
577             rectCtrl.left += ptMoveCtl.x;
578             rectCtrl.top  += ptMoveCtl.y;
579           }
580           else if (rectCtrl.left >= rectTemp.right)
581           {
582             rectCtrl.left += ptMoveCtl.x;
583           }
584           else if (rectCtrl.top >= rectTemp.bottom)
585           {
586             rectCtrl.top  += ptMoveCtl.y;
587           }
588                                         
589           SetWindowPos( hwndChild, 0, rectCtrl.left, rectCtrl.top, 
590                                 rectCtrl.right-rectCtrl.left,rectCtrl.bottom-rectCtrl.top,
591                                 SWP_NOSIZE | SWP_NOZORDER );
592         }
593       } while ((hwndChild=GetWindow( hwndChild, GW_HWNDNEXT )) != (HWND)NULL);
594     }
595     hwndChild = GetWindow(hwndParentDlg,GW_CHILD);
596         
597     if(hwndStc32)
598     {
599       GetWindowRect(hwndStc32,&rectStc32);
600       MapWindowPoints( 0, hwndChildDlg,(LPPOINT)&rectStc32,2);
601       ptMoveCtl.x = rectStc32.left - 0;
602       ptMoveCtl.y = rectStc32.top - 0;
603       if (hwndChild )
604       {
605         do
606         {
607           if(hwndChild != hwndChildDlg)
608           {
609             if (GetWindowLongA( hwndChild, GWL_STYLE ) & WS_MAXIMIZE)
610               continue;
611             GetWindowRect(hwndChild,&rectCtrl);
612             MapWindowPoints( 0, hwndParentDlg,(LPPOINT)&rectCtrl,2);
613
614             rectCtrl.left += ptMoveCtl.x;
615             rectCtrl.top += ptMoveCtl.y;
616
617             SetWindowPos( hwndChild, 0, rectCtrl.left, rectCtrl.top, 
618                 rectCtrl.right-rectCtrl.left,rectCtrl.bottom-rectCtrl.top,
619                 SWP_NOSIZE |SWP_NOZORDER );
620           }
621         } while ((hwndChild=GetWindow( hwndChild, GW_HWNDNEXT )) != (HWND)NULL);
622       }         
623     }
624 }
625
626
627 HRESULT WINAPI FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
628 {
629     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(GetParent(hwnd),FileOpenDlgInfosStr);
630
631 #if 0
632     TRACE("0x%04x\n", uMsg);
633 #endif
634
635     switch(uMsg)
636     {
637       case WM_INITDIALOG:
638       {         
639         fodInfos = (FileOpenDlgInfos *)lParam;
640         lParam = (LPARAM) fodInfos->ofnInfos;
641         ArrangeCtrlPositions(hwnd,GetParent(hwnd));
642
643         if(fodInfos && IsHooked(fodInfos))
644           return CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,hwnd,uMsg,wParam,lParam);
645         return 0;       
646       } 
647     }
648
649     if(fodInfos && IsHooked(fodInfos))
650       return CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,hwnd,uMsg,wParam,lParam); 
651
652     return DefWindowProcA(hwnd,uMsg,wParam,lParam); 
653 }
654
655 HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd)
656 {
657     LPCVOID template;
658     HRSRC hRes;
659     HANDLE hDlgTmpl = 0;
660     HWND hChildDlg = 0;
661
662     TRACE("\n");
663
664     if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATE ||
665         fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE)
666     {
667       if (fodInfos->ofnInfos->Flags  & OFN_ENABLETEMPLATEHANDLE)
668       {
669         if( !(template = LockResource( fodInfos->ofnInfos->hInstance)))
670         {
671           COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
672           return (HWND)NULL;
673         }
674       }
675       else
676       {
677         if (!(hRes = FindResourceA(MapHModuleSL(fodInfos->ofnInfos->hInstance),
678              (fodInfos->ofnInfos->lpTemplateName), RT_DIALOGA)))
679         {
680           COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE);
681           return (HWND)NULL;
682         }
683         if (!(hDlgTmpl = LoadResource( MapHModuleSL(fodInfos->ofnInfos->hInstance),
684              hRes )) || !(template = LockResource( hDlgTmpl )))
685         {
686           COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
687           return (HWND)NULL;
688         }
689       }
690
691       hChildDlg= CreateDialogIndirectParamA(fodInfos->ofnInfos->hInstance,template,hwnd,(DLGPROC)FileOpenDlgProcUserTemplate,(LPARAM)fodInfos);
692       if(hChildDlg)
693       {
694         ShowWindow(hChildDlg,SW_SHOW); 
695         return hChildDlg;
696       }
697     }
698     else if( IsHooked(fodInfos))
699     {
700       RECT rectHwnd;
701       struct  {
702          DLGTEMPLATE tmplate;
703          WORD menu,class,title;
704          } temp;
705       GetClientRect(hwnd,&rectHwnd);
706       temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS;
707       temp.tmplate.dwExtendedStyle = 0;
708       temp.tmplate.cdit = 0;
709       temp.tmplate.x = 0;
710       temp.tmplate.y = 0;
711       temp.tmplate.cx = rectHwnd.right-rectHwnd.left;
712       temp.tmplate.cy = rectHwnd.bottom-rectHwnd.top;
713       temp.menu = temp.class = temp.title = 0;
714       hChildDlg = CreateDialogIndirectParamA(fodInfos->ofnInfos->hInstance,&temp,
715                   hwnd,(DLGPROC)FileOpenDlgProcUserTemplate,(LPARAM)fodInfos);
716       return hChildDlg;
717     }
718     return (HWND)NULL;
719 }
720  
721 /***********************************************************************
722 *          SendCustomDlgNotificationMessage
723 *
724 * Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog
725 */
726
727 HRESULT SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode)
728 {
729     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr);
730
731     TRACE("0x%04x 0x%04x\n",hwndParentDlg, uCode);
732
733     if(!fodInfos) return 0;
734
735     if(fodInfos->ofnInfos->Flags & OFN_UNICODE)
736       FIXME("sending OPENFILENAMEA structure. Hook is expecting OPENFILENAMEW!\n");
737
738     if(fodInfos->DlgInfos.hwndCustomDlg)
739     {
740         OFNOTIFYA ofnNotify;
741         HRESULT ret;
742         ofnNotify.hdr.hwndFrom=hwndParentDlg;
743         ofnNotify.hdr.idFrom=0;
744         ofnNotify.hdr.code = uCode;
745         ofnNotify.lpOFN = fodInfos->ofnInfos;
746         TRACE("CALL NOTIFY for %x\n", uCode);
747         ret = SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify);
748         TRACE("RET NOTIFY\n");
749         return ret;
750     }
751     return TRUE;
752 }
753
754 /***********************************************************************
755 *         FILEDLG95_HandleCustomDialogMessages
756 *
757 * Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages
758 */
759 HRESULT FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
760 {
761     LPSTR lpstrFileSpec;
762     int reqSize;
763     char lpstrPath[MAX_PATH];
764     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
765     if(!fodInfos) return -1;
766
767     switch(uMsg)
768     {
769         case CDM_GETFILEPATH:
770             GetDlgItemTextA(hwnd,IDC_FILENAME,lpstrPath, sizeof(lpstrPath));
771             lpstrFileSpec = (LPSTR)PathFindFileNameA(lpstrPath);
772             if (lpstrFileSpec==lpstrPath) 
773             {
774                 char lpstrCurrentDir[MAX_PATH];
775                 /* Prepend the current path */
776                 SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrCurrentDir);
777                 if ((LPSTR)lParam!=NULL)
778                     snprintf((LPSTR)lParam,(int)wParam,"%s\\%s",lpstrCurrentDir,lpstrPath);
779                 reqSize=strlen(lpstrCurrentDir)+1+strlen(lpstrPath)+1;
780             } 
781             else 
782             {
783                 lstrcpynA((LPSTR)lParam,(LPSTR)lpstrPath,(int)wParam);
784                 reqSize=strlen(lpstrPath);
785             }
786             /* return the required buffer size */
787             return reqSize;
788
789         case CDM_GETFOLDERPATH:
790             SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent,lpstrPath);
791             if ((LPSTR)lParam!=NULL)
792                 lstrcpynA((LPSTR)lParam,lpstrPath,(int)wParam);
793             return strlen(lpstrPath);
794
795         case CDM_GETSPEC:
796             reqSize=GetDlgItemTextA(hwnd,IDC_FILENAME,lpstrPath, sizeof(lpstrPath));
797             lpstrFileSpec = (LPSTR)PathFindFileNameA(lpstrPath);
798             if ((LPSTR)lParam!=NULL)
799                 lstrcpynA((LPSTR)lParam, lpstrFileSpec, (int)wParam);
800             return strlen(lpstrFileSpec);
801
802         case CDM_SETCONTROLTEXT:
803             if ( 0 != lParam )
804                 SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam );
805             return TRUE;
806
807         case CDM_HIDECONTROL:
808         case CDM_SETDEFEXT:
809             FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n");
810             return -1;
811     }
812     return TRUE;
813 }
814  
815 /***********************************************************************
816  *          FileOpenDlgProc95
817  *
818  * File open dialog procedure
819  */
820 HRESULT WINAPI FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
821 {
822 #if 0
823   TRACE("0x%04x 0x%04x\n", hwnd, uMsg);
824 #endif
825   
826   switch(uMsg)
827   {
828     case WM_INITDIALOG:
829       {
830          FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam;
831
832          /* Adds the FileOpenDlgInfos in the property list of the dialog 
833             so it will be easily accessible through a GetPropA(...) */
834          SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos);
835
836          fodInfos->DlgInfos.hwndCustomDlg = 
837            CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd);
838
839          FILEDLG95_InitControls(hwnd);
840          SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE);
841          FILEDLG95_FillControls(hwnd, wParam, lParam);
842          SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE);
843          SetWindowPos(fodInfos->DlgInfos.hwndCustomDlg, HWND_BOTTOM,
844                       0,0,0,0, SWP_NOMOVE|SWP_NOSIZE);
845          return 0;
846        }
847     case WM_COMMAND:
848       return FILEDLG95_OnWMCommand(hwnd, wParam, lParam);
849     case WM_DRAWITEM:
850       {
851         switch(((LPDRAWITEMSTRUCT)lParam)->CtlID)
852         {
853         case IDC_LOOKIN:
854           FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam);
855           return TRUE;
856         }
857       }
858       return FALSE;
859           
860     case WM_GETISHELLBROWSER:
861       return FILEDLG95_OnWMGetIShellBrowser(hwnd);
862
863     case WM_DESTROY:
864       RemovePropA(hwnd, FileOpenDlgInfosStr);
865       return FALSE;
866
867     case WM_NOTIFY:
868     {
869         LPNMHDR lpnmh = (LPNMHDR)lParam;
870         UINT stringId = -1;
871
872         /* set up the button tooltips strings */
873         if(TTN_GETDISPINFOA == lpnmh->code )
874         {
875             LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam; 
876             switch(lpnmh->idFrom )
877             {
878                 /* Up folder button */
879                 case FCIDM_TB_UPFOLDER:
880                     stringId = IDS_UPFOLDER;
881                     break;
882                 /* New folder button */
883                 case FCIDM_TB_NEWFOLDER:
884                     stringId = IDS_NEWFOLDER;
885                     break;
886                 /* List option button */
887                 case FCIDM_TB_SMALLICON:
888                     stringId = IDS_LISTVIEW;
889                     break;
890                 /* Details option button */
891                 case FCIDM_TB_REPORTVIEW:
892                     stringId = IDS_REPORTVIEW;
893                     break;
894                 /* Desktop button */
895                 case FCIDM_TB_DESKTOP:
896                     stringId = IDS_TODESKTOP;
897                     break;
898                 default:
899                     stringId = 0;
900             }
901             lpdi->hinst = COMMDLG_hInstance32; 
902             lpdi->lpszText =  (LPSTR) stringId;
903         }
904         return FALSE;
905     }
906     default :
907       if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST)
908         return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam);
909       return FALSE;
910   }
911 }
912
913 /***********************************************************************
914  *      FILEDLG95_InitControls
915  *
916  * WM_INITDIALOG message handler (before hook notification)
917  */
918 static LRESULT FILEDLG95_InitControls(HWND hwnd)
919 {
920   TBBUTTON tbb[] =
921   {
922    {0,                 0,                   TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
923    {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER,   TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
924    {0,                 0,                   TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
925    {VIEW_NEWFOLDER+1,  FCIDM_TB_DESKTOP,    TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
926    {0,                 0,                   TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
927    {VIEW_NEWFOLDER,    FCIDM_TB_NEWFOLDER,  TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
928    {0,                 0,                   TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0 },
929    {VIEW_LIST,         FCIDM_TB_SMALLICON,  TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
930    {VIEW_DETAILS,      FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0 },
931   };
932   TBADDBITMAP tba[] =
933   {
934    { HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR },
935    { COMDLG32_hInstance, 800 }                  // desktop icon
936   };
937   
938   RECT rectTB;
939   
940   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
941
942   TRACE("%p\n", fodInfos);
943
944   /* Get the hwnd of the controls */
945   fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME);
946   fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE);
947   fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN);
948
949   /* construct the toolbar */
950   GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB);
951   MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2);
952
953   fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, (LPSTR) NULL, 
954         WS_CHILD | WS_GROUP | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE,
955         0, 0, 150, 26, hwnd, (HMENU) IDC_TOOLBAR, COMMDLG_hInstance32, NULL); 
956  
957   SetWindowPos(fodInfos->DlgInfos.hwndTB, 0, 
958         rectTB.left,rectTB.top, rectTB.right-rectTB.left, rectTB.bottom-rectTB.top,
959         SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER );
960
961   SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
962
963 /* fixme: use TB_LOADIMAGES when implemented */
964 /*  SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/
965   SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]);
966   SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]);
967
968   SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb);
969   SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0); 
970
971   /* Set the window text with the text specified in the OPENFILENAME structure */
972   if(fodInfos->ofnInfos->lpstrTitle)
973   {
974       SetWindowTextA(hwnd,fodInfos->ofnInfos->lpstrTitle);
975   }
976   else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
977   {
978       SetWindowTextA(hwnd,"Save");
979   }
980
981   /* Initialise the file name edit control */
982   if(fodInfos->ofnInfos->lpstrFile)
983   {
984       LPSTR lpstrFile = PathFindFileNameA(fodInfos->ofnInfos->lpstrFile);
985       SetDlgItemTextA(hwnd, IDC_FILENAME, lpstrFile);
986   }
987
988   /* Must the open as read only check box be checked ?*/
989   if(fodInfos->ofnInfos->Flags & OFN_READONLY)
990   {
991     SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0);
992   }
993
994   /* Must the open as read only check box be hid ?*/
995   if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY)
996   {
997     ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE);
998   }
999
1000   /* Must the help button be hid ?*/
1001   if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP))
1002   {
1003     ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE);
1004   }
1005
1006   /* Resize the height, if open as read only checkbox ad help button
1007      are hidden and we are not using a custom template */
1008   if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) &&
1009        (!(fodInfos->ofnInfos->Flags & 
1010          (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))))
1011   {
1012     RECT rectDlg, rectHelp, rectCancel;
1013     GetWindowRect(hwnd, &rectDlg);
1014     GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp);
1015     GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel);
1016     /* subtract the height of the help button plus the space between
1017        the help button and the cancel button to the height of the dialog */
1018     SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left, 
1019                  (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom), 
1020                  SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
1021   }
1022
1023   /* change Open to Save FIXME: use resources */
1024   if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG)
1025   {
1026       SetDlgItemTextA(hwnd,IDOK,"&Save");
1027       SetDlgItemTextA(hwnd,IDC_LOOKINSTATIC,"Save &in");
1028   }
1029   return 0;
1030 }
1031
1032 /***********************************************************************
1033  *      FILEDLG95_FillControls
1034  *
1035  * WM_INITDIALOG message handler (after hook notification)
1036  */
1037 static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam)
1038 {
1039   LPITEMIDLIST pidlItemId = NULL;
1040   
1041   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam;
1042
1043   TRACE("dir=%s file=%s\n", 
1044   fodInfos->ofnInfos->lpstrInitialDir, fodInfos->ofnInfos->lpstrFile);
1045
1046   /* Get the initial directory pidl */
1047
1048   if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->ofnInfos->lpstrInitialDir)))
1049   {
1050     char path[MAX_PATH];
1051
1052     GetCurrentDirectoryA(MAX_PATH,path);
1053     pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path);
1054   }
1055
1056   /* Initialise shell objects */
1057   FILEDLG95_SHELL_Init(hwnd);
1058
1059   /* Initialize the Look In combo box */
1060   FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB);
1061
1062   /* Initialize the filter combo box */
1063   FILEDLG95_FILETYPE_Init(hwnd);
1064
1065   /* Browse to the initial directory */
1066   IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE);
1067
1068   /* Free pidlItem memory */
1069   COMDLG32_SHFree(pidlItemId);
1070
1071   return TRUE;
1072 }
1073 /***********************************************************************
1074  *      FILEDLG95_Clean
1075  *
1076  * Regroups all the cleaning functions of the filedlg
1077  */
1078 void FILEDLG95_Clean(HWND hwnd)
1079 {
1080       FILEDLG95_FILETYPE_Clean(hwnd);
1081       FILEDLG95_LOOKIN_Clean(hwnd);
1082       FILEDLG95_SHELL_Clean(hwnd);
1083 }
1084 /***********************************************************************
1085  *      FILEDLG95_OnWMCommand
1086  *
1087  * WM_COMMAND message handler
1088  */
1089 static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam)
1090 {
1091   WORD wNotifyCode = HIWORD(wParam); /* notification code */
1092   WORD wID = LOWORD(wParam);         /* item, control, or accelerator identifier */
1093   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1094
1095   switch(wID)
1096   {
1097     /* OK button */
1098   case IDOK:
1099       if(FILEDLG95_OnOpen(hwnd))
1100         SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK);
1101     break;
1102     /* Cancel button */
1103   case IDCANCEL:
1104       FILEDLG95_Clean(hwnd);
1105       EndDialog(hwnd, FALSE);
1106     break;
1107     /* Filetype combo box */
1108   case IDC_FILETYPE:
1109     FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode);
1110     break;
1111     /* LookIn combo box */
1112   case IDC_LOOKIN:
1113     FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode);
1114     break;
1115
1116   /* --- toolbar --- */
1117     /* Up folder button */
1118   case FCIDM_TB_UPFOLDER:
1119     FILEDLG95_SHELL_UpFolder(hwnd);
1120     break;
1121     /* New folder button */
1122   case FCIDM_TB_NEWFOLDER:
1123     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDER);
1124     break;
1125     /* List option button */
1126   case FCIDM_TB_SMALLICON:
1127     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLIST);
1128     break;
1129     /* Details option button */
1130   case FCIDM_TB_REPORTVIEW:
1131     FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILS);
1132     break;
1133     /* Details option button */
1134   case FCIDM_TB_DESKTOP:
1135     FILEDLG95_SHELL_BrowseToDesktop(hwnd);
1136     break;
1137
1138   case IDC_FILENAME:
1139     break;
1140
1141   }
1142   /* Do not use the listview selection anymore */
1143   fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW;
1144   return 0; 
1145 }
1146
1147 /***********************************************************************
1148  *      FILEDLG95_OnWMGetIShellBrowser
1149  *
1150  * WM_GETISHELLBROWSER message handler
1151  */
1152 static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd)
1153 {
1154
1155   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1156
1157   TRACE("\n");
1158
1159   SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)fodInfos->Shell.FOIShellBrowser);
1160
1161   return TRUE; 
1162 }
1163
1164
1165 /***********************************************************************
1166  *      FILEDLG95_OnOpenMultipleFiles
1167  *      
1168  * Handles the opening of multiple files.
1169  *
1170  * FIXME
1171  *  check destination buffer size
1172  */
1173 BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPSTR lpstrFileList, UINT nFileCount, UINT sizeUsed)
1174 {
1175   CHAR   lpstrPathSpec[MAX_PATH] = "";
1176   LPSTR  lpstrFile;
1177   UINT   nCount, nSizePath;
1178   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1179
1180   TRACE("\n");
1181
1182   lpstrFile = fodInfos->ofnInfos->lpstrFile;
1183   lpstrFile[0] = '\0';
1184   
1185   SHGetPathFromIDListA( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec );
1186
1187   if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) &&
1188       ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST))
1189   {
1190     LPSTR lpstrTemp = lpstrFileList; 
1191
1192     for ( nCount = 0; nCount < nFileCount; nCount++ )
1193     {
1194       LPITEMIDLIST pidl;
1195
1196       pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp);
1197       if (!pidl)
1198       {
1199         CHAR lpstrNotFound[100];
1200         CHAR lpstrMsg[100];
1201         CHAR tmp[400];
1202
1203         LoadStringA(COMMDLG_hInstance32, IDS_FILENOTFOUND, lpstrNotFound, 100);
1204         LoadStringA(COMMDLG_hInstance32, IDS_VERIFYFILE, lpstrMsg, 100);
1205
1206         strcpy(tmp, lpstrTemp);
1207         strcat(tmp, "\n");
1208         strcat(tmp, lpstrNotFound);
1209         strcat(tmp, "\n");
1210         strcat(tmp, lpstrMsg);
1211
1212         MessageBoxA(hwnd, tmp, fodInfos->ofnInfos->lpstrTitle, MB_OK | MB_ICONEXCLAMATION);
1213         return FALSE;
1214       }
1215   
1216       /* move to the next file in the list of files */
1217       lpstrTemp += strlen(lpstrTemp) + 1;
1218       COMDLG32_SHFree(pidl);
1219     }
1220   }
1221
1222   nSizePath = strlen(lpstrPathSpec);
1223   strcpy( lpstrFile, lpstrPathSpec);
1224   memcpy( lpstrFile + nSizePath + 1, lpstrFileList, sizeUsed );
1225
1226   fodInfos->ofnInfos->nFileOffset = nSizePath + 1;
1227   fodInfos->ofnInfos->nFileExtension = 0;
1228
1229   /* clean and exit */
1230   FILEDLG95_Clean(hwnd);
1231   return EndDialog(hwnd,TRUE);
1232 }
1233
1234 /***********************************************************************
1235  *      FILEDLG95_OnOpen
1236  *
1237  * Ok button WM_COMMAND message handler
1238  * 
1239  * If the function succeeds, the return value is nonzero.
1240  */
1241 #define ONOPEN_BROWSE 1
1242 #define ONOPEN_OPEN   2
1243 #define ONOPEN_SEARCH 3
1244 static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText)
1245 {
1246   char strMsgTitle[MAX_PATH];
1247   char strMsgText [MAX_PATH];
1248   if (idCaption)
1249     LoadStringA(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle));
1250   else
1251     strMsgTitle[0] = '\0';
1252   LoadStringA(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText));
1253   MessageBoxA(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND);
1254 }
1255
1256 BOOL FILEDLG95_OnOpen(HWND hwnd)
1257 {
1258   char * lpstrFileList;
1259   UINT nFileCount = 0;
1260   UINT sizeUsed = 0;
1261   BOOL ret = TRUE;
1262   char lpstrPathAndFile[MAX_PATH];
1263   char lpstrTemp[MAX_PATH];
1264   LPSHELLFOLDER lpsf = NULL;
1265   int nOpenAction;
1266   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1267
1268   TRACE("hwnd=0x%04x\n", hwnd);
1269
1270   /* get the files from the edit control */
1271   nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed);
1272
1273   /* try if the user selected a folder in the shellview */
1274   if(nFileCount == 0)
1275   {
1276       BrowseSelectedFolder(hwnd);
1277       return FALSE;
1278   }
1279  
1280   if(nFileCount > 1)
1281   {
1282       ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed);
1283       goto ret;
1284   }
1285
1286   TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, lpstrFileList);
1287
1288 /*
1289   Step 1:  Build a complete path name from the current folder and
1290   the filename or path in the edit box.
1291   Special cases:
1292   - the path in the edit box is a root path
1293     (with or without drive letter)
1294   - the edit box contains ".." (or a path with ".." in it)
1295 */
1296
1297   /* Get the current directory name */
1298   if (!SHGetPathFromIDListA(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile))
1299   {
1300     /* we are in a special folder, default to desktop */
1301     if(FAILED(COMDLG32_SHGetFolderPathA(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, lpstrPathAndFile)))
1302     {
1303       /* last fallback */
1304       GetCurrentDirectoryA(MAX_PATH, lpstrPathAndFile);
1305     }
1306   }
1307   PathAddBackslashA(lpstrPathAndFile);
1308
1309   TRACE("current directory=%s\n", lpstrPathAndFile);
1310
1311   /* if the user specifyed a fully qualified path use it */
1312   if(PathIsRelativeA(lpstrFileList))
1313   {
1314     strcat(lpstrPathAndFile, lpstrFileList);
1315   }
1316   else
1317   {
1318     /* does the path have a drive letter? */
1319     if (PathGetDriveNumberA(lpstrFileList) == -1)
1320       strcpy(lpstrPathAndFile+2, lpstrFileList);
1321     else
1322       strcpy(lpstrPathAndFile, lpstrFileList);
1323   }
1324
1325   /* resolve "." and ".." */
1326   PathCanonicalizeA(lpstrTemp, lpstrPathAndFile );
1327   strcpy(lpstrPathAndFile, lpstrTemp);
1328   TRACE("canon=%s\n", lpstrPathAndFile);
1329
1330   MemFree(lpstrFileList);
1331
1332 /*
1333   Step 2: here we have a cleaned up path
1334
1335   We have to parse the path step by step to see if we have to browse
1336   to a folder if the path points to a directory or the last
1337   valid element is a directory.
1338   
1339   valid variables:
1340     lpstrPathAndFile: cleaned up path
1341  */
1342
1343   nOpenAction = ONOPEN_BROWSE;
1344
1345   /* dont apply any checks with OFN_NOVALIDATE */
1346   if(!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE))
1347   {
1348     LPSTR lpszTemp, lpszTemp1;
1349     LPITEMIDLIST pidl = NULL;
1350
1351     /* check for invalid chars */
1352     if(strpbrk(lpstrPathAndFile+3, "/:<>|") != NULL)
1353     {
1354       FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME);
1355       ret = FALSE;
1356       goto ret;
1357     }
1358
1359     if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE;
1360   
1361     lpszTemp1 = lpszTemp = lpstrPathAndFile;
1362     while (lpszTemp1)
1363     {
1364       LPSHELLFOLDER lpsfChild;
1365       WCHAR lpwstrTemp[MAX_PATH];
1366       DWORD dwEaten, dwAttributes;
1367
1368       lpszTemp = PathFindNextComponentA(lpszTemp);
1369
1370       if (!lpszTemp) break; /* end of path */
1371
1372       if(*lpszTemp)
1373       {
1374           DWORD len = MultiByteToWideChar( CP_ACP, 0, lpszTemp1, lpszTemp - lpszTemp1,
1375                                            lpwstrTemp, MAX_PATH );
1376           lpwstrTemp[len] = 0;
1377       }
1378       else
1379       {
1380           MultiByteToWideChar( CP_ACP, 0, lpszTemp1, -1,
1381                                lpwstrTemp, sizeof(lpwstrTemp)/sizeof(WCHAR) );
1382
1383         /* if the last element is a wildcard do a search */
1384         if(strpbrk(lpszTemp1, "*?") != NULL)
1385         {
1386           nOpenAction = ONOPEN_SEARCH;
1387           break;
1388         }
1389       }
1390       lpszTemp1 = lpszTemp;
1391
1392       TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_a(lpszTemp), lpsf);
1393
1394       if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp);
1395
1396       dwAttributes = SFGAO_FOLDER;
1397       if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes)))
1398       {
1399         /* the path component is valid, we have a pidl of the next path component */
1400         TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl);
1401         if(dwAttributes & SFGAO_FOLDER)
1402         {
1403           if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild)))
1404           {
1405             ERR("bind to failed\n"); /* should not fail */
1406             break;
1407           }
1408           IShellFolder_Release(lpsf);
1409           lpsf = lpsfChild;
1410           lpsfChild = NULL;
1411         }
1412         else
1413         {
1414           TRACE("value\n");
1415
1416           /* end dialog, return value */
1417           nOpenAction = ONOPEN_OPEN;
1418           break;
1419         }
1420         COMDLG32_SHFree(pidl);
1421         pidl = NULL;
1422       }
1423       else
1424       {
1425         if(*lpszTemp)   /* points to trailing null for last path element */
1426         {
1427           if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST)
1428           {
1429             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING);
1430             break;
1431           }
1432         }
1433         else
1434         {
1435           if(fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST)
1436           {
1437             FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING);
1438             break;
1439           }
1440         }
1441         /* change to the current folder */
1442         nOpenAction = ONOPEN_OPEN;
1443         break;
1444       }
1445     }
1446     if(pidl) COMDLG32_SHFree(pidl);
1447   }
1448
1449 /*
1450   Step 3: here we have a cleaned up and validated path
1451
1452   valid variables:
1453    lpsf:             ShellFolder bound to the rightmost valid path component
1454    lpstrPathAndFile: cleaned up path
1455    nOpenAction:      action to do
1456 */
1457   TRACE("end validate sf=%p\n", lpsf);
1458
1459   switch(nOpenAction)
1460   {
1461     case ONOPEN_SEARCH:   /* set the current filter to the file mask and refresh */
1462       TRACE("ONOPEN_SEARCH %s\n", lpstrPathAndFile);
1463       {
1464         int iPos;
1465         LPSTR lpszTemp = PathFindFileNameA(lpstrPathAndFile);
1466         DWORD len;
1467
1468         /* replace the current filter */
1469         if(fodInfos->ShellInfos.lpstrCurrentFilter)
1470           MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1471         len = MultiByteToWideChar( CP_ACP, 0, lpszTemp, -1, NULL, 0 );
1472         fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR));
1473         MultiByteToWideChar( CP_ACP, 0, lpszTemp, -1,
1474                              fodInfos->ShellInfos.lpstrCurrentFilter, len );
1475
1476         /* set the filter cb to the extension when possible */
1477         if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp)))
1478         CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos);
1479       }
1480       /* fall through */
1481     case ONOPEN_BROWSE:   /* browse to the highest folder we could bind to */
1482       TRACE("ONOPEN_BROWSE\n");
1483       {
1484         IPersistFolder2 * ppf2;
1485         if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2)))
1486         {
1487           LPITEMIDLIST pidlCurrent;
1488           IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent);
1489           IPersistFolder2_Release(ppf2);
1490           if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent))
1491           {
1492             IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE);
1493           }
1494           else if( nOpenAction == ONOPEN_SEARCH )
1495           {
1496             IShellView_Refresh(fodInfos->Shell.FOIShellView);
1497           }
1498           COMDLG32_SHFree(pidlCurrent);
1499         }
1500       }
1501       ret = FALSE;
1502       break;
1503     case ONOPEN_OPEN:   /* fill in the return struct and close the dialog */
1504       TRACE("ONOPEN_OPEN %s\n", lpstrPathAndFile);
1505       {
1506         /* add default extension */
1507         if (fodInfos->ofnInfos->lpstrDefExt)
1508         {
1509           if (! *PathFindExtensionA(lpstrPathAndFile))
1510           {
1511             /* only add "." in case a default extension does exist */
1512             if (*fodInfos->ofnInfos->lpstrDefExt != '\0')
1513             {
1514                 strcat(lpstrPathAndFile, ".");
1515                 strcat(lpstrPathAndFile, fodInfos->ofnInfos->lpstrDefExt);
1516             }
1517           }
1518         }
1519
1520         /* Check that the size of the file does not exceed buffer size.
1521              (Allow for extra \0 if OFN_MULTISELECT is set.) */
1522         if(strlen(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile -
1523             ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0))
1524         {
1525           LPSTR lpszTemp;
1526           
1527           /* fill destination buffer */
1528           strcpy(fodInfos->ofnInfos->lpstrFile, lpstrPathAndFile);
1529           if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)
1530             fodInfos->ofnInfos->lpstrFile[strlen(fodInfos->ofnInfos->lpstrFile)
1531                 + 1] = '\0';
1532
1533           /* set filename offset */
1534           lpszTemp = PathFindFileNameA(lpstrPathAndFile);
1535           fodInfos->ofnInfos->nFileOffset = lpszTemp - lpstrPathAndFile;
1536  
1537           /* set extension offset */
1538           lpszTemp = PathFindExtensionA(lpstrPathAndFile);
1539           fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? lpszTemp - lpstrPathAndFile + 1 : 0;
1540     
1541           /* set the lpstrFileTitle */
1542           if(fodInfos->ofnInfos->lpstrFileTitle)
1543           {
1544             LPSTR lpstrFileTitle = PathFindFileNameA(lpstrPathAndFile);
1545             strncpy(fodInfos->ofnInfos->lpstrFileTitle, lpstrFileTitle, fodInfos->ofnInfos->nMaxFileTitle);
1546           }
1547
1548           /* ask the hook if we can close */
1549           if(IsHooked(fodInfos))
1550           {
1551             /* FIXME we are sending ASCII-structures. Does not work with NT */
1552             /* first old style */
1553             TRACE("---\n");
1554             CallWindowProcA((WNDPROC)fodInfos->ofnInfos->lpfnHook,
1555                             fodInfos->DlgInfos.hwndCustomDlg,
1556                             fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos);
1557             if (GetWindowLongA(hwnd, DWL_MSGRESULT))
1558             {
1559               TRACE("cancled\n");
1560               ret = FALSE;
1561               goto ret;
1562             }
1563           }
1564
1565           TRACE("close\n");
1566           FILEDLG95_Clean(hwnd);
1567           ret = EndDialog(hwnd, TRUE);
1568         }
1569         else
1570         {
1571           /* FIXME set error FNERR_BUFFERTOSMALL */
1572           FILEDLG95_Clean(hwnd);
1573           ret = EndDialog(hwnd, FALSE);
1574         }
1575         goto ret;
1576       }
1577       break;
1578   }
1579
1580 ret:
1581   if(lpsf) IShellFolder_Release(lpsf);
1582   return ret;
1583 }
1584
1585 /***********************************************************************
1586  *      FILEDLG95_SHELL_Init
1587  *
1588  * Initialisation of the shell objects
1589  */
1590 static HRESULT FILEDLG95_SHELL_Init(HWND hwnd)
1591 {
1592   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1593
1594   TRACE("\n");
1595
1596   /*
1597    * Initialisation of the FileOpenDialogInfos structure 
1598    */
1599
1600   /* Shell */
1601
1602   /*ShellInfos */
1603   fodInfos->ShellInfos.hwndOwner = hwnd;
1604
1605   /* Disable multi-select if flag not set */
1606   if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT))
1607   {
1608      fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL; 
1609   }
1610   fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT;
1611   fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST;
1612
1613   GetWindowRect(GetDlgItem(hwnd,IDC_SHELLSTATIC),&fodInfos->ShellInfos.rectView);
1614   ScreenToClient(hwnd,(LPPOINT)&fodInfos->ShellInfos.rectView.left);
1615   ScreenToClient(hwnd,(LPPOINT)&fodInfos->ShellInfos.rectView.right);
1616
1617   /* Construct the IShellBrowser interface */
1618   fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd);  
1619     
1620   return NOERROR;
1621 }
1622
1623 /***********************************************************************
1624  *      FILEDLG95_SHELL_ExecuteCommand
1625  *
1626  * Change the folder option and refresh the view
1627  * If the function succeeds, the return value is nonzero.
1628  */
1629 static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb)
1630 {
1631   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1632
1633   IContextMenu * pcm;
1634   TRACE("(0x%08x,%p)\n", hwnd, lpVerb);
1635
1636   if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView,
1637                                         SVGIO_BACKGROUND,
1638                                         &IID_IContextMenu,
1639                                         (LPVOID*)&pcm)))
1640   {
1641     CMINVOKECOMMANDINFO ci;
1642     ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO));
1643     ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
1644     ci.lpVerb = lpVerb;
1645     ci.hwnd = hwnd;
1646
1647     IContextMenu_InvokeCommand(pcm, &ci);
1648     IContextMenu_Release(pcm);
1649   }
1650
1651   return FALSE;
1652 }
1653
1654 /***********************************************************************
1655  *      FILEDLG95_SHELL_UpFolder
1656  *
1657  * Browse to the specified object
1658  * If the function succeeds, the return value is nonzero.
1659  */
1660 static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd)
1661 {
1662   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1663
1664   TRACE("\n");
1665
1666   if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
1667                                           NULL,
1668                                           SBSP_PARENT)))
1669   {
1670     return TRUE;
1671   }
1672   return FALSE;
1673 }
1674
1675 /***********************************************************************
1676  *      FILEDLG95_SHELL_BrowseToDesktop
1677  *
1678  * Browse to the Desktop
1679  * If the function succeeds, the return value is nonzero.
1680  */
1681 static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd)
1682 {
1683   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1684   LPITEMIDLIST pidl;
1685   HRESULT hres;
1686   
1687   TRACE("\n");
1688
1689   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl);
1690   hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE);
1691   COMDLG32_SHFree(pidl);
1692   return SUCCEEDED(hres);
1693 }
1694 /***********************************************************************
1695  *      FILEDLG95_SHELL_Clean
1696  *
1697  * Cleans the memory used by shell objects
1698  */
1699 static void FILEDLG95_SHELL_Clean(HWND hwnd)
1700 {
1701     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1702
1703     TRACE("\n");
1704
1705     COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent);
1706
1707     /* clean Shell interfaces */
1708     IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView);
1709     IShellView_Release(fodInfos->Shell.FOIShellView);
1710     IShellFolder_Release(fodInfos->Shell.FOIShellFolder);
1711     IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser);
1712     if (fodInfos->Shell.FOIDataObject)
1713       IDataObject_Release(fodInfos->Shell.FOIDataObject);
1714 }
1715
1716 /***********************************************************************
1717  *      FILEDLG95_FILETYPE_Init
1718  *
1719  * Initialisation of the file type combo box 
1720  */
1721 static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd)
1722 {
1723   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1724
1725   TRACE("\n");
1726
1727   if(fodInfos->ofnInfos->lpstrFilter)
1728   {
1729     int nFilters = 0;   /* number of filters */
1730     LPSTR lpstrFilter;
1731     LPCSTR lpstrPos = fodInfos->ofnInfos->lpstrFilter;
1732
1733     for(;;)
1734     {
1735       /* filter is a list...  title\0ext\0......\0\0 
1736        * Set the combo item text to the title and the item data
1737        *  to the ext
1738        */
1739       LPCSTR lpstrDisplay;
1740       LPSTR lpstrExt;
1741
1742       /* Get the title */
1743       if(! *lpstrPos) break;    /* end */
1744       lpstrDisplay = lpstrPos;
1745       lpstrPos += strlen(lpstrPos) + 1;
1746
1747       /* Copy the extensions */
1748       if (! *lpstrPos) return E_FAIL;   /* malformed filter */
1749       if (!(lpstrExt = (LPSTR) MemAlloc(strlen(lpstrPos)+1))) return E_FAIL;
1750       strcpy(lpstrExt,lpstrPos);
1751       lpstrPos += strlen(lpstrPos) + 1;
1752             
1753       /* Add the item at the end of the combo */
1754       CBAddString(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay);
1755       CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt);
1756       nFilters++;
1757     }
1758     /*
1759      * Set the current filter to the one specified
1760      * in the initialisation structure
1761      * FIXME: lpstrCustomFilter not handled at all
1762      */
1763   
1764     /* set default filter index */
1765     if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->ofnInfos->lpstrCustomFilter == NULL)
1766       fodInfos->ofnInfos->nFilterIndex = 1;
1767
1768     /* First, check to make sure our index isn't out of bounds. */
1769     if ( fodInfos->ofnInfos->nFilterIndex > nFilters )
1770       fodInfos->ofnInfos->nFilterIndex = nFilters;
1771  
1772     /* Set the current index selection. */
1773     CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->ofnInfos->nFilterIndex-1);
1774   
1775     /* Get the corresponding text string from the combo box. */
1776     lpstrFilter = (LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1777                                              fodInfos->ofnInfos->nFilterIndex-1);
1778
1779     if ((INT)lpstrFilter == CB_ERR)  /* control is empty */
1780       lpstrFilter = NULL;       
1781
1782     if(lpstrFilter)
1783     {
1784       DWORD len;
1785       _strlwr(lpstrFilter);     /* lowercase */
1786       len = MultiByteToWideChar( CP_ACP, 0, lpstrFilter, -1, NULL, 0 );
1787       fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
1788       MultiByteToWideChar( CP_ACP, 0, lpstrFilter, -1,
1789                            fodInfos->ShellInfos.lpstrCurrentFilter, len );
1790     }
1791   }
1792   return NOERROR;
1793 }
1794
1795 /***********************************************************************
1796  *      FILEDLG95_FILETYPE_OnCommand
1797  *
1798  * WM_COMMAND of the file type combo box
1799  * If the function succeeds, the return value is nonzero.
1800  */
1801 static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode)
1802 {
1803   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1804
1805   switch(wNotifyCode)
1806   {
1807     case CBN_SELENDOK:
1808     {
1809       LPSTR lpstrFilter;
1810
1811       /* Get the current item of the filetype combo box */
1812       int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB);
1813
1814       /* set the current filter index - indexed from 1 */
1815       fodInfos->ofnInfos->nFilterIndex = iItem + 1;
1816
1817       /* Set the current filter with the current selection */
1818       if(fodInfos->ShellInfos.lpstrCurrentFilter)
1819          MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter);
1820
1821       lpstrFilter = (LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,
1822                                              iItem);
1823       if((int)lpstrFilter != CB_ERR)
1824       {
1825           DWORD len;
1826           _strlwr(lpstrFilter); /* lowercase */
1827           len = MultiByteToWideChar( CP_ACP, 0, lpstrFilter, -1, NULL, 0 );
1828           fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) );
1829           MultiByteToWideChar( CP_ACP, 0, lpstrFilter, -1,
1830                                fodInfos->ShellInfos.lpstrCurrentFilter, len );
1831           SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE);
1832       }
1833
1834       /* Refresh the actual view to display the included items*/
1835       IShellView_Refresh(fodInfos->Shell.FOIShellView);
1836     }
1837   }
1838   return FALSE;
1839 }
1840 /***********************************************************************
1841  *      FILEDLG95_FILETYPE_SearchExt
1842  *
1843  * searches for a extension in the filetype box
1844  */
1845 static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCSTR lpstrExt)
1846 {
1847   int i, iCount = CBGetCount(hwnd);
1848
1849   TRACE("%s\n", lpstrExt);
1850
1851   if(iCount != CB_ERR)
1852   {
1853     for(i=0;i<iCount;i++)
1854     {
1855       if(!strcasecmp(lpstrExt,(LPSTR)CBGetItemDataPtr(hwnd,i)))
1856           return i;
1857     }
1858   }
1859   return -1;
1860 }
1861
1862 /***********************************************************************
1863  *      FILEDLG95_FILETYPE_Clean
1864  *
1865  * Clean the memory used by the filetype combo box
1866  */
1867 static void FILEDLG95_FILETYPE_Clean(HWND hwnd)
1868 {
1869   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
1870   int iPos;
1871   int iCount = CBGetCount(fodInfos->DlgInfos.hwndFileTypeCB);
1872
1873   TRACE("\n");
1874
1875   /* Delete each string of the combo and their associated data */
1876   if(iCount != CB_ERR)
1877   {
1878     for(iPos = iCount-1;iPos>=0;iPos--)
1879     {
1880       MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos));
1881       CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos);
1882     }
1883   }
1884   /* Current filter */
1885   if(fodInfos->ShellInfos.lpstrCurrentFilter)
1886      MemFree(fodInfos->ShellInfos.lpstrCurrentFilter);
1887
1888 }
1889     
1890 /***********************************************************************
1891  *      FILEDLG95_LOOKIN_Init
1892  *
1893  * Initialisation of the look in combo box 
1894  */
1895 static HRESULT FILEDLG95_LOOKIN_Init(HWND hwndCombo)
1896 {
1897   IShellFolder  *psfRoot, *psfDrives;
1898   IEnumIDList   *lpeRoot, *lpeDrives;
1899   LPITEMIDLIST  pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp;
1900
1901   LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos));
1902
1903   TRACE("\n");
1904
1905   liInfos->iMaxIndentation = 0;
1906
1907   SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos);
1908
1909   /* set item height for both text field and listbox */
1910   CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON));
1911   CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON));
1912
1913   /* Initialise data of Desktop folder */
1914   SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp);
1915   FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
1916   COMDLG32_SHFree(pidlTmp);
1917
1918   SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives);
1919
1920   SHGetDesktopFolder(&psfRoot);
1921
1922   if (psfRoot)
1923   {
1924     /* enumerate the contents of the desktop */
1925     if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot)))
1926     {
1927       while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL))
1928       {
1929         FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND);
1930
1931         /* special handling for CSIDL_DRIVES */
1932         if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives))
1933         {
1934           if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives)))
1935           {
1936             /* enumerate the drives */
1937             if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives)))
1938             {
1939               while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL))
1940               {
1941                 pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1);
1942                 FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND);
1943                 COMDLG32_SHFree(pidlAbsTmp);
1944                 COMDLG32_SHFree(pidlTmp1);
1945               }
1946               IEnumIDList_Release(lpeDrives);
1947             }
1948             IShellFolder_Release(psfDrives);
1949           }
1950         }
1951         COMDLG32_SHFree(pidlTmp);
1952       }
1953       IEnumIDList_Release(lpeRoot);
1954     }
1955   }
1956
1957   IShellFolder_Release(psfRoot);
1958   COMDLG32_SHFree(pidlDrives);
1959   return NOERROR;
1960 }
1961
1962 /***********************************************************************
1963  *      FILEDLG95_LOOKIN_DrawItem
1964  *
1965  * WM_DRAWITEM message handler
1966  */
1967 static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct)
1968 {
1969   COLORREF crWin = GetSysColor(COLOR_WINDOW);
1970   COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT);
1971   COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);
1972   RECT rectText;
1973   RECT rectIcon;
1974   SHFILEINFOA sfi;
1975   HIMAGELIST ilItemImage;
1976   int iIndentation;
1977   TEXTMETRICA tm;
1978   LPSFOLDER tmpFolder;
1979
1980
1981   LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr);
1982
1983   TRACE("\n");
1984
1985   if(pDIStruct->itemID == -1)
1986     return 0;
1987
1988   if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem,
1989                             pDIStruct->itemID)))
1990     return 0;
1991
1992
1993   if(pDIStruct->itemID == liInfos->uSelectedItem)
1994   {
1995     ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
1996                                                0,    
1997                                                &sfi,    
1998                                                sizeof (SHFILEINFOA),   
1999                                                SHGFI_PIDL | SHGFI_SMALLICON |    
2000                                                SHGFI_OPENICON | SHGFI_SYSICONINDEX    | 
2001                                                SHGFI_DISPLAYNAME );   
2002   }
2003   else
2004   {
2005     ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2006                                                   0, 
2007                                                   &sfi, 
2008                                                   sizeof (SHFILEINFOA),
2009                                                   SHGFI_PIDL | SHGFI_SMALLICON | 
2010                                                   SHGFI_SYSICONINDEX | 
2011                                                   SHGFI_DISPLAYNAME);
2012   }
2013
2014   /* Is this item selected ? */
2015   if(pDIStruct->itemState & ODS_SELECTED)
2016   {
2017     SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText)));
2018     SetBkColor(pDIStruct->hDC,crHighLight);
2019     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
2020   }
2021   else
2022   {
2023     SetTextColor(pDIStruct->hDC,crText);
2024     SetBkColor(pDIStruct->hDC,crWin);
2025     FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW));
2026   }
2027
2028   /* Do not indent item if drawing in the edit of the combo */
2029   if(pDIStruct->itemState & ODS_COMBOBOXEDIT)
2030   {
2031     iIndentation = 0;
2032     ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem,
2033                                                 0, 
2034                                                 &sfi, 
2035                                                 sizeof (SHFILEINFOA), 
2036                                                 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON 
2037                                                 | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME  );
2038
2039   }
2040   else
2041   {
2042     iIndentation = tmpFolder->m_iIndent;
2043   }
2044   /* Draw text and icon */
2045
2046   /* Initialise the icon display area */
2047   rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation;
2048   rectIcon.top = pDIStruct->rcItem.top;
2049   rectIcon.right = rectIcon.left + ICONWIDTH;
2050   rectIcon.bottom = pDIStruct->rcItem.bottom;
2051
2052   /* Initialise the text display area */
2053   GetTextMetricsA(pDIStruct->hDC, &tm);
2054   rectText.left = rectIcon.right;
2055   rectText.top =
2056           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2;
2057   rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET;
2058   rectText.bottom =
2059           (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2;
2060  
2061   /* Draw the icon from the image list */
2062   ImageList_Draw(ilItemImage,
2063                  sfi.iIcon,
2064                  pDIStruct->hDC,  
2065                  rectIcon.left,  
2066                  rectIcon.top,  
2067                  ILD_TRANSPARENT );  
2068
2069   /* Draw the associated text */
2070   if(sfi.szDisplayName)
2071     TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName));
2072
2073
2074   return NOERROR;
2075 }
2076
2077 /***********************************************************************
2078  *      FILEDLG95_LOOKIN_OnCommand
2079  *
2080  * LookIn combo box WM_COMMAND message handler
2081  * If the function succeeds, the return value is nonzero.
2082  */
2083 static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode)
2084 {
2085   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2086
2087   TRACE("%p\n", fodInfos);
2088
2089   switch(wNotifyCode)
2090   {
2091     case CBN_SELENDOK:
2092     {
2093       LPSFOLDER tmpFolder;
2094       int iItem; 
2095
2096       iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB);
2097
2098       if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,
2099                                                iItem)))
2100         return FALSE;
2101
2102
2103       if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,
2104                                               tmpFolder->pidlItem,
2105                                               SBSP_ABSOLUTE)))
2106       {
2107         return TRUE;
2108       }
2109       break;
2110     }
2111       
2112   }
2113   return FALSE;
2114 }
2115
2116 /***********************************************************************
2117  *      FILEDLG95_LOOKIN_AddItem
2118  *
2119  * Adds an absolute pidl item to the lookin combo box
2120  * returns the index of the inserted item
2121  */
2122 static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId)
2123 {
2124   LPITEMIDLIST pidlNext;
2125   SHFILEINFOA sfi;
2126   SFOLDER *tmpFolder;
2127   LookInInfos *liInfos;
2128
2129   TRACE("%08x\n", iInsertId);
2130
2131   if(!pidl)
2132     return -1;
2133
2134   if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr)))
2135     return -1;
2136     
2137   tmpFolder = MemAlloc(sizeof(SFOLDER));
2138   tmpFolder->m_iIndent = 0;
2139
2140   /* Calculate the indentation of the item in the lookin*/
2141   pidlNext = pidl;
2142   while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) )
2143   {
2144     tmpFolder->m_iIndent++;
2145   }
2146
2147   tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl); /* FIXME: memory leak*/
2148
2149   if(tmpFolder->m_iIndent > liInfos->iMaxIndentation)
2150     liInfos->iMaxIndentation = tmpFolder->m_iIndent;
2151   
2152   sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
2153   SHGetFileInfoA((LPSTR)pidl,
2154                   0,
2155                   &sfi,
2156                   sizeof(sfi),
2157                   SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX 
2158                   | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED);
2159
2160   TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes);
2161
2162   if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM))
2163   {
2164     int iItemID;
2165   
2166     TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent);
2167
2168     /* Add the item at the end of the list */
2169     if(iInsertId < 0)
2170     {
2171       iItemID = CBAddString(hwnd,sfi.szDisplayName);
2172     }
2173     /* Insert the item at the iInsertId position*/
2174     else
2175     {
2176       iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId);
2177     }
2178
2179     CBSetItemDataPtr(hwnd,iItemID,tmpFolder);
2180     return iItemID;
2181   }
2182
2183   MemFree( tmpFolder );
2184   return -1;
2185
2186 }
2187
2188 /***********************************************************************
2189  *      FILEDLG95_LOOKIN_InsertItemAfterParent
2190  *
2191  * Insert an item below its parent 
2192  */
2193 static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl)
2194 {
2195   
2196   LPITEMIDLIST pidlParent = GetParentPidl(pidl);
2197   int iParentPos;
2198
2199   TRACE("\n");
2200
2201   iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL);
2202
2203   if(iParentPos < 0)
2204   {
2205     iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent);
2206   }
2207
2208   /* Free pidlParent memory */
2209   COMDLG32_SHFree((LPVOID)pidlParent);
2210
2211   return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1);
2212 }
2213
2214 /***********************************************************************
2215  *      FILEDLG95_LOOKIN_SelectItem
2216  *
2217  * Adds an absolute pidl item to the lookin combo box
2218  * returns the index of the inserted item
2219  */
2220 int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl)
2221 {
2222   int iItemPos;
2223   LookInInfos *liInfos;
2224
2225   TRACE("\n");
2226
2227   iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL);
2228
2229   liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2230
2231   if(iItemPos < 0)
2232   {
2233     while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1);
2234     iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl);
2235   }
2236
2237   else
2238   {
2239     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2240     while(liInfos->iMaxIndentation > tmpFolder->m_iIndent)
2241     {
2242       int iRemovedItem;
2243
2244       if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd)))
2245         break;
2246       if(iRemovedItem < iItemPos)
2247         iItemPos--;
2248     }
2249   }
2250   
2251   CBSetCurSel(hwnd,iItemPos);
2252   liInfos->uSelectedItem = iItemPos;
2253
2254   return 0;
2255
2256 }
2257
2258 /***********************************************************************
2259  *      FILEDLG95_LOOKIN_RemoveMostExpandedItem
2260  *
2261  * Remove the item with an expansion level over iExpansionLevel
2262  */
2263 static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd)
2264 {
2265   int iItemPos;
2266
2267   LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr);
2268
2269   TRACE("\n");
2270
2271   if(liInfos->iMaxIndentation <= 2)
2272     return -1;
2273
2274   if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0)
2275   {
2276     SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos);
2277     COMDLG32_SHFree(tmpFolder->pidlItem);
2278     MemFree(tmpFolder);
2279     CBDeleteString(hwnd,iItemPos);
2280     liInfos->iMaxIndentation--;
2281
2282     return iItemPos;
2283   }
2284
2285   return -1;
2286 }
2287
2288 /***********************************************************************
2289  *      FILEDLG95_LOOKIN_SearchItem
2290  *
2291  * Search for pidl in the lookin combo box
2292  * returns the index of the found item
2293  */
2294 static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod)
2295 {
2296   int i = 0;
2297   int iCount = CBGetCount(hwnd);
2298
2299   TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod);
2300
2301   if (iCount != CB_ERR)
2302   {
2303     for(;i<iCount;i++)
2304     {
2305       LPSFOLDER tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,i);
2306
2307       if(iSearchMethod == SEARCH_PIDL && COMDLG32_PIDL_ILIsEqual((LPITEMIDLIST)searchArg,tmpFolder->pidlItem))
2308         return i;
2309       if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg)
2310         return i;
2311     }
2312   }
2313
2314   return -1;
2315 }
2316
2317 /***********************************************************************
2318  *      FILEDLG95_LOOKIN_Clean
2319  *
2320  * Clean the memory used by the lookin combo box
2321  */
2322 static void FILEDLG95_LOOKIN_Clean(HWND hwnd)
2323 {
2324     FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2325     int iPos;
2326     int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB);
2327
2328     TRACE("\n");
2329
2330     /* Delete each string of the combo and their associated data */
2331     if (iCount != CB_ERR)
2332     {
2333       for(iPos = iCount-1;iPos>=0;iPos--)
2334       {
2335         SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos);
2336         COMDLG32_SHFree(tmpFolder->pidlItem);
2337         MemFree(tmpFolder);
2338         CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos);
2339       }
2340     }
2341
2342     /* LookInInfos structure */
2343     RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr);
2344
2345 }
2346 /***********************************************************************
2347  * FILEDLG95_FILENAME_FillFromSelection
2348  *
2349  * fills the edit box from the cached DataObject
2350  */
2351 void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd)
2352 {
2353     FileOpenDlgInfos *fodInfos;
2354     LPITEMIDLIST      pidl;
2355     UINT              nFiles = 0, nFileToOpen, nFileSelected, nLength = 0;
2356     char              lpstrTemp[MAX_PATH];
2357     LPSTR             lpstrAllFile = NULL, lpstrCurrFile = NULL;
2358
2359     TRACE("\n");
2360     fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2361
2362     /* Count how many files we have */
2363     nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject );
2364
2365     /* calculate the string length, count files */
2366     if (nFileSelected >= 1)
2367     {
2368       nLength += 3;     /* first and last quotes, trailing \0 */
2369       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2370       {
2371         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2372     
2373         if (pidl)
2374         {
2375           /* get the total length of the selected file names*/
2376           lpstrTemp[0] = '\0';
2377           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER, lpstrTemp );
2378
2379           if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */
2380           {
2381             nLength += strlen( lpstrTemp ) + 3;
2382             nFiles++;
2383           }
2384           COMDLG32_SHFree( pidl );
2385         }
2386       }
2387     }
2388
2389     /* allocate the buffer */
2390     if (nFiles <= 1) nLength = MAX_PATH;
2391     lpstrAllFile = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength);
2392     lpstrAllFile[0] = '\0';
2393
2394     /* Generate the string for the edit control */
2395     if(nFiles >= 1)
2396     {
2397       lpstrCurrFile = lpstrAllFile;
2398       for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ )
2399       {
2400         pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 );
2401
2402         if (pidl)
2403         {
2404           /* get the file name */
2405           lpstrTemp[0] = '\0';
2406           GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER, lpstrTemp );
2407
2408           if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */
2409           {
2410             if ( nFiles > 1)
2411             {
2412               *lpstrCurrFile++ =  '\"';
2413               strcpy( lpstrCurrFile, lpstrTemp );
2414               lpstrCurrFile += strlen( lpstrTemp );
2415               strcpy( lpstrCurrFile, "\" " );
2416               lpstrCurrFile += 2;
2417             }
2418             else
2419             {
2420               strcpy( lpstrAllFile, lpstrTemp );
2421             }
2422           }
2423           COMDLG32_SHFree( (LPVOID) pidl );
2424         }
2425       }
2426     }
2427
2428     SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile );
2429     HeapFree(GetProcessHeap(),0, lpstrAllFile );
2430 }
2431
2432
2433 /* copied from shell32 to avoid linking to it */
2434 static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl)
2435 {
2436         switch (src->uType)
2437         {
2438           case STRRET_WSTR:
2439             WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL);
2440             COMDLG32_SHFree(src->u.pOleStr);
2441             break;
2442
2443           case STRRET_CSTRA:
2444             lstrcpynA((LPSTR)dest, src->u.cStr, len);
2445             break;
2446
2447           case STRRET_OFFSETA:
2448             lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
2449             break;
2450
2451           default:
2452             FIXME("unknown type!\n");
2453             if (len)
2454             {
2455               *(LPSTR)dest = '\0';
2456             }
2457             return(FALSE);
2458         }
2459         return S_OK;
2460 }
2461
2462 /***********************************************************************
2463  * FILEDLG95_FILENAME_GetFileNames
2464  *
2465  * copies the filenames to a 0-delimited string list (A\0B\0C\0\0)
2466  */
2467 int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPSTR * lpstrFileList, UINT * sizeUsed)
2468 {
2469         FileOpenDlgInfos *fodInfos  = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2470         UINT nStrCharCount = 0; /* index in src buffer */
2471         UINT nFileIndex = 0;    /* index in dest buffer */
2472         UINT nFileCount = 0;    /* number of files */
2473         UINT nStrLen = 0;       /* length of string in edit control */
2474         LPSTR lpstrEdit;        /* buffer for string from edit control */
2475
2476         TRACE("\n");
2477
2478         /* get the filenames from the edit control */
2479         nStrLen = SendMessageA(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0);
2480         lpstrEdit = MemAlloc(nStrLen+1);
2481         GetDlgItemTextA(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1);
2482
2483         TRACE("nStrLen=%u str=%s\n", nStrLen, lpstrEdit);
2484         
2485         /* we might get single filename without any '"',
2486          * so we need nStrLen + terminating \0 + end-of-list \0 */
2487         *lpstrFileList = MemAlloc(nStrLen+2);
2488         *sizeUsed = 0;
2489
2490         /* build 0-delimited file list from filenames */
2491         while ( nStrCharCount <= nStrLen )
2492         {
2493           if ( lpstrEdit[nStrCharCount]=='"' )
2494           {
2495             nStrCharCount++;
2496             while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen))
2497             {
2498               (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount];
2499               (*sizeUsed)++;
2500               nStrCharCount++;
2501             }
2502             (*lpstrFileList)[nFileIndex++] = '\0';
2503             (*sizeUsed)++;
2504             nFileCount++;
2505           } 
2506           nStrCharCount++;
2507         }
2508
2509         /* single, unquoted string */
2510         if ((nStrLen > 0) && (*sizeUsed == 0) )
2511         {
2512           strcpy(*lpstrFileList, lpstrEdit);
2513           nFileIndex = strlen(lpstrEdit) + 1;
2514           (*sizeUsed) = nFileIndex;
2515           nFileCount = 1;
2516         }
2517
2518         /* trailing \0 */
2519         (*lpstrFileList)[nFileIndex] = '\0';
2520         (*sizeUsed)++;
2521
2522         MemFree(lpstrEdit);
2523         return nFileCount;
2524 }
2525
2526 #define SETDefFormatEtc(fe,cf,med) \
2527 { \
2528     (fe).cfFormat = cf;\
2529     (fe).dwAspect = DVASPECT_CONTENT; \
2530     (fe).ptd =NULL;\
2531     (fe).tymed = med;\
2532     (fe).lindex = -1;\
2533 };
2534
2535 /*
2536  * DATAOBJECT Helper functions
2537  */
2538
2539 /***********************************************************************
2540  * COMCTL32_ReleaseStgMedium
2541  *
2542  * like ReleaseStgMedium from ole32
2543  */
2544 static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium)
2545 {
2546       if(medium.pUnkForRelease)
2547       {
2548         IUnknown_Release(medium.pUnkForRelease);
2549       }
2550       else
2551       {
2552         GlobalUnlock(medium.u.hGlobal);
2553         GlobalFree(medium.u.hGlobal);
2554       }
2555 }
2556
2557 /***********************************************************************
2558  *          GetPidlFromDataObject
2559  *
2560  * Return pidl(s) by number from the cached DataObject
2561  *
2562  * nPidlIndex=0 gets the fully qualified root path
2563  */
2564 LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex)
2565 {
2566      
2567     STGMEDIUM medium;
2568     FORMATETC formatetc;
2569     LPITEMIDLIST pidl = NULL;
2570     
2571     TRACE("sv=%p index=%u\n", doSelected, nPidlIndex);
2572     
2573     /* Set the FORMATETC structure*/
2574     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
2575
2576     /* Get the pidls from IDataObject */
2577     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
2578     {
2579       LPIDA cida = GlobalLock(medium.u.hGlobal);
2580       if(nPidlIndex <= cida->cidl)
2581       {
2582         pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]]));
2583       }
2584       COMCTL32_ReleaseStgMedium(medium);
2585     }
2586     return pidl;
2587 }
2588
2589 /***********************************************************************
2590  *          GetNumSelected
2591  *
2592  * Return the number of selected items in the DataObject.
2593  *
2594 */
2595 UINT GetNumSelected( IDataObject *doSelected )
2596 {
2597     UINT retVal = 0;
2598     STGMEDIUM medium;
2599     FORMATETC formatetc;
2600
2601     TRACE("sv=%p\n", doSelected);
2602
2603     if (!doSelected) return 0;
2604
2605     /* Set the FORMATETC structure*/
2606     SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
2607
2608     /* Get the pidls from IDataObject */
2609     if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium)))
2610     {
2611       LPIDA cida = GlobalLock(medium.u.hGlobal);
2612       retVal = cida->cidl;
2613       COMCTL32_ReleaseStgMedium(medium);
2614       return retVal;
2615     }
2616     return 0;
2617 }
2618
2619 /*
2620  * TOOLS
2621  */
2622
2623 /***********************************************************************
2624  *      GetName
2625  *
2626  * Get the pidl's display name (relative to folder) and 
2627  * put it in lpstrFileName.
2628  * 
2629  * Return NOERROR on success,
2630  * E_FAIL otherwise
2631  */
2632
2633 HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName)
2634 {
2635   STRRET str;
2636   HRESULT hRes;
2637
2638   TRACE("sf=%p pidl=%p\n", lpsf, pidl);
2639
2640   if(!lpsf)
2641   {
2642     HRESULT hRes;
2643     SHGetDesktopFolder(&lpsf);
2644     hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName);
2645     IShellFolder_Release(lpsf);
2646     return hRes;
2647   }
2648
2649   /* Get the display name of the pidl relative to the folder */
2650   if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str)))
2651   {
2652       return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl);
2653   }
2654   return E_FAIL;
2655 }
2656
2657 /***********************************************************************
2658  *      GetShellFolderFromPidl
2659  *
2660  * pidlRel is the item pidl relative 
2661  * Return the IShellFolder of the absolute pidl
2662  */
2663 IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs)
2664 {
2665   IShellFolder *psf = NULL,*psfParent;
2666
2667   TRACE("%p\n", pidlAbs);
2668
2669   if(SUCCEEDED(SHGetDesktopFolder(&psfParent)))
2670   {
2671     psf = psfParent;
2672     if(pidlAbs && pidlAbs->mkid.cb)
2673     {
2674       if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf)))
2675       {
2676         IShellFolder_Release(psfParent);
2677         return psf;
2678       }
2679     }
2680     /* return the desktop */
2681     return psfParent;
2682   }
2683   return NULL;
2684 }
2685
2686 /***********************************************************************
2687  *      GetParentPidl
2688  *
2689  * Return the LPITEMIDLIST to the parent of the pidl in the list
2690  */
2691 LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl)
2692 {
2693   LPITEMIDLIST pidlParent;
2694
2695   TRACE("%p\n", pidl);
2696   
2697   pidlParent = COMDLG32_PIDL_ILClone(pidl);
2698   COMDLG32_PIDL_ILRemoveLastID(pidlParent);
2699      
2700   return pidlParent;
2701 }
2702
2703 /***********************************************************************
2704  *      GetPidlFromName
2705  *
2706  * returns the pidl of the file name relative to folder 
2707  * NULL if an error occurred
2708  */
2709 LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPCSTR lpcstrFileName)
2710 {
2711   LPITEMIDLIST pidl;
2712   ULONG ulEaten;
2713   WCHAR lpwstrDirName[MAX_PATH];
2714
2715   TRACE("sf=%p file=%s\n", lpsf, lpcstrFileName);
2716
2717   if(!lpcstrFileName) return NULL;
2718   if(!*lpcstrFileName) return NULL;
2719
2720   MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,lpcstrFileName,-1,(LPWSTR)lpwstrDirName,MAX_PATH);  
2721
2722   if(!lpsf)
2723   {
2724     SHGetDesktopFolder(&lpsf);
2725     pidl = GetPidlFromName(lpsf, lpcstrFileName);
2726     IShellFolder_Release(lpsf);
2727   }
2728   else
2729   {
2730     IShellFolder_ParseDisplayName(lpsf, 0, NULL, (LPWSTR)lpwstrDirName, &ulEaten, &pidl, NULL); 
2731   }
2732   return pidl;
2733 }
2734
2735 /*
2736 */
2737 BOOL IsPidlFolder (LPSHELLFOLDER psf, LPITEMIDLIST pidl)
2738 {
2739         ULONG uAttr  = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
2740         HRESULT ret;
2741         
2742         TRACE("%p, %p\n", psf, pidl);
2743         
2744         ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr );
2745         
2746         TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret);
2747         /* see documentation shell 4.1*/
2748         return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
2749 }
2750
2751 /***********************************************************************
2752  *      BrowseSelectedFolder
2753  */
2754 static BOOL BrowseSelectedFolder(HWND hwnd)
2755 {
2756   BOOL bBrowseSelFolder = FALSE;
2757   FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr);
2758
2759   TRACE("\n");
2760
2761   if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1)
2762   {
2763       LPITEMIDLIST pidlSelection;
2764
2765       /* get the file selected */
2766       pidlSelection  = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1);
2767       if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection))
2768       {
2769           if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser,
2770                          pidlSelection, SBSP_RELATIVE ) ) )
2771           {
2772                MessageBoxA( hwnd, "Path does not exist", fodInfos->ofnInfos->lpstrTitle,
2773                       MB_OK | MB_ICONEXCLAMATION );
2774           }
2775
2776          bBrowseSelFolder = TRUE;
2777       }
2778       COMDLG32_SHFree( pidlSelection );
2779   }
2780
2781   return bBrowseSelFolder;
2782
2783
2784 /*
2785  * Memory allocation methods */
2786 static void *MemAlloc(UINT size)
2787 {
2788     return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
2789 }
2790
2791 static void MemFree(void *mem)
2792 {
2793     if(mem)
2794     {
2795         HeapFree(GetProcessHeap(),0,mem);
2796     }
2797 }
2798