1466 lines
40 KiB
C++
1466 lines
40 KiB
C++
|
#include "shellprv.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <limits.h>
|
||
|
#include <shlwapi.h>
|
||
|
#include <objwindow.h>
|
||
|
#include "vdate.h"
|
||
|
#include "ids.h"
|
||
|
#include "fassoc.h"
|
||
|
|
||
|
STDAPI InitFileFolderClassNames(void);
|
||
|
|
||
|
STDAPI OpenWithListRegister(DWORD dwFlags, LPCTSTR pszExt, LPCTSTR pszVerb, HKEY hkProgid);
|
||
|
|
||
|
#define AIF_TEMPKEY 0x1 // temp class key created for the selected exe
|
||
|
#define AIF_SHELLNEW 0x2 // class key with shellnew subkey
|
||
|
|
||
|
#define MAXKEYNAME 128
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT _GetURL(BOOL fXMLLookup, LPCTSTR pszExt, LPTSTR pszURL, DWORD cchSize)
|
||
|
{
|
||
|
TCHAR szUrlTemplate[MAX_URL_STRING];
|
||
|
DWORD cbSize = sizeof(szUrlTemplate);
|
||
|
DWORD dwType;
|
||
|
LANGID nLangID = GetUserDefaultUILanguage();
|
||
|
HRESULT hr = S_OK;
|
||
|
LPCTSTR pszValue = (fXMLLookup ? TEXT("XMLLookup") : TEXT("Application"));
|
||
|
|
||
|
if (0x0409 != nLangID)
|
||
|
{
|
||
|
// We redirect to a single web page on intl so we can handle any languages we don't support
|
||
|
pszValue = TEXT("intl");
|
||
|
}
|
||
|
|
||
|
if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Associations"),
|
||
|
pszValue, &dwType, (void *)szUrlTemplate, &cbSize)) &&
|
||
|
(REG_SZ == dwType))
|
||
|
{
|
||
|
wnsprintf(pszURL, cchSize, szUrlTemplate, nLangID, CharNext(pszExt));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT _OpenDownloadURL(HWND hwnd, LPCTSTR pszExt)
|
||
|
{
|
||
|
TCHAR szUrl[MAX_URL_STRING];
|
||
|
HRESULT hr = _GetURL(FALSE, pszExt, szUrl, ARRAYSIZE(szUrl));
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
HINSTANCE hReturn = ShellExecute(hwnd, NULL, szUrl, NULL, NULL, SW_SHOWNORMAL);
|
||
|
|
||
|
if (hReturn < (HINSTANCE)32)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
class CInternetOpenAs : public CObjectWindow
|
||
|
{
|
||
|
public:
|
||
|
// *** IUnknown ***
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||
|
STDMETHODIMP_(ULONG) AddRef(void);
|
||
|
STDMETHODIMP_(ULONG) Release(void);
|
||
|
|
||
|
HRESULT DisplayDialog(HWND hwndParent, LPCTSTR pszFile);
|
||
|
|
||
|
CInternetOpenAs(void);
|
||
|
|
||
|
private:
|
||
|
virtual ~CInternetOpenAs(void);
|
||
|
// Private Member Variables
|
||
|
long m_cRef;
|
||
|
|
||
|
LPTSTR _pszFilename;
|
||
|
LPTSTR _pszExt;
|
||
|
HWND _hwndParent;
|
||
|
|
||
|
|
||
|
// Private Member Functions
|
||
|
HRESULT _OnInitDlg(HWND hDlg);
|
||
|
HRESULT _OnCommand(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
||
|
HRESULT _OnNotify(HWND hDlg, LPARAM lParam);
|
||
|
|
||
|
// Download thread functions.
|
||
|
DWORD _DownloadThreadProc(void);
|
||
|
void _StartDownloadThread(void);
|
||
|
HRESULT _SetUnknownInfo(void);
|
||
|
HRESULT _ParseXML(BSTR bstrXML, LPTSTR pszFileType, DWORD cchSizeFileType, LPTSTR pszDescription, DWORD cchSizeDescription, LPTSTR pszUrl, DWORD cchSizeUrl, BOOL * pfUnknown);
|
||
|
|
||
|
INT_PTR _InternetOpenDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
||
|
static INT_PTR CALLBACK InternetOpenDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam);
|
||
|
static DWORD CALLBACK DownloadThreadProc(void *pvThis) { return ((CInternetOpenAs *) pvThis)->_DownloadThreadProc(); };
|
||
|
};
|
||
|
|
||
|
#define WMUSER_CREATETOOLTIP (WM_USER + 1) // lParam is the hwndParent, wParam is the WSTR.
|
||
|
#define WMUSER_DESTROYTYPE (WM_USER + 2) // lParam wParam are 0
|
||
|
|
||
|
|
||
|
typedef CAppInfo APPINFO;
|
||
|
|
||
|
class COpenAs
|
||
|
{
|
||
|
public:
|
||
|
ULONG AddRef();
|
||
|
ULONG Release();
|
||
|
|
||
|
friend BOOL_PTR CALLBACK OpenAsDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
|
||
|
friend BOOL_PTR CALLBACK NoOpenDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
|
||
|
friend HRESULT OpenAsDialog(HWND hwnd, POPENASINFO poainfo);
|
||
|
|
||
|
void OnOk();
|
||
|
|
||
|
private:
|
||
|
// params
|
||
|
HWND _hwnd; // parent window
|
||
|
POPENASINFO _poainfo;
|
||
|
|
||
|
// local data
|
||
|
long _cRef;
|
||
|
int _idDlg; // open as dialog type: DLG_OPENAS_NOTYPE or DLG_OPENAS
|
||
|
HWND _hDlg; // open as dialog window handle
|
||
|
HWND _hwndList; // app list
|
||
|
LPTSTR _pszExt;
|
||
|
TCHAR _szNoOpenMsg[MAX_PATH];
|
||
|
TCHAR _szDescription[CCH_KEYMAX]; // file type description
|
||
|
HRESULT _hr;
|
||
|
HTREEITEM _hItemRecommended; // root items to group programs
|
||
|
HTREEITEM _hItemOthers;
|
||
|
|
||
|
// constructer
|
||
|
COpenAs(HWND hwnd, POPENASINFO poainfo) : _hwnd(hwnd), _poainfo(poainfo), _cRef(1)
|
||
|
{
|
||
|
_pszExt = PathFindExtension(poainfo->pcszFile);
|
||
|
}
|
||
|
|
||
|
// other methods
|
||
|
HTREEITEM _AddAppInfoItem(APPINFO *pai, HTREEITEM hParentItem);
|
||
|
HTREEITEM _AddFromNewStorage(IAssocHandler *pah);
|
||
|
HTREEITEM _AddRootItem(BOOL bRecommended);
|
||
|
APPINFO *_TVFindAppInfo(HTREEITEM hItem);
|
||
|
HTREEITEM _TVFindItemByHandler(HTREEITEM hParentItem, LPCTSTR pszHandler);
|
||
|
UINT _FillListByEnumHandlers();
|
||
|
UINT _FillListWithHandlers();
|
||
|
void _InitOpenAsDlg();
|
||
|
BOOL RunAs(APPINFO *pai);
|
||
|
void OpenAsOther();
|
||
|
BOOL OpenAsMakeAssociation(LPCWSTR pszDesc, LPCWSTR pszHandler, HKEY hkey);
|
||
|
void _InitNoOpenDlg();
|
||
|
HRESULT _OpenAsDialog();
|
||
|
void _OnNotify(HWND hDlg, LPARAM lParam);
|
||
|
HRESULT _InternetOpen(void);
|
||
|
};
|
||
|
|
||
|
ULONG COpenAs::AddRef()
|
||
|
{
|
||
|
return ::InterlockedIncrement(&_cRef);
|
||
|
}
|
||
|
|
||
|
ULONG COpenAs::Release()
|
||
|
{
|
||
|
if (::InterlockedDecrement(&_cRef) == 0)
|
||
|
{
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
return _cRef;
|
||
|
}
|
||
|
|
||
|
STDAPI SHCreateAssocHandler(LPCWSTR pszExt, LPCWSTR pszApp, IAssocHandler **ppah);
|
||
|
void COpenAs::OpenAsOther()
|
||
|
{
|
||
|
TCHAR szApp[MAX_PATH];
|
||
|
TCHAR szPath[MAX_PATH];
|
||
|
|
||
|
*szApp = '\0';
|
||
|
SHExpandEnvironmentStrings(TEXT("%ProgramFiles%"), szPath, ARRAYSIZE(szPath));
|
||
|
// do a file open browse
|
||
|
if (GetFileNameFromBrowse(_hDlg, szApp, ARRAYSIZE(szApp), szPath,
|
||
|
MAKEINTRESOURCE(IDS_EXE), MAKEINTRESOURCE(IDS_PROGRAMSFILTER), MAKEINTRESOURCE(IDS_OPENAS)))
|
||
|
{
|
||
|
IAssocHandler *pah;
|
||
|
if (SUCCEEDED(SHCreateAssocHandler(_pszExt, szApp, &pah)))
|
||
|
{
|
||
|
CAppInfo *pai = new CAppInfo(pah);
|
||
|
if (pai)
|
||
|
{
|
||
|
HTREEITEM hItem = NULL;
|
||
|
if (pai->Init())
|
||
|
{
|
||
|
hItem = _TVFindItemByHandler(_hItemRecommended, pai->Name());
|
||
|
if (!hItem && _hItemOthers)
|
||
|
hItem = _TVFindItemByHandler(_hItemOthers, pai->Name());
|
||
|
|
||
|
if (!hItem)
|
||
|
{
|
||
|
hItem = _AddAppInfoItem(pai, _hItemOthers);
|
||
|
if (hItem)
|
||
|
pai = NULL;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
// Select it
|
||
|
if (hItem)
|
||
|
{
|
||
|
TreeView_SelectItem(_hwndList, hItem);
|
||
|
SetFocus(_hwndList);
|
||
|
}
|
||
|
|
||
|
if (pai)
|
||
|
delete pai;
|
||
|
}
|
||
|
pah->Release();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HTREEITEM COpenAs::_AddAppInfoItem(APPINFO *pai, HTREEITEM hParentItem)
|
||
|
{
|
||
|
TVINSERTSTRUCT tvins = {0};
|
||
|
|
||
|
tvins.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
|
||
|
tvins.item.iSelectedImage = tvins.item.iImage = pai->IconIndex();
|
||
|
|
||
|
tvins.item.pszText = (LPWSTR) pai->UIName();
|
||
|
tvins.item.cchTextMax = lstrlen(pai->UIName())+1;
|
||
|
|
||
|
tvins.item.lParam = (LPARAM) pai;
|
||
|
tvins.hInsertAfter = TVI_SORT;
|
||
|
|
||
|
// If NULL, all programs are listed as root items
|
||
|
tvins.hParent = hParentItem;
|
||
|
|
||
|
return TreeView_InsertItem(_hwndList, &tvins);
|
||
|
}
|
||
|
|
||
|
HTREEITEM COpenAs::_AddFromNewStorage(IAssocHandler *pah)
|
||
|
{
|
||
|
HTREEITEM hitem = NULL;
|
||
|
CAppInfo *pai = new CAppInfo(pah);
|
||
|
if (pai)
|
||
|
{
|
||
|
// Trim duplicate items before we add them for other programs
|
||
|
if (pai->Init()
|
||
|
&& (!_hItemRecommended || !_TVFindItemByHandler(_hItemRecommended, pai->Name())))
|
||
|
{
|
||
|
hitem = _AddAppInfoItem(pai, S_OK == pah->IsRecommended() ? _hItemRecommended : _hItemOthers);
|
||
|
}
|
||
|
|
||
|
if (!hitem)
|
||
|
{
|
||
|
delete pai;
|
||
|
}
|
||
|
}
|
||
|
return hitem;
|
||
|
}
|
||
|
|
||
|
HTREEITEM COpenAs::_AddRootItem(BOOL bRecommended)
|
||
|
{
|
||
|
TCHAR sz[MAX_PATH];
|
||
|
|
||
|
int iLen = LoadString(g_hinst, (bRecommended? IDS_OPENWITH_RECOMMENDED : IDS_OPENWITH_OTHERS), sz, ARRAYSIZE(sz));
|
||
|
|
||
|
if (iLen)
|
||
|
{
|
||
|
TVINSERTSTRUCT tvins = {0};
|
||
|
|
||
|
tvins.item.mask = TVIF_TEXT | TVIF_STATE |TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
||
|
tvins.item.pszText = sz;
|
||
|
tvins.item.cchTextMax = iLen;
|
||
|
tvins.item.stateMask = tvins.item.state = TVIS_EXPANDED; // Expand child items by default
|
||
|
tvins.hInsertAfter = TVI_ROOT;
|
||
|
tvins.hParent = NULL;
|
||
|
//
|
||
|
// Currently, we use program icon.
|
||
|
// Change it if PM/UI designer have more appropriate one.
|
||
|
//
|
||
|
tvins.item.iSelectedImage = tvins.item.iImage = Shell_GetCachedImageIndex(c_szShell32Dll, II_STPROGS, 0);
|
||
|
|
||
|
return TreeView_InsertItem(_hwndList, &tvins);
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
APPINFO *COpenAs::_TVFindAppInfo(HTREEITEM hItem)
|
||
|
{
|
||
|
// if hItem not specified, use current selected item
|
||
|
if (!hItem)
|
||
|
hItem = TreeView_GetSelection(_hwndList);
|
||
|
|
||
|
if (hItem)
|
||
|
{
|
||
|
TVITEM tvi = {0};
|
||
|
|
||
|
tvi.mask = TVIF_HANDLE;
|
||
|
tvi.hItem = hItem;
|
||
|
|
||
|
if (TreeView_GetItem(_hwndList, &tvi))
|
||
|
return ((APPINFO *) tvi.lParam);
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
HTREEITEM COpenAs::_TVFindItemByHandler(HTREEITEM hParentItem, LPCTSTR pszHandler)
|
||
|
{
|
||
|
// if we have parent item, search its children, otherwise search root items
|
||
|
HTREEITEM hItem = TreeView_GetNextItem(_hwndList, hParentItem, hParentItem ? TVGN_CHILD : TVGN_ROOT );
|
||
|
while (hItem)
|
||
|
{
|
||
|
APPINFO *pai = _TVFindAppInfo(hItem);
|
||
|
|
||
|
if (pai && !StrCmpI(pai->Name(), pszHandler))
|
||
|
return hItem;
|
||
|
|
||
|
hItem = TreeView_GetNextItem(_hwndList, hItem, TVGN_NEXT);
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
UINT COpenAs::_FillListByEnumHandlers()
|
||
|
{
|
||
|
IEnumAssocHandlers *penum;
|
||
|
UINT cHandlers = 0;
|
||
|
|
||
|
if (SUCCEEDED(SHAssocEnumHandlers(_pszExt, &penum)))
|
||
|
{
|
||
|
HTREEITEM hitemFocus = NULL;
|
||
|
BOOL fFirst = TRUE;
|
||
|
IAssocHandler *pah;
|
||
|
while (S_OK == penum->Next(1, &pah, NULL))
|
||
|
{
|
||
|
if (fFirst)
|
||
|
{
|
||
|
//
|
||
|
// Group programs to "recommended" and "others" only when we can get two different group of programs
|
||
|
// Otherwise, all programs are listed as root items
|
||
|
// Note: in our storage, general handlers is always a superset of extension related handlers
|
||
|
//
|
||
|
// if the first item is recommended,
|
||
|
// then we add the recommended node
|
||
|
//
|
||
|
if (S_OK == pah->IsRecommended())
|
||
|
{
|
||
|
_hItemRecommended = _AddRootItem(TRUE);
|
||
|
_hItemOthers = _AddRootItem(FALSE);
|
||
|
}
|
||
|
fFirst = FALSE;
|
||
|
}
|
||
|
|
||
|
HTREEITEM hitem = _AddFromNewStorage(pah);
|
||
|
if (!hitemFocus && hitem && S_OK == pah->IsRecommended())
|
||
|
{
|
||
|
// we put focus on the first recommended item
|
||
|
// the enum starts with the best
|
||
|
hitemFocus = hitem;
|
||
|
}
|
||
|
|
||
|
cHandlers++;
|
||
|
}
|
||
|
|
||
|
if (cHandlers && _hItemRecommended)
|
||
|
{
|
||
|
if (!hitemFocus)
|
||
|
hitemFocus = TreeView_GetNextItem(_hwndList, _hItemRecommended, TVGN_CHILD);
|
||
|
TreeView_SelectItem(_hwndList, hitemFocus);
|
||
|
}
|
||
|
|
||
|
penum->Release();
|
||
|
}
|
||
|
|
||
|
return cHandlers;
|
||
|
}
|
||
|
|
||
|
|
||
|
UINT COpenAs::_FillListWithHandlers()
|
||
|
{
|
||
|
UINT cHandlers = _FillListByEnumHandlers();
|
||
|
|
||
|
//
|
||
|
// Set focus on the first recommended program if we have program groups
|
||
|
// Otherwise, all programs are root items, focus will be set to the first item by default
|
||
|
//
|
||
|
|
||
|
return cHandlers;
|
||
|
}
|
||
|
|
||
|
void COpenAs::_InitOpenAsDlg()
|
||
|
{
|
||
|
TCHAR szFileName[MAX_PATH];
|
||
|
BOOL fDisableAssociate;
|
||
|
HIMAGELIST himl;
|
||
|
RECT rc;
|
||
|
|
||
|
// Don't let the file name go beyond the width of one line...
|
||
|
lstrcpy(szFileName, PathFindFileName(_poainfo->pcszFile));
|
||
|
GetClientRect(GetDlgItem(_hDlg, IDD_TEXT), &rc);
|
||
|
|
||
|
PathCompactPath(NULL, szFileName, rc.right - 4 * GetSystemMetrics(SM_CXBORDER));
|
||
|
|
||
|
SetDlgItemText(_hDlg, IDD_FILE_TEXT, szFileName);
|
||
|
|
||
|
// AraBern 07/20/99, specific to TS on NT, but can be used on NT without TS
|
||
|
// this restriction doesnt apply to admins
|
||
|
if (SHRestricted(REST_NOFILEASSOCIATE) && !IsUserAnAdmin())
|
||
|
{
|
||
|
CheckDlgButton(_hDlg, IDD_MAKEASSOC, FALSE);
|
||
|
ShowWindow(GetDlgItem(_hDlg, IDD_MAKEASSOC), SW_HIDE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Don't allow associations to be made for things we consider exes...
|
||
|
fDisableAssociate = (! (_poainfo->dwInFlags & OAIF_ALLOW_REGISTRATION) ||
|
||
|
PathIsExe(_poainfo->pcszFile));
|
||
|
|
||
|
// check IDD_MAKEASSOC only for unknown file type and those with OAIF_FORCE_REGISTRATION flag set
|
||
|
if ((_poainfo->dwInFlags & OAIF_FORCE_REGISTRATION) ||
|
||
|
(_idDlg != DLG_OPENAS && !fDisableAssociate))
|
||
|
{
|
||
|
CheckDlgButton(_hDlg, IDD_MAKEASSOC, TRUE);
|
||
|
}
|
||
|
|
||
|
if (fDisableAssociate)
|
||
|
EnableWindow(GetDlgItem(_hDlg, IDD_MAKEASSOC), FALSE);
|
||
|
}
|
||
|
|
||
|
_hwndList = GetDlgItem(_hDlg, IDD_APPLIST);
|
||
|
Shell_GetImageLists(NULL, &himl);
|
||
|
TreeView_SetImageList(_hwndList, himl, TVSIL_NORMAL);
|
||
|
|
||
|
// Leave space between ICON images - SM_CXEDGE
|
||
|
TreeView_SetItemHeight(_hwndList, TreeView_GetItemHeight(_hwndList) + GetSystemMetrics(SM_CXEDGE));
|
||
|
|
||
|
if (!_FillListWithHandlers())
|
||
|
{
|
||
|
// lets force the expensive walk
|
||
|
IRunnableTask *ptask;
|
||
|
if (SUCCEEDED(CTaskEnumHKCR_Create(&ptask)))
|
||
|
{
|
||
|
ptask->Run();
|
||
|
ptask->Release();
|
||
|
_FillListWithHandlers();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// initialize the OK button
|
||
|
EnableWindow(GetDlgItem(_hDlg, IDOK), (TreeView_GetSelection(_hwndList) != NULL));
|
||
|
|
||
|
InitFileFolderClassNames();
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL COpenAs::RunAs(APPINFO *pai)
|
||
|
{
|
||
|
pai->Handler()->Exec(_hwnd, _poainfo->pcszFile);
|
||
|
SHAddToRecentDocs(SHARD_PATH, _poainfo->pcszFile);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void COpenAs::_InitNoOpenDlg()
|
||
|
{
|
||
|
SHFILEINFO sfi;
|
||
|
HICON hIcon;
|
||
|
TCHAR szFormat[MAX_PATH], szTemp[MAX_PATH];
|
||
|
|
||
|
GetDlgItemText(_hDlg, IDD_TEXT1, szFormat, ARRAYSIZE(szFormat));
|
||
|
wnsprintf(szTemp, ARRAYSIZE(szTemp), szFormat, _szDescription, _pszExt);
|
||
|
SetDlgItemText(_hDlg, IDD_TEXT1, szTemp);
|
||
|
|
||
|
if (*_szNoOpenMsg)
|
||
|
SetDlgItemText(_hDlg, IDD_TEXT2, _szNoOpenMsg);
|
||
|
|
||
|
if (SHGetFileInfo(_poainfo->pcszFile, 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_LARGEICON)
|
||
|
&& NULL != sfi.hIcon)
|
||
|
{
|
||
|
hIcon = sfi.hIcon;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HIMAGELIST himl;
|
||
|
Shell_GetImageLists(&himl, NULL);
|
||
|
hIcon = ImageList_ExtractIcon(g_hinst, himl, II_DOCNOASSOC);
|
||
|
}
|
||
|
hIcon = (HICON)SendDlgItemMessage(_hDlg, IDD_ICON, STM_SETICON, (WPARAM)hIcon, 0);
|
||
|
if ( hIcon )
|
||
|
{
|
||
|
DestroyIcon(hIcon);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT COpenAs::_InternetOpen(void)
|
||
|
{
|
||
|
HRESULT hr = E_OUTOFMEMORY;
|
||
|
CInternetOpenAs * pInternetOpenAs = new CInternetOpenAs();
|
||
|
|
||
|
if (pInternetOpenAs)
|
||
|
{
|
||
|
DWORD dwValue;
|
||
|
DWORD cbSize = sizeof(dwValue);
|
||
|
DWORD dwType;
|
||
|
|
||
|
hr = S_OK;
|
||
|
if ((ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"), TEXT("NoInternetOpenWith"), &dwType, (void *)&dwValue, &cbSize)) || (0 == dwValue))
|
||
|
{
|
||
|
// If the policy is not set, use the feature.
|
||
|
hr = pInternetOpenAs->DisplayDialog(_hwnd, _poainfo->pcszFile);
|
||
|
}
|
||
|
|
||
|
pInternetOpenAs->Release();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
class COpenAsAssoc
|
||
|
{
|
||
|
public:
|
||
|
COpenAsAssoc(PCWSTR pszExt);
|
||
|
~COpenAsAssoc() {ATOMICRELEASE(_pqa);}
|
||
|
|
||
|
BOOL HasClassKey();
|
||
|
BOOL HasCommand();
|
||
|
BOOL GetDescription(PWSTR psz, DWORD cch);
|
||
|
BOOL GetNoOpen(PWSTR psz, DWORD cch);
|
||
|
|
||
|
protected:
|
||
|
IQueryAssociations *_pqa;
|
||
|
HRESULT _hrInit;
|
||
|
};
|
||
|
|
||
|
COpenAsAssoc::COpenAsAssoc(PCWSTR pszExt)
|
||
|
{
|
||
|
AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &_pqa));
|
||
|
if (FAILED(_pqa->Init(0, pszExt, NULL, NULL)))
|
||
|
ATOMICRELEASE(_pqa);
|
||
|
}
|
||
|
|
||
|
BOOL COpenAsAssoc::HasClassKey()
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
if (_pqa)
|
||
|
{
|
||
|
HKEY hk;
|
||
|
if (SUCCEEDED(_pqa->GetKey(0, ASSOCKEY_CLASS, NULL, &hk)))
|
||
|
{
|
||
|
RegCloseKey(hk);
|
||
|
fRet = TRUE;
|
||
|
}
|
||
|
}
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
BOOL COpenAsAssoc::HasCommand()
|
||
|
{
|
||
|
DWORD cch;
|
||
|
if (_pqa)
|
||
|
return SUCCEEDED(_pqa->GetString(0, ASSOCSTR_COMMAND, NULL, NULL, &cch));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL COpenAsAssoc::GetDescription(PWSTR psz, DWORD cch)
|
||
|
{
|
||
|
if (_pqa)
|
||
|
return SUCCEEDED(_pqa->GetString(0, ASSOCSTR_FRIENDLYDOCNAME, NULL, psz, &cch));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL COpenAsAssoc::GetNoOpen(PWSTR psz, DWORD cch)
|
||
|
{
|
||
|
if (_pqa)
|
||
|
return SUCCEEDED(_pqa->GetString(0, ASSOCSTR_NOOPEN, NULL, psz, &cch));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
const PCWSTR s_rgImageExts[] =
|
||
|
{
|
||
|
{ TEXT(".bmp")},
|
||
|
{ TEXT(".dib")},
|
||
|
{ TEXT(".emf")},
|
||
|
{ TEXT(".gif")},
|
||
|
{ TEXT(".jfif")},
|
||
|
{ TEXT(".jpg")},
|
||
|
{ TEXT(".jpe")},
|
||
|
{ TEXT(".jpeg")},
|
||
|
{ TEXT(".png")},
|
||
|
{ TEXT(".tif")},
|
||
|
{ TEXT(".tiff")},
|
||
|
{ TEXT(".wmf")},
|
||
|
{ NULL}
|
||
|
};
|
||
|
|
||
|
BOOL _IsImageExt(PCWSTR pszExt)
|
||
|
{
|
||
|
for (int i = 0; s_rgImageExts[i] ; i++)
|
||
|
{
|
||
|
if (0 == StrCmpIW(pszExt, s_rgImageExts[i]))
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static const PCWSTR s_rgZipExts[] =
|
||
|
{
|
||
|
{ TEXT(".zip")},
|
||
|
{ NULL}
|
||
|
};
|
||
|
|
||
|
static const struct
|
||
|
{
|
||
|
const PCWSTR *rgpszExts;
|
||
|
PCWSTR pszDll;
|
||
|
} s_rgFixAssocs[] = {
|
||
|
{ s_rgImageExts, L"shimgvw.dll" },
|
||
|
{ s_rgZipExts, L"zipfldr.dll" },
|
||
|
// { s_rgWmpExts, L"wmp.dll" },
|
||
|
};
|
||
|
|
||
|
|
||
|
PCWSTR _WhichDll(PCWSTR pszExt)
|
||
|
{
|
||
|
for (int i = 0; i < ARRAYSIZE(s_rgFixAssocs); i++)
|
||
|
{
|
||
|
for (int j = 0; s_rgFixAssocs[i].rgpszExts[j] ; j++)
|
||
|
{
|
||
|
if (0 == StrCmpIW(pszExt, s_rgFixAssocs[i].rgpszExts[j]))
|
||
|
return s_rgFixAssocs[i].pszDll;
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
BOOL _CreateProcessWithArgs(LPCTSTR pszApp, LPCTSTR pszArgs, LPCTSTR pszDirectory, PROCESS_INFORMATION *ppi)
|
||
|
{
|
||
|
STARTUPINFO si = {0};
|
||
|
si.cb = sizeof(si);
|
||
|
TCHAR szCommandLine[MAX_PATH * 2];
|
||
|
wnsprintf(szCommandLine, ARRAYSIZE(szCommandLine), L"\"%s\" %s", pszApp, pszArgs);
|
||
|
return CreateProcess(pszApp, szCommandLine, NULL, NULL, FALSE, 0, NULL, pszDirectory, &si, ppi);
|
||
|
}
|
||
|
|
||
|
|
||
|
void _GetSystemPathItem(PCWSTR pszItem, PWSTR pszPath, DWORD cch)
|
||
|
{
|
||
|
GetSystemDirectory(pszPath, cch);
|
||
|
PathCombine(pszPath, pszPath, pszItem);
|
||
|
}
|
||
|
|
||
|
BOOL _Regsvr32Dll(PCWSTR pszDll)
|
||
|
{
|
||
|
WCHAR szReg[MAX_PATH];
|
||
|
WCHAR szDll[MAX_PATH + 3] = L"/s ";
|
||
|
_GetSystemPathItem(L"regsvr32.exe", szReg, ARRAYSIZE(szReg));
|
||
|
_GetSystemPathItem(pszDll, szDll + 3, ARRAYSIZE(szDll) - 3);
|
||
|
|
||
|
PROCESS_INFORMATION pi = {0};
|
||
|
if (_CreateProcessWithArgs(szReg, szDll, NULL, &pi))
|
||
|
{
|
||
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
||
|
|
||
|
CloseHandle(pi.hProcess);
|
||
|
CloseHandle(pi.hThread);
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL _FixAssocs(PCWSTR pszExt)
|
||
|
{
|
||
|
PCWSTR pszDll = _WhichDll(pszExt);
|
||
|
if (pszDll)
|
||
|
{
|
||
|
_Regsvr32Dll(pszDll);
|
||
|
COpenAsAssoc oac(pszExt);
|
||
|
return oac.HasCommand();
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
HRESULT COpenAs::_OpenAsDialog()
|
||
|
{
|
||
|
BOOL fHasCommand = FALSE;
|
||
|
int idDlg = DLG_OPENAS_NOTYPE;
|
||
|
|
||
|
// Depending on policy, do not allow user to change file type association.
|
||
|
if (SHRestricted(REST_NOFILEASSOCIATE))
|
||
|
{
|
||
|
_poainfo->dwInFlags &= ~OAIF_ALLOW_REGISTRATION & ~OAIF_REGISTER_EXT;
|
||
|
}
|
||
|
|
||
|
// We don't allow association for files without extension or with only "." as extension
|
||
|
if (!_pszExt || !*_pszExt || !*(_pszExt+1))
|
||
|
{
|
||
|
idDlg = DLG_OPENAS;
|
||
|
_poainfo->dwInFlags &= ~OAIF_ALLOW_REGISTRATION;
|
||
|
}
|
||
|
// Known file type(has verb): use DLG_OPENAS
|
||
|
// NoOpen file type(has NoOpen value): use DLG_NOOPEN
|
||
|
// Unknown file type(All others): use DLG_OPENAS_NOTYPE
|
||
|
else
|
||
|
{
|
||
|
COpenAsAssoc oac(_pszExt);
|
||
|
fHasCommand = oac.HasCommand();
|
||
|
if (oac.HasClassKey())
|
||
|
{
|
||
|
idDlg = DLG_OPENAS;
|
||
|
oac.GetDescription(_szDescription, ARRAYSIZE(_szDescription));
|
||
|
if (oac.GetNoOpen(_szNoOpenMsg, ARRAYSIZE(_szNoOpenMsg))
|
||
|
&& !fHasCommand)
|
||
|
{
|
||
|
INITCOMMONCONTROLSEX initComctl32;
|
||
|
|
||
|
initComctl32.dwSize = sizeof(initComctl32);
|
||
|
initComctl32.dwICC = (ICC_STANDARD_CLASSES | ICC_LINK_CLASS);
|
||
|
InitCommonControlsEx(&initComctl32); // Register the comctl32 LinkWindow
|
||
|
if ((-1 != DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_NOOPEN), _hwnd, NoOpenDlgProc, (LPARAM)this))
|
||
|
&& _hr == S_FALSE)
|
||
|
{
|
||
|
// user selected cancel
|
||
|
return _hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if this is a busted file association, maybe we can fix it...
|
||
|
if ((OAIF_REGISTER_EXT & _poainfo->dwInFlags) && !fHasCommand)
|
||
|
{
|
||
|
// this feels like an unknown type
|
||
|
if (_FixAssocs(_pszExt))
|
||
|
{
|
||
|
SHChangeNotify(SHCNE_ASSOCCHANGED, 0, NULL, NULL);
|
||
|
|
||
|
// Exec if requested.
|
||
|
if (_poainfo->dwInFlags & OAIF_EXEC)
|
||
|
{
|
||
|
IAssocHandler *pah;
|
||
|
if (SUCCEEDED(SHCreateAssocHandler(_pszExt, NULL, &pah)))
|
||
|
{
|
||
|
CAppInfo *pai = new CAppInfo(pah);
|
||
|
if (pai)
|
||
|
{
|
||
|
if (pai->Init())
|
||
|
{
|
||
|
RunAs(pai);
|
||
|
}
|
||
|
delete pai;
|
||
|
}
|
||
|
pah->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_idDlg = idDlg;
|
||
|
|
||
|
HRESULT hr = _hr;
|
||
|
LinkWindow_RegisterClass();
|
||
|
// If this is the dialog where we don't know the file type and the feature is turned on,
|
||
|
// use the Internet Open As dialog.
|
||
|
if ((FALSE == fHasCommand) &&
|
||
|
SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), TEXT("InternetOpenWith"), FALSE, TRUE))
|
||
|
{
|
||
|
hr = _InternetOpen();
|
||
|
}
|
||
|
|
||
|
// Display the old dialog if fUseInternetOpenAs is NOT set. Or display it if the user
|
||
|
// chooses "Choose..." in that dialog.
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
INITCOMMONCONTROLSEX initComctl32;
|
||
|
|
||
|
initComctl32.dwSize = sizeof(initComctl32);
|
||
|
initComctl32.dwICC = (ICC_STANDARD_CLASSES | ICC_LINK_CLASS);
|
||
|
InitCommonControlsEx(&initComctl32); // Register the comctl32 LinkWindow
|
||
|
if (-1 == DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(idDlg), _hwnd, OpenAsDlgProc, (LPARAM)this))
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL_PTR CALLBACK NoOpenDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
COpenAs *pOpenAs = (COpenAs *)GetWindowLongPtr(hDlg, DWLP_USER);
|
||
|
|
||
|
switch (wMsg)
|
||
|
{
|
||
|
case WM_INITDIALOG:
|
||
|
SetWindowLongPtr(hDlg, DWLP_USER, lParam);
|
||
|
pOpenAs = (COpenAs *)lParam;
|
||
|
pOpenAs->_hDlg = hDlg;
|
||
|
pOpenAs->_InitNoOpenDlg();
|
||
|
break;
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
ASSERT(pOpenAs);
|
||
|
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
||
|
case IDD_OPENWITH:
|
||
|
// this will cause the open with dialog
|
||
|
// to follow this dialog
|
||
|
pOpenAs->_hr = S_OK;
|
||
|
EndDialog(hDlg, TRUE);
|
||
|
break;
|
||
|
|
||
|
case IDCANCEL:
|
||
|
pOpenAs->_hr = S_FALSE;
|
||
|
EndDialog(hDlg, TRUE);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
const static DWORD aOpenAsHelpIDs[] = { // Context Help IDs
|
||
|
IDD_ICON, IDH_FCAB_OPENAS_APPLIST,
|
||
|
IDD_TEXT, IDH_FCAB_OPENAS_APPLIST,
|
||
|
IDD_FILE_TEXT, (DWORD) -1,
|
||
|
IDD_DESCRIPTIONTEXT, IDH_FCAB_OPENAS_DESCRIPTION,
|
||
|
IDD_DESCRIPTION, IDH_FCAB_OPENAS_DESCRIPTION,
|
||
|
IDD_APPLIST, IDH_FCAB_OPENAS_APPLIST,
|
||
|
IDD_MAKEASSOC, IDH_FCAB_OPENAS_MAKEASSOC,
|
||
|
IDD_OTHER, IDH_FCAB_OPENAS_OTHER,
|
||
|
IDD_OPENWITH_BROWSE, IDH_FCAB_OPENAS_OTHER,
|
||
|
IDD_OPENWITH_WEBSITE, IDH_FCAB_OPENWITH_LOOKONWEB,
|
||
|
0, 0
|
||
|
};
|
||
|
|
||
|
const static DWORD aOpenAsDownloadHelpIDs[] = { // Context Help IDs
|
||
|
IDD_ICON, (DWORD) -1,
|
||
|
IDD_FILE_TEXT, (DWORD) -1,
|
||
|
// For DLG_OPENAS_DOWNALOAD
|
||
|
IDD_WEBAUTOLOOKUP, IDH_CANNOTOPEN_USEWEB,
|
||
|
IDD_OPENWITHLIST, IDH_CANNOTOPEN_SELECTLIST,
|
||
|
|
||
|
0, 0
|
||
|
};
|
||
|
|
||
|
void COpenAs::_OnNotify(HWND hDlg, LPARAM lParam)
|
||
|
{
|
||
|
switch (((NMHDR *)lParam)->code)
|
||
|
{
|
||
|
case TVN_DELETEITEM:
|
||
|
if (lParam)
|
||
|
{
|
||
|
APPINFO *pai = (APPINFO *)(((LPNMTREEVIEW) lParam )->itemOld.lParam);
|
||
|
if (pai)
|
||
|
{
|
||
|
delete pai;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case TVN_SELCHANGED:
|
||
|
EnableWindow(GetDlgItem(hDlg, IDOK), (_TVFindAppInfo(TreeView_GetSelection(NULL)) != NULL));
|
||
|
break;
|
||
|
|
||
|
case NM_DBLCLK:
|
||
|
if (IsWindowEnabled(GetDlgItem(hDlg, IDOK)))
|
||
|
PostMessage(hDlg, WM_COMMAND, GET_WM_COMMAND_MPS(IDOK, hDlg, 0));
|
||
|
break;
|
||
|
|
||
|
case NM_RETURN:
|
||
|
case NM_CLICK:
|
||
|
if (lParam)
|
||
|
{
|
||
|
PNMLINK pNMLink = (PNMLINK) lParam;
|
||
|
|
||
|
if (!StrCmpW(pNMLink->item.szID, L"Browse"))
|
||
|
{
|
||
|
_OpenDownloadURL(_hwnd, _pszExt);
|
||
|
EndDialog(hDlg, FALSE);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void COpenAs::OnOk()
|
||
|
{
|
||
|
APPINFO *pai = _TVFindAppInfo(NULL);
|
||
|
|
||
|
if (pai)
|
||
|
{
|
||
|
// See if we should make an association or not...
|
||
|
GetDlgItemText(_hDlg, IDD_DESCRIPTION, _szDescription, ARRAYSIZE(_szDescription));
|
||
|
|
||
|
if ((_poainfo->dwInFlags & OAIF_REGISTER_EXT)
|
||
|
&& (IsDlgButtonChecked(_hDlg, IDD_MAKEASSOC)))
|
||
|
{
|
||
|
pai->Handler()->MakeDefault(_szDescription);
|
||
|
}
|
||
|
|
||
|
// Did we register the association?
|
||
|
_hr = IsDlgButtonChecked(_hDlg, IDD_MAKEASSOC) ? S_OK : S_FALSE;
|
||
|
|
||
|
// Exec if requested.
|
||
|
if (_poainfo->dwInFlags & OAIF_EXEC)
|
||
|
{
|
||
|
RunAs(pai);
|
||
|
}
|
||
|
|
||
|
EndDialog(_hDlg, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL_PTR CALLBACK OpenAsDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
COpenAs *pOpenAs = (COpenAs *)GetWindowLongPtr(hDlg, DWLP_USER);
|
||
|
|
||
|
switch (wMsg)
|
||
|
{
|
||
|
case WM_INITDIALOG:
|
||
|
SetWindowLongPtr(hDlg, DWLP_USER, lParam);
|
||
|
pOpenAs = (COpenAs *)lParam;
|
||
|
if (pOpenAs)
|
||
|
{
|
||
|
pOpenAs->_hDlg = hDlg;
|
||
|
pOpenAs->_InitOpenAsDlg();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_HELP:
|
||
|
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
|
||
|
HELP_WM_HELP, (ULONG_PTR)(LPTSTR) aOpenAsHelpIDs);
|
||
|
break;
|
||
|
|
||
|
case WM_CONTEXTMENU:
|
||
|
if ((int)SendMessage(hDlg, WM_NCHITTEST, 0, lParam) != HTCLIENT)
|
||
|
return FALSE; // don't process it
|
||
|
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
|
||
|
(ULONG_PTR)(void *)aOpenAsHelpIDs);
|
||
|
break;
|
||
|
|
||
|
case WM_NOTIFY:
|
||
|
if (pOpenAs)
|
||
|
{
|
||
|
pOpenAs->_OnNotify(hDlg, lParam);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
ASSERT(pOpenAs);
|
||
|
if (pOpenAs)
|
||
|
{
|
||
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
||
|
{
|
||
|
case IDD_OPENWITH_BROWSE:
|
||
|
pOpenAs->OpenAsOther();
|
||
|
break;
|
||
|
|
||
|
case IDOK:
|
||
|
{
|
||
|
pOpenAs->OnOk();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case IDCANCEL:
|
||
|
pOpenAs->_hr = E_ABORT;
|
||
|
EndDialog(hDlg, FALSE);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return FALSE;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// external API version
|
||
|
|
||
|
HRESULT
|
||
|
OpenAsDialog(
|
||
|
HWND hwnd,
|
||
|
POPENASINFO poainfo)
|
||
|
{
|
||
|
HRESULT hr = E_OUTOFMEMORY;
|
||
|
|
||
|
COpenAs *pOpenAs = new COpenAs(hwnd, poainfo);
|
||
|
DebugMsg(DM_TRACE, TEXT("Enter OpenAs for %s"), poainfo->pcszFile);
|
||
|
if (pOpenAs)
|
||
|
{
|
||
|
hr = pOpenAs->_OpenAsDialog();
|
||
|
pOpenAs->Release();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
void WINAPI OpenAs_RunDLL(HWND hwnd, HINSTANCE hAppInstance, LPSTR lpszCmdLine, int nCmdShow)
|
||
|
{
|
||
|
HRESULT hrOle = SHCoInitialize(); // Needed for SysLink's IAccessability (LresultFromObject)
|
||
|
OPENASINFO oainfo = { 0 };
|
||
|
|
||
|
UINT iLen = lstrlenA(lpszCmdLine)+1;
|
||
|
LPWSTR lpwszCmdLine;
|
||
|
|
||
|
lpwszCmdLine = (LPWSTR)LocalAlloc(LPTR,iLen*sizeof(WCHAR));
|
||
|
if (lpwszCmdLine)
|
||
|
{
|
||
|
MultiByteToWideChar(CP_ACP, 0,
|
||
|
lpszCmdLine, -1,
|
||
|
lpwszCmdLine, iLen);
|
||
|
|
||
|
DebugMsg(DM_TRACE, TEXT("OpenAs_RunDLL is called with (%s)"), lpwszCmdLine);
|
||
|
|
||
|
oainfo.pcszFile = lpwszCmdLine;
|
||
|
oainfo.dwInFlags = (OAIF_ALLOW_REGISTRATION |
|
||
|
OAIF_REGISTER_EXT |
|
||
|
OAIF_EXEC);
|
||
|
|
||
|
OpenAsDialog(hwnd, &oainfo);
|
||
|
|
||
|
LocalFree(lpwszCmdLine);
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hrOle))
|
||
|
{
|
||
|
CoUninitialize();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void WINAPI OpenAs_RunDLLW(HWND hwnd, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow)
|
||
|
{
|
||
|
HRESULT hrOle = SHCoInitialize(); // Needed for SysLink's IAccessability (LresultFromObject)
|
||
|
OPENASINFO oainfo = { 0 };
|
||
|
|
||
|
DebugMsg(DM_TRACE, TEXT("OpenAs_RunDLL is called with (%s)"), lpwszCmdLine);
|
||
|
|
||
|
oainfo.pcszFile = lpwszCmdLine;
|
||
|
oainfo.dwInFlags = (OAIF_ALLOW_REGISTRATION |
|
||
|
OAIF_REGISTER_EXT |
|
||
|
OAIF_EXEC);
|
||
|
|
||
|
OpenAsDialog(hwnd, &oainfo);
|
||
|
|
||
|
if (SUCCEEDED(hrOle))
|
||
|
{
|
||
|
CoUninitialize();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
//
|
||
|
// Type checking
|
||
|
//
|
||
|
const static RUNDLLPROCA lpfnRunDLL = OpenAs_RunDLL;
|
||
|
const static RUNDLLPROCW lpfnRunDLLW = OpenAs_RunDLLW;
|
||
|
#endif
|
||
|
|
||
|
//===========================
|
||
|
// *** Private Methods ***
|
||
|
//===========================
|
||
|
HRESULT CreateWindowTooltip(HWND hDlg, HWND hwndWindow, LPCTSTR pszText)
|
||
|
{
|
||
|
HRESULT hr = E_OUTOFMEMORY;
|
||
|
HWND hwndToolTipo = CreateWindow(TOOLTIPS_CLASS, c_szNULL, WS_POPUP | TTS_NOPREFIX, CW_USEDEFAULT, CW_USEDEFAULT,
|
||
|
CW_USEDEFAULT, CW_USEDEFAULT, hDlg, NULL, HINST_THISDLL, NULL);
|
||
|
|
||
|
if (hwndToolTipo)
|
||
|
{
|
||
|
TOOLINFO ti;
|
||
|
|
||
|
ti.cbSize = sizeof(ti);
|
||
|
ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
|
||
|
ti.hwnd = hDlg;
|
||
|
ti.uId = (UINT_PTR)hwndWindow;
|
||
|
ti.lpszText = (LPTSTR)pszText; // const -> non const
|
||
|
ti.hinst = HINST_THISDLL;
|
||
|
SendMessage(hwndToolTipo, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CInternetOpenAs::_ParseXML(BSTR bstrXML, LPTSTR pszFileType, DWORD cchSizeFileType, LPTSTR pszDescription, DWORD cchSizeDescription, LPTSTR pszUrl, DWORD cchSizeUrl, BOOL * pfUnknown)
|
||
|
{
|
||
|
IXMLDOMDocument * pXMLDoc;
|
||
|
HRESULT hr = XMLDOMFromBStr(bstrXML, &pXMLDoc);
|
||
|
|
||
|
*pfUnknown = FALSE;
|
||
|
pszFileType[0] = pszDescription[0] = pszUrl[0] = 0;
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IXMLDOMElement * pXMLElement = NULL;
|
||
|
|
||
|
hr = pXMLDoc->get_documentElement(&pXMLElement);
|
||
|
if (S_FALSE == hr)
|
||
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
||
|
else if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// This is only valid XML if the root tag is "MSFILEASSOCIATIONS".
|
||
|
// The case is not important.
|
||
|
hr = XMLElem_VerifyTagName(pXMLElement, L"MSFILEASSOCIATIONS");
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CComBSTR bstrFileType;
|
||
|
|
||
|
hr = XMLNode_GetChildTagTextValue(pXMLElement, L"FILETYPENAME", &bstrFileType);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CComBSTR bstrDesc;
|
||
|
CComBSTR bstrURL;
|
||
|
|
||
|
StrCpyN(pszFileType, bstrFileType, cchSizeFileType);
|
||
|
if (SUCCEEDED(XMLNode_GetChildTagTextValue(pXMLElement, L"DESCRIPTION", &bstrDesc)))
|
||
|
{
|
||
|
StrCpyN(pszDescription, bstrDesc, cchSizeDescription);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StrCpyN(pszDescription, L"", cchSizeDescription);
|
||
|
}
|
||
|
|
||
|
hr = XMLNode_GetChildTagTextValue(pXMLElement, L"URL", &bstrURL);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CComBSTR bstrUnknown;
|
||
|
|
||
|
StrCpyN(pszUrl, bstrURL, cchSizeUrl);
|
||
|
if (SUCCEEDED(XMLNode_GetChildTagTextValue(pXMLElement, L"UNKNOWN", &bstrUnknown)) &&
|
||
|
!StrCmpIW(bstrUnknown, L"TRUE"))
|
||
|
{
|
||
|
*pfUnknown = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pXMLElement->Release();
|
||
|
}
|
||
|
|
||
|
pXMLDoc->Release();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD CInternetOpenAs::_DownloadThreadProc(void)
|
||
|
{
|
||
|
#ifdef FEATURE_DOWNLOAD_DESCRIPTION
|
||
|
// 1. Create the URL
|
||
|
TCHAR szUrl[MAX_PATH];
|
||
|
|
||
|
if (SUCCEEDED(_GetURL(TRUE, _pszExt, szUrl, ARRAYSIZE(szUrl))))
|
||
|
{
|
||
|
// 2. Download the XML
|
||
|
BSTR bstrXML;
|
||
|
HRESULT hr = DownloadUrl(szUrl, &bstrXML);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
TCHAR szFileType[MAX_PATH];
|
||
|
TCHAR szDescription[2000];
|
||
|
BOOL fUnknown = FALSE;
|
||
|
|
||
|
// 3. Get the info from the XML to the UI
|
||
|
hr = _ParseXML(bstrXML, szFileType, ARRAYSIZE(szFileType), szDescription, ARRAYSIZE(szDescription), szUrl, ARRAYSIZE(szUrl), &fUnknown);
|
||
|
if (SUCCEEDED(hr) && IsWindow(_hwnd))
|
||
|
{
|
||
|
SetWindowText(GetDlgItem(_hwnd, IDD_FILETYPE_TEXT), szFileType);
|
||
|
SendMessage(_hwnd, WMUSER_CREATETOOLTIP, (WPARAM)szDescription, (LPARAM)GetDlgItem(_hwnd, IDD_FILETYPE_TEXT));
|
||
|
|
||
|
if (fUnknown)
|
||
|
{
|
||
|
// Hide the "Type" control.
|
||
|
SendMessage(_hwnd, WMUSER_DESTROYTYPE, NULL, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SysFreeString(bstrXML);
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
_SetUnknownInfo();
|
||
|
}
|
||
|
}
|
||
|
#endif // FEATURE_DOWNLOAD_DESCRIPTION
|
||
|
|
||
|
Release();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT CInternetOpenAs::_SetUnknownInfo(void)
|
||
|
{
|
||
|
// Hide the "Type" control.
|
||
|
#ifdef FEATURE_DOWNLOAD_DESCRIPTION
|
||
|
EnableWindow(GetDlgItem(_hwnd, IDD_FILETYPE_LABLE), FALSE);
|
||
|
EnableWindow(GetDlgItem(_hwnd, IDD_FILETYPE_TEXT), FALSE);
|
||
|
ShowWindow(GetDlgItem(_hwnd, IDD_FILETYPE_LABLE), SW_HIDE);
|
||
|
ShowWindow(GetDlgItem(_hwnd, IDD_FILETYPE_TEXT), SW_HIDE);
|
||
|
#endif // FEATURE_DOWNLOAD_DESCRIPTION
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CInternetOpenAs::_StartDownloadThread(void)
|
||
|
{
|
||
|
#ifdef FEATURE_DOWNLOAD_DESCRIPTION
|
||
|
AddRef();
|
||
|
if (!SHCreateThread(CInternetOpenAs::DownloadThreadProc, this, (CTF_COINIT | CTF_PROCESS_REF | CTF_FREELIBANDEXIT), NULL))
|
||
|
{
|
||
|
// We failed so don't leave the background thread with a ref.
|
||
|
Release();
|
||
|
|
||
|
_SetUnknownInfo();
|
||
|
}
|
||
|
#endif // FEATURE_DOWNLOAD_DESCRIPTION
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CInternetOpenAs::_OnInitDlg(HWND hDlg)
|
||
|
{
|
||
|
_hwnd = hDlg;
|
||
|
|
||
|
// Start the background thread to download the information.
|
||
|
_StartDownloadThread();
|
||
|
SetWindowText(GetDlgItem(_hwnd, IDD_FILE_TEXT), _pszFilename);
|
||
|
CheckDlgButton(hDlg, IDD_WEBAUTOLOOKUP, BST_CHECKED);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CInternetOpenAs::_OnCommand(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
UINT idCtrl = GET_WM_COMMAND_ID(wParam, lParam);
|
||
|
UINT wEvent = GET_WM_COMMAND_CMD(wParam, lParam);
|
||
|
|
||
|
switch (idCtrl)
|
||
|
{
|
||
|
case IDCANCEL:
|
||
|
EndDialog(hDlg, E_FAIL);
|
||
|
break;
|
||
|
|
||
|
case IDOK:
|
||
|
if (BST_UNCHECKED != IsDlgButtonChecked(hDlg, IDD_WEBAUTOLOOKUP))
|
||
|
{
|
||
|
_OpenDownloadURL(_hwnd, _pszExt);
|
||
|
EndDialog(hDlg, E_FAIL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EndDialog(hDlg, S_OK); // return S_OK so it will open the next dialog.
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CInternetOpenAs::_OnNotify(HWND hDlg, LPARAM lParam)
|
||
|
{
|
||
|
switch (((NMHDR *)lParam)->code)
|
||
|
{
|
||
|
case NM_CLICK:
|
||
|
if (lParam)
|
||
|
{
|
||
|
PNMLINK pNMLink = (PNMLINK) lParam;
|
||
|
|
||
|
if (!StrCmpW(pNMLink->item.szID, L"GoOnline"))
|
||
|
{
|
||
|
_OpenDownloadURL(_hwnd, _pszExt);
|
||
|
EndDialog(hDlg, E_FAIL);
|
||
|
}
|
||
|
else if (!StrCmpW(pNMLink->item.szID, L"Choose"))
|
||
|
{
|
||
|
EndDialog(hDlg, S_OK); // return S_OK so it will open the next dialog.
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
INT_PTR CALLBACK CInternetOpenAs::InternetOpenDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
CInternetOpenAs * pThis = (CInternetOpenAs *)GetWindowLongPtr(hDlg, DWLP_USER);
|
||
|
|
||
|
if (WM_INITDIALOG == wMsg)
|
||
|
{
|
||
|
pThis = (CInternetOpenAs *) lParam;
|
||
|
|
||
|
if (pThis)
|
||
|
{
|
||
|
SetWindowLongPtr(hDlg, DWLP_USER, lParam);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pThis)
|
||
|
return pThis->_InternetOpenDlgProc(hDlg, wMsg, wParam, lParam);
|
||
|
|
||
|
return DefWindowProc(hDlg, wMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
|
||
|
// This Property Sheet appear in the top level of the "Display Control Panel".
|
||
|
INT_PTR CInternetOpenAs::_InternetOpenDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
switch(message)
|
||
|
{
|
||
|
case WM_INITDIALOG:
|
||
|
_OnInitDlg(hDlg);
|
||
|
break;
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
_OnCommand(hDlg, message, wParam, lParam);
|
||
|
break;
|
||
|
|
||
|
case WM_NOTIFY:
|
||
|
_OnNotify(hDlg, lParam);
|
||
|
break;
|
||
|
|
||
|
case WM_HELP:
|
||
|
WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (DWORD_PTR) aOpenAsDownloadHelpIDs);
|
||
|
break;
|
||
|
|
||
|
case WM_CONTEXTMENU: // right mouse click
|
||
|
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (DWORD_PTR) aOpenAsDownloadHelpIDs);
|
||
|
break;
|
||
|
|
||
|
case WMUSER_CREATETOOLTIP:
|
||
|
CreateWindowTooltip(_hwnd, (HWND)lParam, (LPCWSTR)wParam);
|
||
|
break;
|
||
|
|
||
|
case WMUSER_DESTROYTYPE:
|
||
|
#ifdef FEATURE_DOWNLOAD_DESCRIPTION
|
||
|
EnableWindow(GetDlgItem(_hwnd, IDD_FILETYPE_LABLE), FALSE);
|
||
|
EnableWindow(GetDlgItem(_hwnd, IDD_FILETYPE_TEXT), FALSE);
|
||
|
ShowWindow(GetDlgItem(_hwnd, IDD_FILETYPE_LABLE), SW_HIDE);
|
||
|
ShowWindow(GetDlgItem(_hwnd, IDD_FILETYPE_TEXT), SW_HIDE);
|
||
|
#endif // FEATURE_DOWNLOAD_DESCRIPTION
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//===========================
|
||
|
// *** Public Methods ***
|
||
|
//===========================
|
||
|
HRESULT CInternetOpenAs::DisplayDialog(HWND hwnd, LPCTSTR pszFile)
|
||
|
{
|
||
|
HRESULT hr = E_OUTOFMEMORY;
|
||
|
INITCOMMONCONTROLSEX initComctl32;
|
||
|
|
||
|
initComctl32.dwSize = sizeof(initComctl32);
|
||
|
initComctl32.dwICC = (ICC_STANDARD_CLASSES | ICC_LINK_CLASS);
|
||
|
InitCommonControlsEx(&initComctl32); // Register the comctl32 LinkWindow
|
||
|
|
||
|
Str_SetPtrW(&_pszFilename, (PathFindFileName(pszFile) ? PathFindFileName(pszFile) : pszFile));
|
||
|
Str_SetPtrW(&_pszExt, PathFindExtension(_pszFilename));
|
||
|
if (_pszExt)
|
||
|
{
|
||
|
_hwndParent = hwnd;
|
||
|
|
||
|
hr = (HRESULT) DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_OPENAS_DOWNALOAD), _hwnd, CInternetOpenAs::InternetOpenDlgProc, (LPARAM)this);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//===========================
|
||
|
// *** IUnknown Interface ***
|
||
|
//===========================
|
||
|
ULONG CInternetOpenAs::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement(&m_cRef);
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG CInternetOpenAs::Release()
|
||
|
{
|
||
|
if (InterlockedDecrement(&m_cRef))
|
||
|
return m_cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CInternetOpenAs::QueryInterface(REFIID riid, void **ppvObj)
|
||
|
{
|
||
|
HRESULT hr = E_NOINTERFACE;
|
||
|
|
||
|
static const QITAB qit[] =
|
||
|
{
|
||
|
QITABENT(CInternetOpenAs, IOleWindow),
|
||
|
{ 0 },
|
||
|
};
|
||
|
|
||
|
return QISearch(this, qit, riid, ppvObj);
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================
|
||
|
// *** Class Methods ***
|
||
|
//===========================
|
||
|
CInternetOpenAs::CInternetOpenAs(void) : m_cRef(1)
|
||
|
{
|
||
|
DllAddRef();
|
||
|
|
||
|
// This needs to be allocated in Zero Inited Memory.
|
||
|
// Assert that all Member Variables are inited to Zero.
|
||
|
ASSERT(!_pszExt);
|
||
|
}
|
||
|
|
||
|
|
||
|
CInternetOpenAs::~CInternetOpenAs()
|
||
|
{
|
||
|
Str_SetPtrW(&_pszExt, NULL);
|
||
|
Str_SetPtrW(&_pszFilename, NULL);
|
||
|
|
||
|
DllRelease();
|
||
|
}
|