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