2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 #include <afs/param.h>
19 #include <WINNT/subclass.h>
20 #include <WINNT/talocale.h>
21 #include <WINNT/dialog.h>
22 #include <WINNT/fastlist.h>
24 #ifdef FORWARD_WM_COMMAND
25 #undef FORWARD_WM_COMMAND
27 #define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \
28 (fn)((hwnd), WM_COMMAND, MAKEWPARAM((UINT)(id),(UINT)(codeNotify)), (LPARAM)(HWND)(hwndCtl))
32 * MISCELLANEOUS ______________________________________________________________
37 #define REALLOC(_a,_c,_r,_i) DialogReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
38 BOOL DialogReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
43 if (cReq <= *pcTarget)
46 if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
49 if ((pNew = (LPVOID)Allocate (cbElement * cNew)) == NULL)
51 memset (pNew, 0x00, cbElement * cNew);
55 memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
66 void DialogGetRectInParent (HWND hWnd, RECT *pr)
70 GetWindowRect (hWnd, pr);
72 pr->right -= pr->left;
73 pr->bottom -= pr->top; // right/bottom == width/height for now
78 ScreenToClient (GetParent (hWnd), &pt);
82 pr->right += pr->left;
83 pr->bottom += pr->top;
88 * PROPERTY SHEETS ____________________________________________________________
92 BOOL PropSheet_HandleNotify (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
97 switch (((NMHDR FAR *)lp)->code)
100 FORWARD_WM_COMMAND (hDlg, IDOK, 0, 0, SendMessage);
103 FORWARD_WM_COMMAND (hDlg, IDAPPLY, 0, 0, SendMessage);
106 FORWARD_WM_COMMAND (hDlg, IDHELP, 0, 0, SendMessage);
109 FORWARD_WM_COMMAND (hDlg, IDINIT, wp, lp, SendMessage);
112 FORWARD_WM_COMMAND (hDlg, IDCANCEL, 0, 0, SendMessage);
128 } *aPropSheets = NULL;
130 static size_t cPropSheets = 0;
133 HRESULT CALLBACK PropTab_HookProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
135 if (PropSheet_HandleNotify (hDlg, msg, wp, lp))
138 HWND hSheet = GetParent (hDlg);
139 HWND hTab = GetDlgItem (hSheet, IDC_PROPSHEET_TABCTRL);
144 for (ii = 0; ii < cPropSheets; ++ii)
146 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hSheet))
149 if (ii >= cPropSheets)
151 for (size_t ii = 0; ii < cPropSheets; ++ii)
153 if (aPropSheets[ii].fInUse && !aPropSheets[ii].hSheet)
155 aPropSheets[ii].hSheet = hSheet;
160 if (ii < cPropSheets)
163 for (iTab = 0; iTab < aPropSheets[ii].psh->cTabs; ++iTab)
165 if (aPropSheets[ii].psh->aTabs[iTab].hDlg == hDlg)
168 if (iTab == aPropSheets[ii].psh->cTabs)
170 iTab = (size_t)TabCtrl_GetCurSel (hTab);
172 if (iTab < aPropSheets[ii].psh->cTabs)
174 aPropSheets[ii].psh->aTabs[iTab].hDlg = hDlg;
175 BOOL rc = (CallWindowProc ((WNDPROC)(aPropSheets[ ii ].psh->aTabs[ iTab ].dlgproc), hDlg, msg, wp, lp)?TRUE:FALSE);
180 ++ aPropSheets[ ii ].cRef;
184 if (!(-- aPropSheets[ ii ].cRef))
186 PropSheet_Free (aPropSheets[ ii ].psh);
187 aPropSheets[ ii ].fInUse = FALSE;
197 return DefWindowProc (hDlg, msg, wp, lp);
202 LPPROPSHEET PropSheet_Create (LONG idsTitle, BOOL fContextHelp, HWND hParent, LPARAM lp)
204 LPPROPSHEET psh = New (PROPSHEET);
205 memset (psh, 0x00, sizeof(PROPSHEET));
206 psh->sh.dwSize = sizeof(PROPSHEETHEADER);
207 psh->sh.dwFlags = PSH_MODELESS | ((fContextHelp) ? PSH_HASHELP : 0);
208 psh->sh.hwndParent = hParent;
209 psh->sh.hInstance = THIS_HINST;
210 psh->sh.pszCaption = (HIWORD(idsTitle)) ? (LPTSTR)(LONG_PTR)idsTitle : FormatString(TEXT("%1"),TEXT("%m"),idsTitle);
211 psh->fMadeCaption = (HIWORD(idsTitle)) ? FALSE : TRUE;
216 LPPROPSHEET PropSheet_Create (int idsTitle, BOOL fContextHelp, HWND hParent, LPARAM lp)
218 return PropSheet_Create ((LONG)idsTitle, fContextHelp, hParent, lp);
221 LPPROPSHEET PropSheet_Create (LPTSTR pszTitle, BOOL fContextHelp, HWND hParent, LPARAM lp)
223 return PropSheet_Create ((LONG)(LONG_PTR)pszTitle, fContextHelp, hParent, lp);
227 BOOL PropSheet_AddTab (LPPROPSHEET psh, LONG idsTitle, int idd, DLGPROC dlgproc, LPARAM lpUser, BOOL fHelpButton, BOOL fStartPage)
229 TCHAR szTitle[ cchRESOURCE ];
232 memset (&psp, 0x00, sizeof(psp));
233 psp.dwSize = sizeof(PROPSHEETPAGE);
234 psp.dwFlags = PSP_DEFAULT | PSP_DLGINDIRECT | (fHelpButton ? PSP_HASHELP : 0);
235 psp.pResource = TaLocale_GetDialogResource (idd, &psp.hInstance);
236 psp.pfnDlgProc = (DLGPROC)PropTab_HookProc;
239 // When first creating the PROPSHEET structure, we had to guess about
240 // which module the tabs would be coming from. Now that we have at least
241 // one tab, we can correct that guess.
243 psh->sh.hInstance = psp.hInstance;
245 if (HIWORD(idsTitle))
247 psp.pszTitle = (LPTSTR)(LONG_PTR)idsTitle;
248 psp.dwFlags |= PSP_USETITLE;
250 else if (idsTitle != 0)
252 GetString (szTitle, idsTitle);
253 psp.pszTitle = szTitle;
254 psp.dwFlags |= PSP_USETITLE;
258 if ((hp = CreatePropertySheetPage (&psp)) == 0)
261 size_t size = psh->sh.nPages;
262 if (!REALLOC( psh->sh.phpage, size, 1+psh->sh.nPages, 1))
265 psh->sh.nPages = (UINT) size;
266 if (!REALLOC( psh->aTabs, psh->cTabs, psh->sh.nPages, 1))
269 psh->aTabs[ psh->sh.nPages-1 ].dlgproc = dlgproc;
270 psh->aTabs[ psh->sh.nPages-1 ].lpUser = lpUser;
271 psh->aTabs[ psh->sh.nPages-1 ].hDlg = 0;
273 psh->sh.phpage[ psh->sh.nPages-1 ] = hp;
275 psh->sh.nStartPage = psh->sh.nPages-1;
280 BOOL PropSheet_AddTab (LPPROPSHEET psh, int idsTitle, int idd, DLGPROC dlgproc, LPARAM lpUser, BOOL fHelpButton, BOOL fStartPage)
282 return PropSheet_AddTab (psh, (LONG)idsTitle, idd, dlgproc, lpUser, fHelpButton, fStartPage);
285 BOOL PropSheet_AddTab (LPPROPSHEET psh, LPTSTR pszTitle, int idd, DLGPROC dlgproc, LPARAM lpUser, BOOL fHelpButton, BOOL fStartPage)
287 return PropSheet_AddTab (psh, (LONG)(LONG_PTR)pszTitle, idd, dlgproc, lpUser, fHelpButton, fStartPage);
291 void PropSheet_NotifyAllTabs (LPPROPSHEET psh, HWND hDlg, UINT msg)
293 for (size_t ii = 0; ii < psh->cTabs; ++ii)
295 if (psh->aTabs[ ii ].dlgproc)
297 CallWindowProc ((WNDPROC)(psh->aTabs[ ii ].dlgproc), hDlg, msg, (WPARAM)psh, psh->aTabs[ ii ].lpUser);
303 HRESULT CALLBACK PropSheet_HookProc (HWND hSheet, UINT msg, WPARAM wp, LPARAM lp)
305 PVOID oldproc = Subclass_FindNextHook (hSheet, PropSheet_HookProc);
309 rc = CallWindowProc ((WNDPROC)oldproc, hSheet, msg, wp, lp);
311 rc = DefWindowProc (hSheet, msg, wp, lp);
317 for (ii = 0; ii < cPropSheets; ++ii)
319 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hSheet))
322 if (ii < cPropSheets)
324 for (size_t iTab = 0; iTab < aPropSheets[ii].psh->cTabs; ++iTab)
326 if ( (aPropSheets[ii].psh->aTabs[iTab].hDlg) &&
327 (IsWindow (aPropSheets[ii].psh->aTabs[iTab].hDlg)) &&
328 (aPropSheets[ii].psh->aTabs[iTab].dlgproc != NULL) )
330 DestroyWindow (aPropSheets[ii].psh->aTabs[iTab].hDlg);
334 PropSheet_NotifyAllTabs (aPropSheets[ ii ].psh, hSheet, WM_DESTROY_SHEET);
336 if (!(-- aPropSheets[ ii ].cRef))
338 PropSheet_Free (aPropSheets[ ii ].psh);
339 aPropSheets[ ii ].fInUse = FALSE;
343 Subclass_RemoveHook (hSheet, PropSheet_HookProc);
351 LPARAM PropSheet_FindTabParam (HWND hTab)
354 for (ii = 0; ii < cPropSheets; ++ii)
356 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hTab))
357 return aPropSheets[ii].psh->lpUser;
360 HWND hSheet = GetParent (hTab);
361 for (ii = 0; ii < cPropSheets; ++ii)
363 if (aPropSheets[ii].fInUse && (aPropSheets[ii].hSheet == hSheet))
366 if (ii < cPropSheets)
368 for (size_t iTab = 0; iTab < aPropSheets[ ii ].psh->cTabs; ++iTab)
370 if (hTab == aPropSheets[ ii ].psh->aTabs[ iTab ].hDlg)
371 return aPropSheets[ ii ].psh->aTabs[ iTab ].lpUser;
379 BOOL PropSheet_ShowModal (LPPROPSHEET psh, void (*fnPump)(MSG *lpm))
382 if ((hSheet = PropSheet_ShowModeless (psh, SW_SHOW)) == NULL)
385 BOOL fWasEnabled = TRUE;
386 HWND hParent = psh->sh.hwndParent;
387 if (hParent && IsWindow (hParent))
389 fWasEnabled = IsWindowEnabled (hParent);
390 EnableWindow (hParent, FALSE);
394 while (GetMessage (&msg, NULL, 0, 0))
396 if (IsMemoryManagerMessage (&msg))
399 if (!PropSheet_GetCurrentPageHwnd (hSheet))
401 if (hParent && IsWindow (hParent))
402 EnableWindow (hParent, fWasEnabled);
403 DestroyWindow (hSheet);
406 if (!IsWindow (hSheet))
412 TranslateMessage (&msg);
413 DispatchMessage (&msg);
418 if (PropSheet_IsDialogMessage (hSheet, &msg))
425 TranslateMessage (&msg);
426 DispatchMessage (&msg);
430 if (hParent && IsWindow (hParent))
431 EnableWindow (hParent, fWasEnabled);
437 HWND PropSheet_ShowModeless (LPPROPSHEET psh, int nCmdShow)
439 // Write down that we're opening a property sheet. Since we
440 // don't know the window handle yet, we'll set it to zero--
441 // when PropSheetTab_HookProc gets called for a property sheet
442 // that doesn't seem to be listed, it will write down hSheet for us.
443 // This way, we get the aPropSheets[] array filled in--complete with
444 // window handle--*before* the tabs themselves get any messages.
445 // Otherwise, we'd have to wait until the WM_INITDIALOG/IDINIT
446 // messages were finished.
449 for (ii = 0; ii < cPropSheets; ++ii)
451 if (!aPropSheets[ ii ].fInUse)
454 if (!REALLOC (aPropSheets, cPropSheets, 1+ii, 4))
456 aPropSheets[ ii ].fInUse = TRUE;
457 aPropSheets[ ii ].hSheet = 0;
458 aPropSheets[ ii ].psh = psh;
459 aPropSheets[ ii ].cRef = 1;
461 // Open the property sheet dialog.
463 psh->sh.dwFlags |= PSH_MODELESS;
466 if ((hSheet = (HWND)PropertySheet (&psh->sh)) == NULL)
469 // Tell all tabs (not just the first one) that the sheet has been
470 // created. We'll also want to hook the sheet itself here, so we can
471 // clean up when it's destroyed.
473 Subclass_AddHook (hSheet, PropSheet_HookProc);
474 PropSheet_NotifyAllTabs (psh, hSheet, WM_INITDIALOG_SHEET);
475 ShowWindow (hSheet, nCmdShow);
481 void PropSheet_Free (LPPROPSHEET psh)
487 Free (psh->sh.phpage);
489 if (psh->fMadeCaption && psh->sh.pszCaption)
491 FreeString (psh->sh.pszCaption);
503 HWND PropSheet_FindTabWindow (LPPROPSHEET psh, DLGPROC dlgproc)
507 for (size_t iTab = 0; iTab < psh->cTabs; ++iTab)
509 if (dlgproc == psh->aTabs[ iTab ].dlgproc)
510 return psh->aTabs[ iTab ].hDlg;
517 void PropSheetChanged (HWND hDlg)
519 PropSheet_Changed (GetParent(hDlg), hDlg);
523 void TabCtrl_SwitchToTab (HWND hTab, int iTab)
525 TabCtrl_SetCurSel (hTab, iTab);
529 nm.idFrom = IDC_PROPSHEET_TABCTRL;
530 nm.code = TCN_SELCHANGE;
531 SendMessage (GetParent (hTab), WM_NOTIFY, 0, (LPARAM)&nm);
536 * LISTVIEW ___________________________________________________________________
540 LPARAM FL_StartChange (HWND hList, BOOL fReset)
542 LPARAM dwSelected = FL_GetSelectedData (hList);
543 FastList_Begin (hList);
545 FastList_RemoveAll (hList);
550 void FL_EndChange (HWND hList, LPARAM lpToSelect)
553 FL_SetSelectedByData (hList, lpToSelect);
554 FastList_EndAll (hList);
558 void FL_ResizeColumns (HWND hList, WORD nCols, WORD *acx)
560 for (WORD ii = 0; ii < nCols; ++ii)
563 FastList_GetColumn (hList, ii, &flc);
565 flc.cxWidth = acx[ ii ];
566 FastList_SetColumn (hList, ii, &flc);
571 void cdecl FL_SetColumns (HWND hList, WORD nCols, WORD *acx, ...)
576 for (WORD ii = 0; ii < nCols; ii++)
579 GetString (flc.szText, va_arg (arg, WORD));
580 flc.dwFlags = FLCF_JUSTIFY_LEFT;
581 flc.cxWidth = acx[ ii ]; // width of the column, in pixels
582 FastList_SetColumn (hList, ii, &flc);
587 void FL_GetColumns (HWND hList, WORD nCols, WORD *acx)
589 for (WORD ii = 0; ii < nCols; ii++)
592 FastList_GetColumn (hList, ii, &flc);
593 acx[ ii ] = (WORD)flc.cxWidth;
598 HLISTITEM cdecl FL_AddItem (HWND hList, WORD nCols, LPARAM lp, int iImage1, ...)
601 va_start (arg, iImage1);
603 FASTLISTADDITEM flai;
604 memset (&flai, 0x00, sizeof(flai));
606 flai.iFirstImage = iImage1;
607 flai.iSecondImage = IMAGE_NOIMAGE;
608 flai.pszText = va_arg (arg, LPTSTR);
612 FastList_Begin (hList);
615 if ((hItem = FastList_AddItem (hList, &flai)) != NULL)
617 for (WORD ii = 1; ii < nCols; ii++)
619 FastList_SetItemText (hList, hItem, ii, va_arg (arg, LPTSTR));
623 FastList_End (hList);
628 void FL_GetItemText (HWND hList, HLISTITEM hItem, int iCol, LPTSTR psz)
630 LPCTSTR pszText = FastList_GetItemText (hList, hItem, iCol);
634 lstrcpy (psz, pszText);
638 void FL_SetItemText (HWND hList, HLISTITEM hItem, int iCol, LPCTSTR psz)
640 FastList_SetItemText (hList, hItem, iCol, psz);
644 void FL_SetSelectedByData (HWND hList, LPARAM lp)
647 if ((hItem = FastList_FindItem (hList, lp)) != NULL)
649 FL_SetSelected (hList, hItem);
654 void FL_SetSelected (HWND hList, HLISTITEM hItem)
656 FastList_Begin (hList);
657 FastList_SelectNone (hList);
660 FastList_SelectItem (hList, hItem, TRUE);
661 FastList_EnsureVisible (hList, hItem);
663 FastList_SetFocus (hList, hItem);
664 FastList_End (hList);
668 HLISTITEM FL_GetSelected (HWND hList, HLISTITEM hItem)
670 return FastList_FindNextSelected (hList, hItem);
674 HLISTITEM FL_GetFocused (HWND hList)
676 return FastList_GetFocus (hList);
680 LPARAM FL_GetFocusedData (HWND hList)
683 if ((hItem = FastList_GetFocus (hList)) == NULL)
686 return FastList_GetItemParam (hList, hItem);
690 LPARAM FL_GetData (HWND hList, HLISTITEM hItem)
692 return FastList_GetItemParam (hList, hItem);
696 HLISTITEM FL_GetIndex (HWND hList, LPARAM lp)
698 return FastList_FindItem (hList, lp);
702 LPARAM FL_GetSelectedData (HWND hList)
705 if ((hItem = FastList_FindFirstSelected (hList)) == NULL)
708 return FastList_GetItemParam (hList, hItem);
712 void FL_RestoreView (HWND hList, LPVIEWINFO lpvi)
714 FastList_Begin (hList);
716 for (size_t cColumns = FastList_GetColumnCount(hList); cColumns; --cColumns)
718 FastList_RemoveColumn (hList, cColumns-1);
721 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
723 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
726 size_t iColumn = lpvi->aColumns[ ii ];
729 GetString (flc.szText, lpvi->idsColumns[ iColumn ]);
731 flc.dwFlags = (lpvi->cxColumns[ iColumn ] & COLUMN_RIGHTJUST) ? FLCF_JUSTIFY_RIGHT : (lpvi->cxColumns[ iColumn ] & COLUMN_CENTERJUST) ? FLCF_JUSTIFY_CENTER : FLCF_JUSTIFY_LEFT;
732 flc.cxWidth = (lpvi->cxColumns[ iColumn ] & (~COLUMN_JUSTMASK));
733 FastList_SetColumn (hList, ii, &flc);
736 // Restore the fastlist's sort style
738 FastList_SetSortStyle (hList, (lpvi->iSort & (~COLUMN_SORTREV)), !!(lpvi->iSort & COLUMN_SORTREV));
740 // Switch the FastList into the proper mode--Large Icons,
741 // Small Icons, List or Details.
743 LONG dw = GetWindowLong (hList, GWL_STYLE);
744 dw &= ~FLS_VIEW_MASK;
746 SetWindowLong (hList, GWL_STYLE, dw);
748 FastList_End (hList);
752 void FL_StoreView (HWND hList, LPVIEWINFO lpvi)
754 // First, remember what mode the the FastList is in--Large,
755 // Small, List, Tree, or TreeList.
757 lpvi->lvsView = GetWindowLong (hList, GWL_STYLE);
758 lpvi->lvsView &= FLS_VIEW_MASK;
760 // Record the fastlist's sort style
764 FastList_GetSortStyle (hList, &iCol, &fRev);
765 lpvi->iSort = (size_t)iCol;
767 lpvi->iSort |= COLUMN_SORTREV;
769 // Then remember the columns' widths; we expect that the columns
770 // which are shown (ie, nColsShown and aColumns[]) are up-to-date
773 if (lpvi->lvsView & FLS_VIEW_LIST)
775 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
777 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
780 size_t iColumn = lpvi->aColumns[ii];
782 int dwJust = (lpvi->cxColumns[ iColumn ] & COLUMN_JUSTMASK);
785 FastList_GetColumn (hList, ii, &flc);
786 lpvi->cxColumns[ iColumn ] = flc.cxWidth | dwJust;
792 HLISTITEM cdecl FL_AddItem (HWND hList, LPVIEWINFO lpvi, LPARAM lp, int iImage1, ...)
795 va_start (arg, iImage1);
797 LPTSTR apszColumns[ nCOLUMNS_MAX ];
799 for (iColumn = 0; iColumn < lpvi->nColsAvail; ++iColumn)
801 apszColumns[ iColumn ] = va_arg (arg, LPTSTR);
804 FastList_Begin (hList);
806 HLISTITEM hItem = NULL;
807 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
809 if ((iColumn = lpvi->aColumns[ ii ]) >= lpvi->nColsAvail)
814 FASTLISTADDITEM flai;
815 memset (&flai, 0x00, sizeof(flai));
817 flai.iFirstImage = iImage1;
818 flai.iSecondImage = IMAGE_NOIMAGE;
819 flai.pszText = apszColumns[ iColumn ];
823 hItem = FastList_AddItem (hList, &flai);
827 FastList_SetItemText (hList, hItem, (int)ii, apszColumns[ (int)iColumn ]);
831 FastList_End (hList);
836 BOOL FL_HitTestForHeaderBar (HWND hList, POINT ptClient)
839 for (hHeader = GetWindow (hList, GW_CHILD);
841 hHeader = GetWindow (hHeader, GW_HWNDNEXT))
843 TCHAR szClassName[ cchRESOURCE ];
845 if (GetClassName (hHeader, szClassName, cchRESOURCE))
847 if (!lstrcmp (szClassName, WC_HEADER))
852 if (hHeader && IsWindow(hHeader) && IsWindowVisible(hHeader))
855 DialogGetRectInParent (hHeader, &rHeader);
856 if (PtInRect (&rHeader, ptClient))
866 * LISTVIEW ___________________________________________________________________
870 LPARAM LV_StartChange (HWND hList, BOOL fReset)
872 LPARAM dwSelected = LV_GetSelectedData (hList);
873 SendMessage (hList, WM_SETREDRAW, FALSE, 0);
875 ListView_DeleteAllItems (hList);
880 void LV_EndChange (HWND hList, LPARAM lpToSelect)
882 SendMessage (hList, WM_SETREDRAW, TRUE, 0);
884 if (lpToSelect != (LPARAM)NULL)
885 LV_SetSelectedByData (hList, lpToSelect);
889 void LV_ResizeColumns (HWND hList, WORD nCols, WORD *acx)
891 for (WORD ii = 0; ii < nCols; ++ii)
893 ListView_SetColumnWidth (hList, ii, acx[ ii ]);
897 void cdecl LV_SetColumns (HWND hList, WORD nCols, WORD *acx, ...)
902 for (WORD ii = 0; ii < nCols; ii++)
905 TCHAR text[ cchRESOURCE ];
907 GetString (text, va_arg (arg, WORD));
909 lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
910 lvC.fmt = LVCFMT_LEFT;
912 lvC.cx = acx[ ii ]; // width of the column, in pixels
914 ListView_InsertColumn (hList, ii, &lvC);
919 void LV_GetColumns (HWND hList, WORD nCols, WORD *acx)
921 for (WORD ii = 0; ii < nCols; ii++)
923 acx[ ii ] = ListView_GetColumnWidth (hList, ii);
928 void cdecl LV_AddItem (HWND hList, WORD nCols, int index, LPARAM lp, int iImage, ...)
932 va_start (arg, iImage);
934 lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
939 lvI.pszText = va_arg (arg, LPTSTR);
940 lvI.cchTextMax = cchRESOURCE;
944 if ((index == INDEX_SORT) && (lvI.pszText != LPSTR_TEXTCALLBACK))
946 lvI.iItem = LV_PickInsertionPoint (hList, lvI.pszText);
949 DWORD dw = ListView_InsertItem (hList, &lvI);
951 for (WORD ii = 1; ii < nCols; ii++)
953 ListView_SetItemText (hList, dw, ii, va_arg (arg, LPTSTR));
958 void cdecl LV_GetItemText (HWND hList, int index, short col, LPTSTR psz)
961 ListView_GetItemText (hList, index, col, (LPTSTR)psz, cchRESOURCE);
965 void cdecl LV_SetItemText (HWND hList, int index, short col, LPCTSTR psz)
967 ListView_SetItemText (hList, index, col, (LPTSTR)psz);
971 void LV_SetSelectedByData (HWND hList, LPARAM lp)
975 if ((index = LV_GetIndex (hList, lp)) != -1)
977 LV_SetSelected (hList, index);
982 void LV_SetSelected (HWND hList, int index)
984 ListView_EnsureVisible (hList, index, FALSE);
986 ListView_SetItemState (hList, index, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
990 int LV_GetSelected (HWND hList, int index)
992 return ListView_GetNextItem (hList, index, LVNI_SELECTED);
996 int LV_GetFocused (HWND hList)
998 return ListView_GetNextItem (hList, -1, LVNI_FOCUSED);
1002 LPARAM LV_GetFocusedData (HWND hList)
1006 if ((idxFocus = LV_GetFocused (hList)) == -1)
1009 return LV_GetData (hList, idxFocus);
1013 LPARAM LV_GetData (HWND hList, int index)
1017 memset (&lvI, 0x00, sizeof(LV_ITEM));
1018 lvI.mask = LVIF_PARAM;
1021 if (! ListView_GetItem (hList, &lvI))
1028 int LV_GetIndex (HWND hList, LPARAM lp)
1032 memset (&lvfi, 0x00, sizeof(lvfi));
1034 lvfi.flags = LVFI_PARAM;
1037 return ListView_FindItem (hList, -1, &lvfi);
1041 LPARAM LV_GetSelectedData (HWND hList)
1045 if ((index = LV_GetSelected (hList)) == -1)
1048 return LV_GetData (hList, index);
1052 void LV_RestoreView (HWND hList, LPVIEWINFO lpvi)
1054 // Add columns to the listview; remember that we'll have to remove any
1055 // existing columns first.
1057 while (ListView_DeleteColumn (hList, 0))
1060 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
1062 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
1065 size_t iColumn = lpvi->aColumns[ii];
1069 TCHAR szText[ cchRESOURCE ];
1070 GetString (szText, lpvi->idsColumns[ iColumn ]);
1072 lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
1073 lvc.fmt = (lpvi->cxColumns[ iColumn ] & COLUMN_RIGHTJUST) ? LVCFMT_RIGHT : (lpvi->cxColumns[ iColumn ] & COLUMN_CENTERJUST) ? LVCFMT_CENTER : LVCFMT_LEFT;
1074 lvc.pszText = szText;
1075 lvc.cx = (lpvi->cxColumns[ iColumn ] & (~COLUMN_JUSTMASK));
1076 lvc.iSubItem = (int)ii;
1077 ListView_InsertColumn (hList, ii, &lvc);
1080 // Switch the ListView into the proper mode--Large Icons,
1081 // Small Icons, List or Details.
1083 LONG dw = GetWindowLong (hList, GWL_STYLE);
1084 dw &= ~LVS_TYPEMASK;
1085 dw |= lpvi->lvsView;
1086 dw |= LVS_AUTOARRANGE;
1087 SetWindowLong (hList, GWL_STYLE, dw);
1088 ListView_Arrange (hList, LVA_DEFAULT);
1092 void LV_StoreView (HWND hList, LPVIEWINFO lpvi)
1094 // First, remember what mod the the ListView is in--Large Icons,
1095 // Small Icons, List or Details.
1097 lpvi->lvsView = GetWindowLong (hList, GWL_STYLE);
1098 lpvi->lvsView &= LVS_TYPEMASK;
1100 // Then remember the columns' widths; we expect that the columns
1101 // which are shown (ie, nColsShown and aColumns[]) are up-to-date
1104 if (lpvi->lvsView == LVS_REPORT)
1106 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
1108 if (lpvi->aColumns[ ii ] >= lpvi->nColsAvail)
1111 size_t iColumn = lpvi->aColumns[ii];
1113 int dwJust = (lpvi->cxColumns[ iColumn ] & COLUMN_JUSTMASK);
1115 lpvi->cxColumns[ iColumn ] = ListView_GetColumnWidth (hList, ii);
1116 lpvi->cxColumns[ iColumn ] |= dwJust;
1122 typedef struct // VIEWSORTINFO
1128 } VIEWSORTINFO, *LPVIEWSORTINFO;
1130 HRESULT CALLBACK LV_SortView_Numeric (LPARAM lp1, LPARAM lp2, LPARAM lpSort)
1132 LPVIEWSORTINFO lpvsi = (LPVIEWSORTINFO)lpSort;
1133 TCHAR szText[ cchRESOURCE ];
1137 int ii1 = LV_GetIndex (lpvsi->hList, lp1);
1138 int ii2 = LV_GetIndex (lpvsi->hList, lp2);
1140 LV_GetItemText (lpvsi->hList, ii1, (short)lpvsi->iColSort, szText);
1143 LV_GetItemText (lpvsi->hList, ii2, (short)lpvsi->iColSort, szText);
1146 if (lpvsi->fAscending)
1147 return (HRESULT)((d2 < d1) ? -1 : (d2 == d1) ? 0 : 1);
1149 return (HRESULT)((d1 < d2) ? -1 : (d1 == d2) ? 0 : 1);
1153 HRESULT CALLBACK LV_SortView_Alphabetic (LPARAM lp1, LPARAM lp2, LPARAM lpSort)
1155 LPVIEWSORTINFO lpvsi = (LPVIEWSORTINFO)lpSort;
1156 TCHAR szText1[ cchRESOURCE ];
1157 TCHAR szText2[ cchRESOURCE ];
1159 int ii1 = LV_GetIndex (lpvsi->hList, lp1);
1160 int ii2 = LV_GetIndex (lpvsi->hList, lp2);
1162 LV_GetItemText (lpvsi->hList, ii1, (short)lpvsi->iColSort, szText1);
1163 LV_GetItemText (lpvsi->hList, ii2, (short)lpvsi->iColSort, szText2);
1165 if (lpvsi->fAscending)
1166 return lstrcmp (szText2, szText1);
1168 return lstrcmp (szText1, szText2);
1172 void LV_SortView (HWND hList, LPVIEWINFO lpvi)
1175 for (iColSort = 0; iColSort < lpvi->nColsShown; ++iColSort)
1177 if ((lpvi->iSort & (~COLUMN_SORTREV)) == lpvi->aColumns[ iColSort ])
1181 if (iColSort < lpvi->nColsShown)
1186 vsi.iColSort = iColSort;
1187 vsi.fAscending = (lpvi->iSort & COLUMN_SORTREV) ? TRUE : FALSE;
1189 if (lpvi->cxColumns[ lpvi->iSort ] & COLUMN_RIGHTJUST)
1190 ListView_SortItems (hList, (PFNLVCOMPARE)LV_SortView_Numeric, (LPARAM)&vsi);
1192 ListView_SortItems (hList, (PFNLVCOMPARE)LV_SortView_Alphabetic, (LPARAM)&vsi);
1197 void cdecl LV_AddItem (HWND hList, LPVIEWINFO lpvi, int index, LPARAM lp, int iImage, ...)
1200 va_start (arg, iImage);
1202 LPTSTR apszColumns[ nCOLUMNS_MAX ];
1204 for (iColumn = 0; iColumn < lpvi->nColsAvail; ++iColumn)
1206 apszColumns[ iColumn ] = va_arg (arg, LPTSTR);
1209 if ((index == INDEX_SORT) && (iColumn) && (apszColumns[0] != LPSTR_TEXTCALLBACK))
1211 index = LV_PickInsertionPoint (hList, apszColumns[0]);
1215 for (size_t ii = 0; ii < lpvi->nColsShown; ++ii)
1217 if ((iColumn = lpvi->aColumns[ ii ]) >= lpvi->nColsAvail)
1223 lvitem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
1225 lvitem.stateMask = 0;
1226 lvitem.iItem = index;
1227 lvitem.iSubItem = 0;
1228 lvitem.pszText = apszColumns[ iColumn ];
1229 lvitem.cchTextMax = cchRESOURCE;
1230 lvitem.iImage = iImage;
1233 dw = ListView_InsertItem (hList, &lvitem);
1237 ListView_SetItemText (hList, dw, (int)ii, apszColumns[ iColumn ]);
1243 BOOL LV_HitTestForHeaderBar (HWND hList, POINT ptClient)
1246 for (hHeader = GetWindow (hList, GW_CHILD);
1248 hHeader = GetWindow (hHeader, GW_HWNDNEXT))
1250 TCHAR szClassName[ cchRESOURCE ];
1252 if (GetClassName (hHeader, szClassName, cchRESOURCE))
1254 if (!lstrcmp (szClassName, WC_HEADER))
1259 if (hHeader && IsWindow(hHeader) && IsWindowVisible(hHeader))
1262 DialogGetRectInParent (hHeader, &rHeader);
1263 if (PtInRect (&rHeader, ptClient))
1271 int LV_PickInsertionPoint (HWND hList, LPTSTR pszNewItem, int (__stdcall *fnSort)(LPCTSTR, LPCTSTR))
1274 int iItemHigh = ListView_GetItemCount (hList) -1;
1279 while (iItemLow <= iItemHigh)
1281 int iItemTest = iItemLow + (iItemHigh - iItemLow) / 2;
1283 TCHAR szItemTest[ 256 ];
1284 ListView_GetItemText (hList, iItemTest, 0, szItemTest, 256);
1286 int iCompare = (*fnSort)(pszNewItem, szItemTest);
1289 if ((iItemHigh = iItemTest-1) < iItemLow)
1290 return iItemHigh +1;
1294 if ((iItemLow = iItemTest+1) > iItemHigh)
1305 * COMBO BOXES ________________________________________________________________
1309 LPARAM CB_StartChange (HWND hCombo, BOOL fReset)
1311 LPARAM dwSelected = CB_GetSelectedData (hCombo);
1312 SendMessage (hCombo, WM_SETREDRAW, FALSE, 0);
1314 SendMessage (hCombo, CB_RESETCONTENT, 0, 0);
1319 void CB_EndChange (HWND hCombo, LPARAM lpToSelect)
1321 SendMessage (hCombo, WM_SETREDRAW, TRUE, 0);
1323 if (lpToSelect != (LPARAM)NULL)
1324 CB_SetSelectedByData (hCombo, lpToSelect);
1328 UINT CB_AddItem (HWND hCombo, int nsz, LPARAM lp)
1333 psz = FormatString (nsz);
1334 rc = CB_AddItem (hCombo, psz, lp);
1341 UINT CB_AddItem (HWND hCombo, LPCTSTR psz, LPARAM lp)
1344 if ((index = (UINT)SendMessage (hCombo, CB_ADDSTRING, 0, (LPARAM)psz)) != (UINT)-1)
1346 SendMessage (hCombo, CB_SETITEMDATA, index, lp);
1352 void CB_SetSelected (HWND hCombo, UINT index)
1354 SendMessage (hCombo, CB_SETCURSEL, index, 0);
1358 void CB_SetSelectedByData (HWND hCombo, LPARAM lpMatch)
1360 CB_SetSelected (hCombo, CB_GetIndex (hCombo, lpMatch));
1364 UINT CB_GetSelected (HWND hCombo)
1366 return (UINT)SendMessage (hCombo, CB_GETCURSEL, 0, 0);
1370 LPARAM CB_GetSelectedData (HWND hCombo)
1374 if ((index = CB_GetSelected (hCombo)) == -1)
1377 return CB_GetData (hCombo, index);
1381 LPARAM CB_GetData (HWND hCombo, UINT index)
1383 return (LPARAM)SendMessage (hCombo, CB_GETITEMDATA, index, 0);
1387 UINT CB_GetIndex (HWND hCombo, LPARAM lpMatch)
1389 UINT idxMax = (UINT)SendMessage (hCombo, CB_GETCOUNT, 0, 0);
1391 for (UINT index = 0; index < idxMax; index++)
1393 if (SendMessage (hCombo, CB_GETITEMDATA, index, 0) == lpMatch)
1402 * LIST BOXES _________________________________________________________________
1406 LPARAM LB_StartChange (HWND hList, BOOL fReset)
1408 LPARAM dwSelected = LB_GetSelectedData (hList);
1409 SendMessage (hList, WM_SETREDRAW, FALSE, 0);
1411 SendMessage (hList, LB_RESETCONTENT, 0, 0);
1416 void LB_EndChange (HWND hList, LPARAM lpToSelect)
1418 SendMessage (hList, WM_SETREDRAW, TRUE, 0);
1420 if (lpToSelect != (LPARAM)NULL)
1421 LB_SetSelectedByData (hList, lpToSelect);
1425 UINT LB_AddItem (HWND hList, int nsz, LPARAM lp)
1430 psz = FormatString (nsz);
1431 rc = LB_AddItem (hList, psz, lp);
1438 UINT LB_AddItem (HWND hList, LPCTSTR psz, LPARAM lp)
1441 if ((index = (UINT)SendMessage (hList, LB_ADDSTRING, 0, (LPARAM)psz)) != -1)
1443 SendMessage (hList, LB_SETITEMDATA, index, lp);
1449 void LB_EnsureVisible (HWND hList, UINT index)
1452 if ((cyItem = (int)SendMessage (hList, LB_GETITEMHEIGHT, 0, 0)) != 0)
1455 GetClientRect (hList, &rClient);
1457 if ((cWindow = cyRECT(rClient) / cyItem) == 0)
1460 int idxTop = (int)SendMessage (hList, LB_GETTOPINDEX, 0, 0);
1461 if (index < (UINT)idxTop)
1463 SendMessage (hList, LB_SETTOPINDEX, index, 0);
1465 else if (index >= (UINT)(idxTop +cWindow))
1467 SendMessage (hList, LB_SETTOPINDEX, index -cWindow +1, 0);
1473 void LB_SetSelected (HWND hList, UINT index)
1475 SendMessage (hList, LB_SETCURSEL, index, 0);
1476 LB_EnsureVisible (hList, index);
1480 void LB_SetSelectedByData (HWND hList, LPARAM lpMatch)
1482 LB_SetSelected (hList, LB_GetIndex (hList, lpMatch));
1486 UINT LB_GetSelected (HWND hList)
1488 return (UINT)SendMessage (hList, LB_GETCURSEL, 0, 0);
1492 LPARAM LB_GetSelectedData (HWND hList)
1496 if ((index = LB_GetSelected (hList)) == (UINT)-1)
1499 return LB_GetData (hList, index);
1503 LPARAM LB_GetData (HWND hList, UINT index)
1505 return (LPARAM)SendMessage (hList, LB_GETITEMDATA, index, 0);
1509 UINT LB_GetIndex (HWND hList, LPARAM lpMatch)
1511 UINT idxMax = (UINT)SendMessage (hList, LB_GETCOUNT, 0, 0);
1513 for (UINT index = 0; index < idxMax; index++)
1515 if (SendMessage (hList, LB_GETITEMDATA, index, 0) == lpMatch)
1523 WORD LB_GetStringExtent (HWND hList, LPTSTR pszString)
1525 HDC hdc = GetDC (hList);
1528 GetTextExtentPoint32 (hdc, pszString, lstrlen(pszString), &sz);
1530 ReleaseDC (hList, hdc);
1531 return (WORD)( sz.cx + 2 * GetSystemMetrics (SM_CXBORDER) );
1535 HRESULT CALLBACK ListBox_HScrollHook (HWND hList, UINT msg, WPARAM wp, LPARAM lp)
1537 PVOID oldProc = Subclass_FindNextHook (hList, ListBox_HScrollHook);
1542 Subclass_RemoveHook (hList, ListBox_HScrollHook);
1547 LPTSTR pszString = (LPTSTR)lp;
1548 WORD cxString = LB_GetStringExtent (hList, pszString);
1549 WORD cxExtent = (WORD)SendMessage (hList, LB_GETHORIZONTALEXTENT, 0, 0);
1550 if (cxString > cxExtent)
1551 SendMessage (hList, LB_SETHORIZONTALEXTENT, (WPARAM)cxString, 0);
1555 case LB_DELETESTRING:
1557 int iItemSkip = (int)wp;
1558 int iItemMax = (int)SendMessage (hList, LB_GETCOUNT, 0, 0);
1562 for (iItem = 0; iItem < iItemMax; iItem++)
1564 if (iItem == iItemSkip)
1566 int cch = (int)SendMessage (hList, LB_GETTEXTLEN, (WPARAM)iItem, 0);
1567 cchMax = max (cch, cchMax);
1570 WORD cxExtent = (WORD)SendMessage (hList, LB_GETHORIZONTALEXTENT, 0, 0);
1571 WORD cxStringMax = 0;
1572 LPTSTR pszString = AllocateString (cchMax +1);
1574 for (iItem = 0; iItem < iItemMax; iItem++)
1576 if (iItem == iItemSkip)
1578 SendMessage (hList, LB_GETTEXT, (WPARAM)iItem, (LPARAM)pszString);
1579 WORD cxString = LB_GetStringExtent (hList, pszString);
1580 cxStringMax = max (cxString, cxStringMax);
1583 FreeString (pszString);
1584 SendMessage (hList, LB_SETHORIZONTALEXTENT, (WPARAM)cxStringMax, 0);
1590 return CallWindowProc ((WNDPROC)oldProc, hList, msg, wp, lp);
1592 return DefWindowProc (hList, msg, wp, lp);
1596 void LB_EnableHScroll (HWND hList)
1598 Subclass_AddHook (hList, ListBox_HScrollHook);
1603 * TREEVIEWS __________________________________________________________________
1607 LPARAM TV_GetData (HWND hTree, HTREEITEM hti)
1612 tvi.mask = TVIF_PARAM;
1614 if (!TreeView_GetItem (hTree, &tvi))
1615 return (LPARAM)NULL;
1621 LPARAM TV_GetSelectedData (HWND hTree)
1623 HTREEITEM hti = TreeView_GetSelection (hTree);
1628 return TV_GetData (hTree, hti);
1632 LPARAM TV_StartChange (HWND hTree, BOOL fReset)
1634 LPARAM dwSelected = TV_GetSelectedData (hTree);
1635 SendMessage (hTree, WM_SETREDRAW, FALSE, 0);
1637 TreeView_DeleteAllItems (hTree);
1642 void TV_EndChange (HWND hTree, LPARAM lpToSelect)
1644 SendMessage (hTree, WM_SETREDRAW, TRUE, 0);
1646 if (lpToSelect != NULL)
1648 HTREEITEM hti = TV_RecursiveFind (hTree, TVI_ROOT, lpToSelect);
1650 TreeView_SelectItem (hTree, hti);
1655 HTREEITEM TV_RecursiveFind (HWND hTree, HTREEITEM htiRoot, LPARAM lpToFind)
1657 for (HTREEITEM hti = (htiRoot == TVI_ROOT) ? TreeView_GetRoot (hTree) : TreeView_GetChild (hTree, htiRoot);
1659 hti = TreeView_GetNextSibling (hTree, hti))
1661 if (lpToFind == TV_GetData (hTree, hti))
1665 if ((htiFound = TV_RecursiveFind (hTree, hti, lpToFind)) != NULL)
1674 * COMMON DIALOGS _____________________________________________________________
1678 BOOL Browse_Open (HWND hParent, LPTSTR pszFilename, LPTSTR pszLastDirectory, int idsFilter, int iddTemplate, LPOFNHOOKPROC lpfnHook, DWORD lCustData)
1680 TCHAR szFilter[ cchRESOURCE ];
1681 GetString (szFilter, idsFilter);
1682 TCHAR chFilter = szFilter[ lstrlen(szFilter)-1 ];
1683 for (LPTSTR pszFilter = szFilter;
1684 (*pszFilter) && ((pszFilter = (LPTSTR)lstrchr (pszFilter, chFilter)) != NULL);
1687 *pszFilter = TEXT('\0');
1691 memset (&ofn, 0x00, sizeof(ofn));
1692 ofn.lStructSize = sizeof(ofn);
1693 ofn.hwndOwner = hParent;
1694 ofn.hInstance = THIS_HINST;
1695 ofn.lpstrFilter = szFilter;
1696 ofn.nFilterIndex = 1;
1697 ofn.lpstrFile = pszFilename;
1698 ofn.nMaxFile = MAX_PATH;
1699 ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
1700 ofn.lCustData = lCustData;
1702 if (iddTemplate != 0)
1704 ofn.lpTemplateName = MAKEINTRESOURCE( iddTemplate );
1705 ofn.Flags |= OFN_ENABLETEMPLATE | OFN_EXPLORER;
1707 if (lpfnHook != NULL)
1709 ofn.lpfnHook = lpfnHook;
1710 ofn.Flags |= OFN_ENABLEHOOK | OFN_EXPLORER;
1713 TCHAR szPath[ MAX_PATH ];
1714 GetCurrentDirectory (MAX_PATH, szPath);
1715 if (pszLastDirectory && *pszLastDirectory)
1716 SetCurrentDirectory (pszLastDirectory);
1718 BOOL rc = GetOpenFileName (&ofn);
1720 if (pszLastDirectory)
1721 GetCurrentDirectory (MAX_PATH, pszLastDirectory);
1722 SetCurrentDirectory (szPath);
1728 BOOL Browse_Save (HWND hParent, LPTSTR pszFilename, LPTSTR pszLastDirectory, int idsFilter, int iddTemplate, LPOFNHOOKPROC lpfnHook, DWORD lCustData)
1730 TCHAR szFilter[ cchRESOURCE ];
1731 GetString (szFilter, idsFilter);
1732 TCHAR chFilter = szFilter[ lstrlen(szFilter)-1 ];
1733 for (LPTSTR pszFilter = szFilter;
1734 (*pszFilter) && ((pszFilter = (LPTSTR)lstrchr (pszFilter, chFilter)) != NULL);
1737 *pszFilter = TEXT('\0');
1741 memset (&sfn, 0x00, sizeof(sfn));
1742 sfn.lStructSize = sizeof(sfn);
1743 sfn.hwndOwner = hParent;
1744 sfn.hInstance = THIS_HINST;
1745 sfn.lpstrFilter = szFilter;
1746 sfn.nFilterIndex = 1;
1747 sfn.lpstrFile = pszFilename;
1748 sfn.nMaxFile = MAX_PATH;
1749 sfn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
1750 sfn.lCustData = lCustData;
1752 if (iddTemplate != 0)
1754 sfn.lpTemplateName = MAKEINTRESOURCE( iddTemplate );
1755 sfn.Flags |= OFN_ENABLETEMPLATE | OFN_EXPLORER;
1757 if (lpfnHook != NULL)
1759 sfn.lpfnHook = lpfnHook;
1760 sfn.Flags |= OFN_ENABLEHOOK | OFN_EXPLORER;
1763 TCHAR szPath[ MAX_PATH ];
1764 GetCurrentDirectory (MAX_PATH, szPath);
1765 if (pszLastDirectory && *pszLastDirectory)
1766 SetCurrentDirectory (pszLastDirectory);
1768 BOOL rc = GetSaveFileName (&sfn);
1770 if (pszLastDirectory)
1771 GetCurrentDirectory (MAX_PATH, pszLastDirectory);
1772 SetCurrentDirectory (szPath);
1779 * HOURGLASS CURSOR ETC _______________________________________________________
1783 static LONG nHourGlassRequests = 0;
1785 void StartHourGlass (void)
1787 if ((++nHourGlassRequests) == 1)
1789 SetCursor (LoadCursor (NULL, IDC_WAIT));
1793 void StopHourGlass (void)
1795 if ((nHourGlassRequests == 0) || ((--nHourGlassRequests) == 0))
1797 SetCursor (LoadCursor (NULL, IDC_ARROW));
1803 void DisplayContextMenu (HMENU hm, POINT ptScreen, HWND hParent)
1805 HMENU hmDummy = CreateMenu();
1806 InsertMenu (hmDummy, 0, MF_POPUP, (UINT)(UINT_PTR)hm, NULL);
1808 TrackPopupMenu (GetSubMenu (hmDummy, 0),
1809 TPM_LEFTALIGN | TPM_RIGHTBUTTON,
1810 ptScreen.x, ptScreen.y,
1813 DestroyMenu (hmDummy);
1817 size_t CountChildren (HWND hParent, LPTSTR pszClass)
1821 for (HWND hChild = GetWindow (hParent, GW_CHILD);
1823 hChild = GetWindow (hChild, GW_HWNDNEXT))
1825 TCHAR szClassName[ cchRESOURCE ];
1827 if (GetClassName (hChild, szClassName, cchRESOURCE))
1829 if (!lstrcmp (szClassName, pszClass))
1838 WORD NextControlID (HWND hParent)
1842 for (HWND hChild = GetWindow (hParent, GW_CHILD);
1844 hChild = GetWindow (hChild, GW_HWNDNEXT))
1846 LONG wChild = GetWindowLong (hChild, GWL_ID);
1847 if ((wChild < 0) || (wChild >= 0xF000))
1850 wNext = max( wNext, (WORD) wChild+1 );
1857 BOOL IsAncestor (HWND hParent, HWND hChild)
1859 for ( ; hChild; hChild = GetParent(hChild))
1861 if (hParent == hChild)
1868 HWND GetTabChild (HWND hTab)
1870 for (HWND hChild = GetWindow (hTab, GW_CHILD);
1872 hChild = GetWindow (hChild, GW_HWNDNEXT))
1874 TCHAR szClassName[ cchRESOURCE ];
1876 if (GetClassName (hChild, szClassName, cchRESOURCE))
1878 if (!lstrcmp (szClassName, TEXT("#32770"))) // WC_DIALOG
1887 HWND GetLastDlgTabItem (HWND hDlg)
1892 for (HWND hSearch = GetNextDlgTabItem (hDlg, NULL, FALSE);
1893 (hSearch != NULL) && (hSearch != hFirst);
1894 hSearch = GetNextDlgTabItem (hDlg, hSearch, FALSE))
1905 BOOL IsPropSheet (HWND hSheet)
1908 if ((hTab = GetDlgItem (hSheet, IDC_PROPSHEET_TABCTRL)) == NULL)
1911 TCHAR szClassName[ cchRESOURCE ];
1912 if (!GetClassName (hTab, szClassName, cchRESOURCE))
1915 if (lstrcmp (szClassName, WC_TABCONTROL))