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 "../resource.h"
35 #include "searchprogram.h"
38 int CollectProgramsThread::Run()
41 collect_programs(SpecialFolderPath(CSIDL_COMMON_PROGRAMS
, _hwnd
));
42 } catch(COMException
&) {
47 collect_programs(SpecialFolderPath(CSIDL_PROGRAMS
, _hwnd
));
48 } catch(COMException
&) {
57 void CollectProgramsThread::collect_programs(const ShellPath
& path
)
59 ShellDirectory
* dir
= new ShellDirectory(GetDesktopFolder(), path
, 0);
62 dir
->smart_scan(SORT_NONE
);
64 for(Entry
*entry
=dir
->_down
; _alive
&& entry
; entry
=entry
->_next
) {
65 if (entry
->_shell_attribs
& SFGAO_HIDDEN
)
68 if (entry
->_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
69 collect_programs(entry
->create_absolute_pidl());
70 else if (entry
->_shell_attribs
& SFGAO_LINK
)
72 _callback(entry
, _para
);
76 void CollectProgramsThread::free_dirs()
78 while(!_dirs
.empty()) {
79 ShellDirectory
* dir
= _dirs
.top();
80 dir
->free_subentries();
87 #pragma warning(disable: 4355)
90 FindProgramDlg::FindProgramDlg(HWND hwnd
)
92 _list_ctrl(GetDlgItem(hwnd
, IDC_PROGRAMS_FOUND
)),
93 _thread(collect_programs_callback
, hwnd
, this),
94 _sort(_list_ctrl
, CompareFunc
/*, (LPARAM)this*/)
97 const size_t nChars
= sizeof(szTemp
)/sizeof(*szTemp
);
98 SetWindowIcon(hwnd
, IDI_SEARCH
);
100 _resize_mgr
.Add(IDC_FILTER
, RESIZE_X
);
101 _resize_mgr
.Add(IDC_CHECK_ENTRIES
, MOVE_X
);
102 _resize_mgr
.Add(IDC_PROGRAMS_FOUND
, RESIZE
);
104 _resize_mgr
.Resize(+520, +300);
106 _haccel
= LoadAccelerators(g_Globals
._hInstance
, MAKEINTRESOURCE(IDA_SEARCH_PROGRAM
));
108 (void)ListView_SetImageList(_list_ctrl
, g_Globals
._icon_cache
.get_sys_imagelist(), LVSIL_SMALL
);
110 LV_COLUMN column
= {LVCF_FMT
|LVCF_WIDTH
|LVCF_TEXT
, LVCFMT_LEFT
, 250};
112 LoadString(g_Globals
._hInstance
, IDS_NAMECOLUMN
, szTemp
, nChars
);
113 column
.pszText
= szTemp
;
114 ListView_InsertColumn(_list_ctrl
, 0, &column
);
117 LoadString(g_Globals
._hInstance
, IDS_PATHCOLUMN
, szTemp
, nChars
);
118 column
.pszText
= szTemp
;
119 ListView_InsertColumn(_list_ctrl
, 1, &column
);
122 LoadString(g_Globals
._hInstance
, IDS_MENUCOLUMN
, szTemp
, nChars
);
123 column
.pszText
= szTemp
;
124 ListView_InsertColumn(_list_ctrl
, 2, &column
);
126 ListView_SetExtendedListViewStyleEx(_list_ctrl
, LVS_EX_FULLROWSELECT
, LVS_EX_FULLROWSELECT
);
128 _common_programs
= SpecialFolderFSPath(CSIDL_COMMON_PROGRAMS
, hwnd
);
129 if (!_common_programs
.empty())
130 _common_programs
.append(_T("\\"));
132 _user_programs
= SpecialFolderFSPath(CSIDL_PROGRAMS
, hwnd
);
133 if (!_user_programs
.empty())
134 _user_programs
.append(_T("\\"));
140 register_pretranslate(hwnd
);
143 FindProgramDlg::~FindProgramDlg()
147 unregister_pretranslate(_hwnd
);
151 void FindProgramDlg::Refresh(bool delete_cache
)
158 GetWindowText(GetDlgItem(_hwnd
, IDC_FILTER
), buffer
, COUNTOF(buffer
));
160 _lwr_filter
= buffer
;
162 HiddenWindow
hide_listctrl(_list_ctrl
);
164 ListView_DeleteAllItems(_list_ctrl
);
166 if (delete_cache
|| !_thread
._cache_valid
) {
170 for(FPDCache::const_iterator it
=_cache
.begin(); it
!=_cache
.end(); ++it
)
175 void FindProgramDlg::collect_programs_callback(Entry
* entry
, void* param
)
177 FindProgramDlg
* pThis
= (FindProgramDlg
*) param
;
179 IShellLink
* pShellLink
;
180 HRESULT hr
= entry
->GetUIObjectOf(pThis
->_hwnd
, IID_IShellLink
, (LPVOID
*)&pShellLink
);
183 ShellLinkPtr
shell_link(pShellLink
);
185 shell_link
->Release();
187 /*hr = pShellLink->Resolve(pThis->_hwnd, SLR_NO_UI);
188 if (SUCCEEDED(hr))*/ {
190 TCHAR path
[MAX_PATH
];
192 hr
= pShellLink
->GetPath(path
, COUNTOF(path
)-1, &wfd
, SLGP_UNCPRIORITY
);
195 TCHAR entry_path
[MAX_PATH
];
197 entry
->get_path(entry_path
, COUNTOF(entry_path
));
201 int len
= pThis
->_common_programs
.size();
203 if (len
&& !_tcsnicmp(entry_path
, pThis
->_common_programs
, len
))
204 menu_path
= ResString(IDS_ALL_USERS
) + (String(entry_path
)+len
);
205 else if ((len
=pThis
->_user_programs
.size()) && !_tcsnicmp(entry_path
, pThis
->_user_programs
, len
))
206 menu_path
= String(entry_path
)+len
;
208 // store info in cache
211 new_entry
._entry
= entry
;
212 new_entry
._menu_path
= menu_path
;
213 new_entry
._path
= path
;
214 new_entry
._idxIcon
= I_IMAGECALLBACK
;
216 pThis
->_cache
.push_front(new_entry
);
217 FPDEntry
& cache_entry
= pThis
->_cache
.front();
219 Lock
lock(pThis
->_thread
._crit_sect
);
221 // resolve deadlocks while executing Thread::Stop()
222 if (!pThis
->_thread
.is_alive())
225 pThis
->add_entry(cache_entry
);
231 void FindProgramDlg::add_entry(const FPDEntry
& cache_entry
)
233 String lwr_path
= cache_entry
._path
;
234 String lwr_name
= cache_entry
._entry
->_display_name
;
239 if (_lwr_filter
.empty())
240 if (_tcsstr(lwr_name
, _T("uninstal")) || _tcsstr(lwr_name
, _T("deinstal"))) // filter out deinstallation links
243 if (!_tcsstr(lwr_path
, _lwr_filter
) && !_tcsstr(lwr_name
, _lwr_filter
))
246 LV_ITEM item
= {LVIF_TEXT
|LVIF_IMAGE
|LVIF_PARAM
, INT_MAX
};
248 item
.pszText
= cache_entry
._entry
->_display_name
;
249 item
.iImage
= cache_entry
._idxIcon
;
250 item
.lParam
= (LPARAM
) &cache_entry
;
251 item
.iItem
= ListView_InsertItem(_list_ctrl
, &item
); // We could use the information in _sort to enable manual sorting while populating the list.
253 item
.mask
= LVIF_TEXT
;
256 item
.pszText
= (LPTSTR
)(LPCTSTR
)cache_entry
._path
;
257 ListView_SetItem(_list_ctrl
, &item
);
260 item
.pszText
= (LPTSTR
)(LPCTSTR
)cache_entry
._menu_path
;
261 ListView_SetItem(_list_ctrl
, &item
);
264 LRESULT
FindProgramDlg::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
268 (void)ListView_SetImageList(_list_ctrl
, 0, LVSIL_SMALL
); // detach system image list
271 case PM_TRANSLATE_MSG
: {
272 MSG
* pmsg
= (MSG
*) lparam
;
274 if (TranslateAccelerator(_hwnd
, _haccel
, pmsg
))
280 return super::WndProc(nmsg
, wparam
, lparam
);
286 int FindProgramDlg::Command(int id
, int code
)
288 if (code
== BN_CLICKED
) {
298 case IDC_CHECK_ENTRIES
:
303 return super::Command(id
, code
);
308 else if (code
== EN_CHANGE
) {
321 void FindProgramDlg::LaunchSelected()
323 Lock
lock(_thread
._crit_sect
);
325 int count
= ListView_GetSelectedCount(_list_ctrl
);
328 if (MessageBox(_hwnd
, ResString(IDS_LAUNCH_MANY_PROGRAMS
), ResString(IDS_TITLE
), MB_OKCANCEL
) != IDOK
)
331 for(int idx
=-1; (idx
=ListView_GetNextItem(_list_ctrl
, idx
, LVNI_SELECTED
))!=-1; ) {
332 LPARAM lparam
= ListView_GetItemData(_list_ctrl
, idx
);
335 FPDEntry
& cache_entry
= *(FPDEntry
*)lparam
;
336 cache_entry
._entry
->launch_entry(_hwnd
);
341 int FindProgramDlg::Notify(int id
, NMHDR
* pnmh
)
344 case LVN_GETDISPINFO
: {
345 LV_DISPINFO
* pDispInfo
= (LV_DISPINFO
*) pnmh
;
347 if (pnmh
->hwndFrom
== _list_ctrl
) {
348 if (pDispInfo
->item
.mask
& LVIF_IMAGE
) {
349 FPDEntry
& cache_entry
= *(FPDEntry
*)pDispInfo
->item
.lParam
;
350 Entry
* entry
= cache_entry
._entry
;
352 if (entry
->_icon_id
== ICID_UNKNOWN
)
353 entry
->_icon_id
= entry
->extract_icon(ICF_SYSCACHE
);
355 pDispInfo
->item
.iImage
= g_Globals
._icon_cache
.get_icon(entry
->_icon_id
).get_sysiml_idx();
356 pDispInfo
->item
.mask
|= LVIF_DI_SETITEM
;
364 if (pnmh
->hwndFrom
== _list_ctrl
)
367 Lock lock(_thread._crit_sect);
369 LPNMLISTVIEW pnmv = (LPNMLISTVIEW) pnmh;
370 LPARAM lparam = ListView_GetItemData(pnmh->hwndFrom, pnmv->iItem);
373 FPDEntry& cache_entry = *(FPDEntry*)lparam;
374 cache_entry._entry->launch_entry(_hwnd);
379 case HDN_ITEMCLICK
: {
381 NMHEADER
* phdr
= (NMHEADER
*)pnmh
;
383 if (GetParent(pnmh
->hwndFrom
) == _list_ctrl
) {
384 if (_thread
._cache_valid
) { // disable manual sorting while populating the list
385 _sort
.toggle_sort(phdr
->iItem
);
395 int CALLBACK
FindProgramDlg::CompareFunc(LPARAM lparam1
, LPARAM lparam2
, LPARAM lparamSort
)
397 ListSort
* sort
= (ListSort
*)lparamSort
;
399 FPDEntry
& a
= *(FPDEntry
*)lparam1
;
400 FPDEntry
& b
= *(FPDEntry
*)lparam2
;
404 switch(sort
->_sort_crit
) {
406 cmp
= _tcsicoll(a
._entry
->_display_name
, b
._entry
->_display_name
);
410 cmp
= _tcsicoll(a
._path
, b
._path
);
414 cmp
= _tcsicoll(a
._menu_path
, b
._menu_path
);
417 return sort
->_direction
? -cmp
: cmp
;
420 void FindProgramDlg::CheckEntries()
422 ///@todo check all entries for existing targets, display a list of not working entries and ask the user for permission to delete them