windows-nt/Source/XPSP1/NT/shell/shell32/ftedit.cpp
2020-09-26 16:20:57 +08:00

662 lines
18 KiB
C++

#include "shellprv.h"
#include "ids.h"
#include "help.h"
#include "ascstr.h"
#include "ftdlg.h"
#include "ftedit.h"
#include "ftcmmn.h"
#define ID_TIMER 2222
const static DWORD cs_rgdwHelpIDsArray[] =
{ // Context Help IDs
IDC_FT_EDIT_EXT_EDIT_TEXT, IDH_FCAB_FT_NE_FILEEXT,
IDC_FT_EDIT_EXT_EDIT, IDH_FCAB_FT_NE_FILEEXT,
IDC_FT_EDIT_PID_COMBO_TEXT, IDH_FCAB_FT_NE_FILETYPE,
IDC_FT_EDIT_PID_COMBO, IDH_FCAB_FT_NE_FILETYPE,
IDC_FT_EDIT_ADVANCED, IDH_FCAB_FT_NE_ADV_BUT,
IDC_NO_HELP_1, NO_HELP,
0, 0
};
CFTEditDlg::CFTEditDlg(FTEDITPARAM* pftEditParam) :
CFTDlg((ULONG_PTR)cs_rgdwHelpIDsArray), _pftEditParam(pftEditParam),
_iLVSel(-1)
{
}
CFTEditDlg::~CFTEditDlg()
{
}
///////////////////////////////////////////////////////////////////////////////
// Logic specific to our problem
LRESULT CFTEditDlg::OnInitDialog(WPARAM wParam, LPARAM lParam)
{
HRESULT hres = E_FAIL;
if (_pftEditParam)
{
hres = _InitAssocStore();
if (SUCCEEDED(hres))
{
_hHeapProgID = HeapCreate(0, 8 * 1024, 0);
if (!_hHeapProgID)
hres = E_OUTOFMEMORY;
}
if (SUCCEEDED(hres))
SetDlgItemText(_hwnd, IDC_FT_EDIT_EXT_EDIT, TEXT(""));
}
if (FAILED(hres))
EndDialog(_hwnd, -1);
else
Edit_LimitText(GetDlgItem(_hwnd, IDC_FT_EDIT_EXT_EDIT), MAX_EXT - 1);
// Return TRUE so that system set focus
return TRUE;
}
LRESULT CFTEditDlg::OnEdit(WORD wNotif)
{
if (_fAdvanced)
{
if (EN_CHANGE == wNotif)
{
if (_nTimer)
{
KillTimer(_hwnd, _nTimer);
_nTimer = 0;
}
_nTimer = SetTimer(_hwnd, ID_TIMER, 400, NULL);
}
}
return FALSE;
}
LRESULT CFTEditDlg::OnTimer(UINT nTimer)
{
// Kill the timer
KillTimer(_hwnd, _nTimer);
_nTimer = 0;
_ProgIDComboHelper();
return TRUE;
}
HRESULT CFTEditDlg::_ProgIDComboHelper()
{
TCHAR szExt[MAX_EXT];
TCHAR szProgIDDescr[MAX_PROGIDDESCR];
DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr);
HRESULT hres = E_FAIL;
GetDlgItemText(_hwnd, IDC_FT_EDIT_EXT_EDIT, szExt, ARRAYSIZE(szExt));
hres = _GetProgIDDescrFromExt(szExt, szProgIDDescr, &cchProgIDDescr);
if (SUCCEEDED(hres))
_SelectProgIDDescr(szProgIDDescr);
return hres;
}
HRESULT CFTEditDlg::_GetProgIDDescrFromExt(LPTSTR pszExt, LPTSTR pszProgIDDescr,
DWORD* pcchProgIDDescr)
{
IAssocInfo* pAI = NULL;
HRESULT hres = _pAssocStore->GetAssocInfo(pszExt, AIINIT_EXT, &pAI);
if (SUCCEEDED(hres))
{
hres = pAI->GetString(AISTR_PROGIDDESCR, pszProgIDDescr, pcchProgIDDescr);
pAI->Release();
}
return hres;
}
LRESULT CFTEditDlg::OnAdvancedButton(WORD wNotif)
{
DECLAREWAITCURSOR;
TCHAR szAdvBtnText[50];
SetWaitCursor();
_fAdvanced = !_fAdvanced;
LoadString(g_hinst, _fAdvanced ? IDS_FT_ADVBTNTEXTEXPAND : IDS_FT_ADVBTNTEXTCOLLAPS,
szAdvBtnText, ARRAYSIZE(szAdvBtnText));
SetWindowText(GetDlgItem(_hwnd, IDC_FT_EDIT_ADVANCED), szAdvBtnText);
_ConfigureDlg();
UpdateWindow(_hwnd);
if (_fAdvanced)
{
HWND hwndCombo = GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO);
// Is the combobox filled yet?
if (!ComboBox_GetCount(hwndCombo))
{
_FillProgIDDescrCombo();
// Select the <New> item
if (FAILED(_ProgIDComboHelper()))
{
TCHAR szNew[20];
if (LoadString(g_hinst, IDS_FT_NEW, szNew, ARRAYSIZE(szNew)))
{
int iIndex = ComboBox_FindStringExact(hwndCombo, -1, szNew);
if (CB_ERR != iIndex)
ComboBox_SetCurSel(hwndCombo, iIndex);
}
}
}
}
ResetWaitCursor();
return FALSE;
}
void CFTEditDlg::_ConfigureDlg()
{
// Need to:
// - position OK and Cancel
// - resize dlg
// - Show/hide Combo and its text
RECT rcControl;
RECT rcDialog;
RECT rcCancel;
RECT rcOK;
int iStdMargins = 0;
int iStdSpaceBetweenControls = 0;
GetWindowRect(_hwnd, &rcDialog);
GetWindowRect(GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO_TEXT),
&rcControl);
// Calculate the folowing (cannot be fixed, varies with dialog font)
// [msadek]; screen coordinates. need to consider the mirrored case
if(IS_WINDOW_RTL_MIRRORED(_hwnd))
{
iStdMargins = rcDialog.right - rcControl.right;
}
else
{
iStdMargins = rcControl.left - rcDialog.left;
}
iStdSpaceBetweenControls = MulDiv(4, iStdMargins, 7);
// Move Cancel and OK button
GetWindowRect(GetDlgItem(_hwnd,
_fAdvanced ? IDC_FT_EDIT_PID_COMBO : IDC_FT_EDIT_EXT_EDIT),
&rcControl);
MapWindowRect(HWND_DESKTOP, _hwnd, &rcControl);
GetWindowRect(GetDlgItem(_hwnd, IDCANCEL), &rcCancel);
MapWindowRect(HWND_DESKTOP, _hwnd, &rcCancel);
OffsetRect(&rcCancel, 0, -rcCancel.top);
GetWindowRect(GetDlgItem(_hwnd, IDOK), &rcOK);
MapWindowRect(HWND_DESKTOP, _hwnd, &rcOK);
OffsetRect(&rcOK, 0, -rcOK.top);
OffsetRect(&rcCancel, 0, rcControl.bottom + iStdSpaceBetweenControls);
OffsetRect(&rcOK, 0, rcControl.bottom + iStdSpaceBetweenControls);
SetWindowPos(GetDlgItem(_hwnd, IDOK), NULL,
rcOK.left, rcOK.top, 0, 0, SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOZORDER);
SetWindowPos(GetDlgItem(_hwnd, IDCANCEL), NULL,
rcCancel.left, rcCancel.top, 0, 0, SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOZORDER);
// Resize Dlg
ClientToScreen(_hwnd, ((POINT*)&rcCancel) + 1);
rcDialog.bottom = rcCancel.bottom + iStdMargins;
SetWindowPos(_hwnd, NULL,
0, 0, rcDialog.right - rcDialog.left, rcDialog.bottom - rcDialog.top,
SWP_NOMOVE|SWP_SHOWWINDOW|SWP_NOZORDER);
// Show/Hide Combo and its text
ShowWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO_TEXT), _fAdvanced);
ShowWindow(GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO), _fAdvanced);
// Set focus to combo
SetFocus(GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO));
}
LRESULT CFTEditDlg::OnOK(WORD wNotif)
{
HRESULT hres = S_FALSE;
// Pick up the extension
GetDlgItemText(_hwnd, IDC_FT_EDIT_EXT_EDIT, _pftEditParam->szExt,
_pftEditParam->dwExt);
// Is it empty?
if (0 != (*_pftEditParam->szExt))
{
// No, that's good
// FEATURE: do some check for valid extension name
IAssocInfo* pAI = NULL;
hres = _pAssocStore->GetAssocInfo(_pftEditParam->szExt,
AIINIT_EXT, &pAI);
if (SUCCEEDED(hres))
{
BOOL fExist = FALSE;
hres = pAI->GetBOOL(AIBOOL_EXTEXIST, &fExist);
// Is this extension already existing?
if (SUCCEEDED(hres) && !fExist)
{
// No, create it
// Check for spaces in the ext name
LPTSTR pszExt = _pftEditParam->szExt;
while (*pszExt && (S_FALSE != hres))
{
if (TEXT(' ') == *pszExt)
{
hres = S_FALSE;
ShellMessageBox(g_hinst, _hwnd,
MAKEINTRESOURCE(IDS_FT_MB_NOSPACEINEXT),
MAKEINTRESOURCE(IDS_FT), MB_OK | MB_ICONSTOP);
// Set focus to Ext combo
PostMessage(_hwnd, WM_CTRL_SETFOCUS, (WPARAM)0,
(LPARAM)GetDlgItem(_hwnd, IDC_FT_EDIT_EXT_EDIT));
}
++pszExt;
}
if (S_OK==hres)
hres = pAI->Create();
}
if (S_OK==hres)
hres = _HandleProgIDAssoc(pAI, _pftEditParam->szExt, fExist);
pAI->Release();
}
}
else
{
ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_FT_MB_NOEXT),
MAKEINTRESOURCE(IDS_FT), MB_OK | MB_ICONSTOP);
// Set focus to Ext combo
PostMessage(_hwnd, WM_CTRL_SETFOCUS, (WPARAM)0,
(LPARAM)GetDlgItem(_hwnd, IDC_FT_EDIT_EXT_EDIT));
}
// If we fail, we are in serious trouble, so we just close the dialog
ASSERT(SUCCEEDED(hres));
if (S_FALSE != hres)
EndDialog(_hwnd, IDOK);
return FALSE;
}
HRESULT CFTEditDlg::_GetProgIDInfo(IAssocInfo* pAI, LPTSTR pszProgID,
DWORD* pcchProgID, BOOL* pfNewProgID, BOOL* pfExplicitNew)
{
HWND hwndCombo = GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO);
*pfNewProgID = FALSE;
*pfExplicitNew = FALSE;
if (ComboBox_GetCount(hwndCombo))
{
int iSel = ComboBox_GetCurSel(hwndCombo);
if (CB_ERR != iSel)
{
LPTSTR pszTmpProgID = (LPTSTR)ComboBox_GetItemData(hwndCombo, iSel);
// Is this the "<New>" item (the only one with a ProgID == NULL)?
if (!pszTmpProgID)
{
// Yes
*pfNewProgID = TRUE;
*pfExplicitNew = TRUE;
}
else
{
// No
StrCpyN(pszProgID, pszTmpProgID, *pcchProgID);
}
}
}
else
{
*pfNewProgID = TRUE;
}
return S_OK;
}
HRESULT CFTEditDlg::_HandleProgIDAssoc(IAssocInfo* pAI, LPTSTR pszExt, BOOL fExtExist)
{
TCHAR szProgID[MAX_PROGID];
DWORD cchProgID = ARRAYSIZE(szProgID);
BOOL fNewProgID = FALSE;
BOOL fExplicitNew = FALSE;
*szProgID = 0;
HRESULT hres = _GetProgIDInfo(pAI, szProgID, &cchProgID, &fNewProgID, &fExplicitNew);
if (SUCCEEDED(hres))
{
// Is this Extension already existing?
if (fExtExist)
{
//
// First make sure it's not the exact same ext - progID assoc
//
TCHAR szTmpProgID[MAX_PROGID];
DWORD cchTmpProgID = ARRAYSIZE(szTmpProgID);
hres = pAI->GetString(AISTR_PROGID, szTmpProgID, &cchTmpProgID);
// Did we got a progID?
if (SUCCEEDED(hres))
{
// Yes
// Are they the same?
if (0 == lstrcmpi(szTmpProgID, szProgID))
{
// Yes, fail, nothing more to do
hres = E_FAIL;
}
else
{
// No, go on
hres = S_OK;
}
}
else
{
// No, there probably is no ProgID, go on
hres = S_OK;
}
//
// Unless the user chose <New> explicitly ask if he wants to break the assoc
//
// Did the user explicitly chose <New> (and we did not failed already)?
if (!fExplicitNew && SUCCEEDED(hres))
{
// We need to warn user that he will break existing assoc
TCHAR szProgIDDescr[MAX_PROGIDDESCR];
DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr);
hres = pAI->GetString(AISTR_PROGIDDESCR, szProgIDDescr, &cchProgIDDescr);
if (SUCCEEDED(hres))
{
if (IDNO == ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_FT_EDIT_ALREADYASSOC),
MAKEINTRESOURCE(IDS_FT_EDIT_ALRASSOCTITLE), MB_YESNO | MB_ICONEXCLAMATION,
pszExt, szProgIDDescr, pszExt, szProgIDDescr))
{
// S_FALSE means user does not want to go on
hres = S_FALSE;
}
}
else
{
// no progIDDescr... Check if we have a progID
TCHAR szProgID[MAX_PROGID];
DWORD cchProgID = ARRAYSIZE(szProgID);
hres = pAI->GetString(AISTR_PROGID, szProgID, &cchProgID);
if (FAILED(hres))
{
// no progID, set hres to S_OK so that we go on and create one
hres = S_OK;
}
}
}
}
// Should we go on and create new progID?
if (S_OK==hres && fNewProgID)
{
// Yes, create it
IAssocInfo* pAIProgID = NULL;
hres = _pAssocStore->GetAssocInfo(NULL, AIINIT_PROGID, &pAIProgID);
if (SUCCEEDED(hres))
{
hres = pAIProgID->Create();
if (SUCCEEDED(hres))
{
TCHAR szExt[MAX_EXT];
DWORD cchExt = ARRAYSIZE(szExt);
TCHAR szProgIDDescr[MAX_PROGIDDESCR];
HRESULT hresTmp = pAI->GetString(AISTR_EXT, szExt, &cchExt);
if (SUCCEEDED(hresTmp) && *szExt)
{
MakeDefaultProgIDDescrFromExt(szProgIDDescr, ARRAYSIZE(szProgIDDescr), szExt);
hresTmp = pAIProgID->SetString(AISTR_PROGIDDESCR, szProgIDDescr);
}
// Get the ProgID for later use
pAIProgID->GetString(AISTR_PROGID, szProgID, &cchProgID);
}
pAIProgID->Release();
}
}
if (S_OK==hres)
{
// Set the new extension progID
hres = pAI->SetString(AISTR_PROGID, szProgID);
if (SUCCEEDED(hres))
{
// Get the description
pAI->GetString(AISTR_PROGIDDESCR, _pftEditParam->szProgIDDescr,
&(_pftEditParam->dwProgIDDescr));
}
}
}
return hres;
}
LRESULT CFTEditDlg::OnCancel(WORD wNotif)
{
EndDialog(_hwnd, IDCANCEL);
return FALSE;
}
HRESULT CFTEditDlg::_FillProgIDDescrCombo()
{
HWND hwndCombo = GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO);
// Data stuff
IEnumAssocInfo* pEnum = NULL;
HRESULT hres = _pAssocStore->EnumAssocInfo(
ASENUM_PROGID | ASENUM_ASSOC_ALL, NULL, AIINIT_NONE, &pEnum);
if (SUCCEEDED(hres))
{
IAssocInfo* pAI = NULL;
while ((E_OUTOFMEMORY != hres) && (S_OK == pEnum->Next(&pAI)))
{
TCHAR szProgIDDescr[MAX_PROGIDDESCR];
DWORD cchProgIDDescr = ARRAYSIZE(szProgIDDescr);
hres = pAI->GetString(AISTR_PROGIDDESCR, szProgIDDescr, &cchProgIDDescr);
if (SUCCEEDED(hres))
{
int iIndex = CB_ERR;
if (*szProgIDDescr)
{
if (CB_ERR == ComboBox_FindStringExact(hwndCombo, -1, szProgIDDescr))
iIndex = ComboBox_AddString(hwndCombo, szProgIDDescr);
}
if ((CB_ERR != iIndex) && (CB_ERRSPACE != iIndex))
{
TCHAR szProgID[MAX_PROGID];
DWORD cchProgID = ARRAYSIZE(szProgID);
hres = pAI->GetString(AISTR_PROGID, szProgID, &cchProgID);
if (SUCCEEDED(hres))
{
LPTSTR pszProgID = _AddProgID(szProgID);
if (pszProgID)
{
lstrcpy(pszProgID, szProgID);
ComboBox_SetItemData(hwndCombo, iIndex, pszProgID);
}
else
{
// Out of memory
hres = E_OUTOFMEMORY;
ShellMessageBox(g_hinst, _hwnd, MAKEINTRESOURCE(IDS_ERROR +
ERROR_NOT_ENOUGH_MEMORY), MAKEINTRESOURCE(IDS_FT),
MB_OK | MB_ICONSTOP);
// Already allocated mem will be cleaned-up in OnDestroy
}
}
}
}
pAI->Release();
}
pEnum->Release();
if (SUCCEEDED(hres))
{
TCHAR szNew[20];
if (LoadString(g_hinst, IDS_FT_NEW, szNew, ARRAYSIZE(szNew)))
{
int iIndex = ComboBox_InsertString(hwndCombo, 0, szNew);
if (CB_ERR != iIndex)
ComboBox_SetItemData(hwndCombo, iIndex, NULL);
}
}
}
return hres;
}
BOOL CFTEditDlg::_SelectProgIDDescr(LPTSTR pszProgIDDescr)
{
int iIndex = ComboBox_SelectString(GetDlgItem(_hwnd, IDC_FT_EDIT_PID_COMBO),
-1, pszProgIDDescr);
return ((CB_ERR != iIndex) ? TRUE : FALSE);
}
LRESULT CFTEditDlg::OnDestroy(WPARAM wParam, LPARAM lParam)
{
_CleanupProgIDs();
CFTDlg::OnDestroy(wParam, lParam);
return FALSE;
}
LPTSTR CFTEditDlg::_AddProgID(LPTSTR pszProgID)
{
ASSERT(_hHeapProgID);
return (LPTSTR)HeapAlloc(_hHeapProgID, 0, (lstrlen(pszProgID) + 1) * sizeof(TCHAR));
}
void CFTEditDlg::_CleanupProgIDs()
{
if (_hHeapProgID)
HeapDestroy(_hHeapProgID);
}
///////////////////////////////////////////////////////////////////////////////
// Windows boiler plate code
LRESULT CFTEditDlg::OnCommand(WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = FALSE;
switch(GET_WM_COMMAND_ID(wParam, lParam))
{
case IDC_FT_EDIT_ADVANCED:
lRes = OnAdvancedButton(GET_WM_COMMAND_CMD(wParam, lParam));
break;
case IDC_FT_EDIT_EXT_EDIT:
lRes = OnEdit(GET_WM_COMMAND_CMD(wParam, lParam));
break;
default:
lRes = CFTDlg::OnCommand(wParam, lParam);
break;
}
return lRes;
}
LRESULT CFTEditDlg::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = FALSE;
switch(uMsg)
{
case WM_TIMER:
if (ID_TIMER == wParam)
lRes = OnTimer((UINT)wParam);
else
lRes = CFTDlg::WndProc(uMsg, wParam, lParam);
break;
default:
lRes = CFTDlg::WndProc(uMsg, wParam, lParam);
break;
}
return lRes;
}