2 * Copyright 2003, 2004, 2005 Martin Fuchs
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 // dialogs/searchprogram.cpp
27 // Martin Fuchs, 02.10.2003
33 #include "searchprogram.h"
36 int CollectProgramsThread::Run()
39 collect_programs(SpecialFolderPath(CSIDL_COMMON_PROGRAMS
, _hwnd
));
40 } catch(COMException
&) {
45 collect_programs(SpecialFolderPath(CSIDL_PROGRAMS
, _hwnd
));
46 } catch(COMException
&) {
55 void CollectProgramsThread::collect_programs(const ShellPath
& path
)
57 ShellDirectory
* dir
= new ShellDirectory(GetDesktopFolder(), path
, 0);
60 dir
->smart_scan(SORT_NONE
);
62 for(Entry
*entry
=dir
->_down
; _alive
&& entry
; entry
=entry
->_next
) {
63 if (entry
->_shell_attribs
& SFGAO_HIDDEN
)
66 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
67 collect_programs(entry
->create_absolute_pidl());
68 else if (entry
->_shell_attribs
& SFGAO_LINK
)
70 _callback(entry
, _para
);
74 void CollectProgramsThread::free_dirs()
76 while(!_dirs
.empty()) {
77 ShellDirectory
* dir
= _dirs
.top();
78 dir
->free_subentries();
85 #pragma warning(disable: 4355)
88 FindProgramDlg::FindProgramDlg(HWND hwnd
)
90 _list_ctrl(GetDlgItem(hwnd
, IDC_PROGRAMS_FOUND
)),
91 _thread(collect_programs_callback
, hwnd
, this),
92 _sort(_list_ctrl
, CompareFunc
/*, (LPARAM)this*/)
95 const size_t nChars
= sizeof(szTemp
)/sizeof(*szTemp
);
96 SetWindowIcon(hwnd
, IDI_SEARCH
);
98 _resize_mgr
.Add(IDC_FILTER
, RESIZE_X
);
99 _resize_mgr
.Add(IDC_CHECK_ENTRIES
, MOVE_X
);
100 _resize_mgr
.Add(IDC_PROGRAMS_FOUND
, RESIZE
);
102 _resize_mgr
.Resize(+520, +300);
104 _haccel
= LoadAccelerators(g_Globals
._hInstance
, MAKEINTRESOURCE(IDA_SEARCH_PROGRAM
));
106 (void)ListView_SetImageList(_list_ctrl
, g_Globals
._icon_cache
.get_sys_imagelist(), LVSIL_SMALL
);
108 LV_COLUMN column
= {LVCF_FMT
|LVCF_WIDTH
|LVCF_TEXT
, LVCFMT_LEFT
, 250};
110 LoadString(g_Globals
._hInstance
, IDS_NAMECOLUMN
, szTemp
, nChars
);
111 column
.pszText
= szTemp
;
112 ListView_InsertColumn(_list_ctrl
, 0, &column
);
115 LoadString(g_Globals
._hInstance
, IDS_PATHCOLUMN
, szTemp
, nChars
);
116 column
.pszText
= szTemp
;
117 ListView_InsertColumn(_list_ctrl
, 1, &column
);
120 LoadString(g_Globals
._hInstance
, IDS_MENUCOLUMN
, szTemp
, nChars
);
121 column
.pszText
= szTemp
;
122 ListView_InsertColumn(_list_ctrl
, 2, &column
);
124 ListView_SetExtendedListViewStyleEx(_list_ctrl
, LVS_EX_FULLROWSELECT
, LVS_EX_FULLROWSELECT
);
126 _common_programs
= SpecialFolderFSPath(CSIDL_COMMON_PROGRAMS
, hwnd
);
127 if (!_common_programs
.empty())
128 _common_programs
.append(_T("\\"));
130 _user_programs
= SpecialFolderFSPath(CSIDL_PROGRAMS
, hwnd
);
131 if (!_user_programs
.empty())
132 _user_programs
.append(_T("\\"));
138 register_pretranslate(hwnd
);
141 FindProgramDlg::~FindProgramDlg()
145 unregister_pretranslate(_hwnd
);
149 void FindProgramDlg::Refresh(bool delete_cache
)
156 GetWindowText(GetDlgItem(_hwnd
, IDC_FILTER
), buffer
, COUNTOF(buffer
));
158 _lwr_filter
= buffer
;
160 HiddenWindow
hide_listctrl(_list_ctrl
);
162 ListView_DeleteAllItems(_list_ctrl
);
164 if (delete_cache
|| !_thread
._cache_valid
) {
168 for(FPDCache::const_iterator it
=_cache
.begin(); it
!=_cache
.end(); ++it
)
173 void FindProgramDlg::collect_programs_callback(Entry
* entry
, void* param
)
175 FindProgramDlg
* pThis
= (FindProgramDlg
*) param
;
177 IShellLink
* pShellLink
;
178 HRESULT hr
= entry
->GetUIObjectOf(pThis
->_hwnd
, IID_IShellLink
, (LPVOID
*)&pShellLink
);
181 ShellLinkPtr
shell_link(pShellLink
);
183 shell_link
->Release();
185 /*hr = pShellLink->Resolve(pThis->_hwnd, SLR_NO_UI);
186 if (SUCCEEDED(hr))*/ {
188 TCHAR path
[MAX_PATH
];
190 hr
= pShellLink
->GetPath(path
, COUNTOF(path
)-1, &wfd
, SLGP_UNCPRIORITY
);
193 TCHAR entry_path
[MAX_PATH
];
195 entry
->get_path(entry_path
, COUNTOF(entry_path
));
199 int len
= pThis
->_common_programs
.size();
201 if (len
&& !_tcsnicmp(entry_path
, pThis
->_common_programs
, len
))
202 menu_path
= ResString(IDS_ALL_USERS
) + (String(entry_path
)+len
);
203 else if ((len
=pThis
->_user_programs
.size()) && !_tcsnicmp(entry_path
, pThis
->_user_programs
, len
))
204 menu_path
= String(entry_path
)+len
;
206 // store info in cache
209 new_entry
._entry
= entry
;
210 new_entry
._menu_path
= menu_path
;
211 new_entry
._path
= path
;
212 new_entry
._idxIcon
= I_IMAGECALLBACK
;
214 pThis
->_cache
.push_front(new_entry
);
215 FPDEntry
& cache_entry
= pThis
->_cache
.front();
217 Lock
lock(pThis
->_thread
._crit_sect
);
219 // resolve deadlocks while executing Thread::Stop()
220 if (!pThis
->_thread
.is_alive())
223 pThis
->add_entry(cache_entry
);
229 void FindProgramDlg::add_entry(const FPDEntry
& cache_entry
)
231 String lwr_path
= cache_entry
._path
;
232 String lwr_name
= cache_entry
._entry
->_display_name
;
237 if (_lwr_filter
.empty())
238 if (_tcsstr(lwr_name
, _T("uninstal")) || _tcsstr(lwr_name
, _T("deinstal"))) // filter out deinstallation links
241 if (!_tcsstr(lwr_path
, _lwr_filter
) && !_tcsstr(lwr_name
, _lwr_filter
))
244 LV_ITEM item
= {LVIF_TEXT
|LVIF_IMAGE
|LVIF_PARAM
, INT_MAX
};
246 item
.pszText
= cache_entry
._entry
->_display_name
;
247 item
.iImage
= cache_entry
._idxIcon
;
248 item
.lParam
= (LPARAM
) &cache_entry
;
249 item
.iItem
= ListView_InsertItem(_list_ctrl
, &item
); // We could use the information in _sort to enable manual sorting while populating the list.
251 item
.mask
= LVIF_TEXT
;
254 item
.pszText
= (LPTSTR
)(LPCTSTR
)cache_entry
._path
;
255 ListView_SetItem(_list_ctrl
, &item
);
258 item
.pszText
= (LPTSTR
)(LPCTSTR
)cache_entry
._menu_path
;
259 ListView_SetItem(_list_ctrl
, &item
);
262 LRESULT
FindProgramDlg::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
266 (void)ListView_SetImageList(_list_ctrl
, 0, LVSIL_SMALL
); // detach system image list
269 case PM_TRANSLATE_MSG
: {
270 MSG
* pmsg
= (MSG
*) lparam
;
272 if (TranslateAccelerator(_hwnd
, _haccel
, pmsg
))
278 return super::WndProc(nmsg
, wparam
, lparam
);
284 int FindProgramDlg::Command(int id
, int code
)
286 if (code
== BN_CLICKED
) {
296 case IDC_CHECK_ENTRIES
:
301 return super::Command(id
, code
);
306 else if (code
== EN_CHANGE
) {
319 void FindProgramDlg::LaunchSelected()
321 Lock
lock(_thread
._crit_sect
);
323 int count
= ListView_GetSelectedCount(_list_ctrl
);
326 if (MessageBox(_hwnd
, ResString(IDS_LAUNCH_MANY_PROGRAMS
), ResString(IDS_TITLE
), MB_OKCANCEL
) != IDOK
)
329 for(int idx
=-1; (idx
=ListView_GetNextItem(_list_ctrl
, idx
, LVNI_SELECTED
))!=-1; ) {
330 LPARAM lparam
= ListView_GetItemData(_list_ctrl
, idx
);
333 FPDEntry
& cache_entry
= *(FPDEntry
*)lparam
;
334 cache_entry
._entry
->launch_entry(_hwnd
);
339 int FindProgramDlg::Notify(int id
, NMHDR
* pnmh
)
342 case LVN_GETDISPINFO
: {
343 LV_DISPINFO
* pDispInfo
= (LV_DISPINFO
*) pnmh
;
345 if (pnmh
->hwndFrom
== _list_ctrl
) {
346 if (pDispInfo
->item
.mask
& LVIF_IMAGE
) {
347 FPDEntry
& cache_entry
= *(FPDEntry
*)pDispInfo
->item
.lParam
;
348 Entry
* entry
= cache_entry
._entry
;
350 if (entry
->_icon_id
== ICID_UNKNOWN
)
351 entry
->_icon_id
= entry
->extract_icon(ICF_SYSCACHE
);
353 pDispInfo
->item
.iImage
= g_Globals
._icon_cache
.get_icon(entry
->_icon_id
).get_sysiml_idx();
354 pDispInfo
->item
.mask
|= LVIF_DI_SETITEM
;
362 if (pnmh
->hwndFrom
== _list_ctrl
)
365 Lock lock(_thread._crit_sect);
367 LPNMLISTVIEW pnmv = (LPNMLISTVIEW) pnmh;
368 LPARAM lparam = ListView_GetItemData(pnmh->hwndFrom, pnmv->iItem);
371 FPDEntry& cache_entry = *(FPDEntry*)lparam;
372 cache_entry._entry->launch_entry(_hwnd);
377 case HDN_ITEMCLICK
: {
379 NMHEADER
* phdr
= (NMHEADER
*)pnmh
;
381 if (GetParent(pnmh
->hwndFrom
) == _list_ctrl
) {
382 if (_thread
._cache_valid
) { // disable manual sorting while populating the list
383 _sort
.toggle_sort(phdr
->iItem
);
393 int CALLBACK
FindProgramDlg::CompareFunc(LPARAM lparam1
, LPARAM lparam2
, LPARAM lparamSort
)
395 ListSort
* sort
= (ListSort
*)lparamSort
;
397 FPDEntry
& a
= *(FPDEntry
*)lparam1
;
398 FPDEntry
& b
= *(FPDEntry
*)lparam2
;
402 switch(sort
->_sort_crit
) {
404 cmp
= _tcsicoll(a
._entry
->_display_name
, b
._entry
->_display_name
);
408 cmp
= _tcsicoll(a
._path
, b
._path
);
412 cmp
= _tcsicoll(a
._menu_path
, b
._menu_path
);
415 return sort
->_direction
? -cmp
: cmp
;
418 void FindProgramDlg::CheckEntries()
420 ///@todo check all entries for existing targets, display a list of not working entries and ask the user for permission to delete them