mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
844 lines
22 KiB
844 lines
22 KiB
/*
|
|
* template - Dialog box property sheet for "Templates"
|
|
*/
|
|
|
|
#include "tweakui.h"
|
|
|
|
#define ctchProgMax 80
|
|
|
|
#pragma BEGIN_CONST_DATA
|
|
|
|
const static DWORD CODESEG rgdwHelp[] = {
|
|
IDC_TEMPLATETEXT, IDH_TEMPLATE,
|
|
IDC_TEMPLATE, IDH_TEMPLATE,
|
|
IDC_LVDELETE, IDH_TEMPLATEDEL,
|
|
0, 0,
|
|
};
|
|
|
|
#pragma END_CONST_DATA
|
|
|
|
typedef struct TI { /* ti - template info */
|
|
BYTE isi; /* Index to state icon */
|
|
HKEY hkRoot; /* Root for locating the key */
|
|
/* HKCR or HKCR\CLSID */
|
|
TCH tszExt[10]; /* Filename extension (for icon refresh) */
|
|
TCH tszKey[ctchKeyMax + 6]; /* 6 = strlen("\\CLSID") */
|
|
} TI, *PTI;
|
|
|
|
#define itiPlvi(plvi) ((UINT)(plvi)->lParam)
|
|
#define ptiIti(iti) (&ptdii->pti[iti])
|
|
#define ptiPlvi(plvi) ptiIti(itiPlvi(plvi))
|
|
|
|
typedef struct TDII {
|
|
Declare_Gxa(TI, ti);
|
|
WNDPROC wpTemplate;
|
|
BOOL fRundll; /* Need to run Rundll on Apply */
|
|
} TDII, *PTDII;
|
|
|
|
TDII tdii;
|
|
#define ptdii (&tdii)
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ptszStrRChr
|
|
*
|
|
* Get the rightmost occurrence.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
PTSTR PASCAL
|
|
ptszStrRChr(PCTSTR ptsz, TCH tch)
|
|
{
|
|
PTSTR ptszRc = 0;
|
|
for (ptsz = ptszStrChr(ptsz, tch); ptsz; ptsz = ptszStrChr(ptsz + 1, tch)) {
|
|
ptszRc = (PTSTR)ptsz;
|
|
}
|
|
return ptszRc;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* ptszFilenameCqn
|
|
*
|
|
* Get the filename part of a cqn.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
PTSTR PASCAL
|
|
ptszFilenameCqn(PCTSTR cqn)
|
|
{
|
|
PTSTR ptsz = ptszStrRChr(cqn, TEXT('\\'));
|
|
return ptsz ? ptsz + 1 : (PTSTR)cqn;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Path_Append
|
|
*
|
|
* Append a filename to a directory, inserting a backslash
|
|
* as necessary.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void
|
|
Path_Append(LPTSTR ptszDir, LPCTSTR ptszFile)
|
|
{
|
|
ptszDir = TweakUi_TrimTrailingBs(ptszDir);
|
|
*ptszDir++ = TEXT('\\');
|
|
lstrcpy(ptszDir, ptszFile);
|
|
|
|
}
|
|
/*****************************************************************************
|
|
*
|
|
* Template_NudgeExplorer
|
|
*
|
|
* Explorer doesn't recognize changes to templates until an application
|
|
* terminates, so we simply execute Rundll spuriously. It realizes that
|
|
* there is nothing to do and exits. This exit triggers Explorer to
|
|
* rebuild the filename extension list.
|
|
*
|
|
* This nudge doesn't work on NT 5, so we also have to nuke the
|
|
* ShellNew cache.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#pragma BEGIN_CONST_DATA
|
|
ConstString(c_tszRundll, "rundll32");
|
|
#pragma END_CONST_DATA
|
|
|
|
void PASCAL
|
|
Template_NudgeExplorer(void)
|
|
{
|
|
WinExec(c_tszRundll, SW_HIDE);
|
|
|
|
RegDeleteTree(g_hkCUSMWCV, TEXT("Explorer\\Discardable\\PostSetup\\ShellNew"));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_SubkeyExists
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Template_SubkeyExists(HKEY hk, PCTSTR ptszSubkey)
|
|
{
|
|
return GetRegStr(hk, 0, ptszSubkey, 0, 0);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_AddTemplateInfo
|
|
*
|
|
* pti must be the next ti in the array (i.e., Misc_AllocPx)
|
|
*
|
|
* Returns the icon index, if successful, or -1 on error.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int PASCAL
|
|
Template_AddTemplateInfo(HWND hwnd, PCTSTR ptszExt, PTI pti, BOOL fCheck)
|
|
{
|
|
int iRc;
|
|
SHFILEINFO sfi;
|
|
if (SHGetFileInfo(ptszExt, 0, &sfi, cbX(sfi),
|
|
SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES |
|
|
SHGFI_SYSICONINDEX | SHGFI_SMALLICON)) {
|
|
pti->isi = fCheck + 1;
|
|
iRc = LV_AddItem(hwnd, ptdii->cti++, sfi.szTypeName, sfi.iIcon, fCheck);
|
|
} else {
|
|
iRc = -1;
|
|
}
|
|
return iRc;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* TemplateCallbackInfo
|
|
*
|
|
* Information handed to a template callback.
|
|
*
|
|
* hk - The ptszShellNew subkey itself
|
|
*
|
|
*****************************************************************************/
|
|
|
|
typedef BOOL (PASCAL *TCICALLBACK)(struct TCI *ptci, HKEY hk,
|
|
PCTSTR ptszShellNew);
|
|
|
|
typedef struct TCI {
|
|
TCICALLBACK pfn;
|
|
PTI pti; /* Template info containing result */
|
|
HWND hwnd; /* Listview window handle */
|
|
PCTSTR ptszExt; /* The .ext being studied */
|
|
} TCI, *PTCI;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_CheckShellNew
|
|
*
|
|
* Look for the ShellNew stuff (or ShellNew- if temporarily disabled).
|
|
*
|
|
* Returns boolean success/failure.
|
|
*
|
|
* If ptszExt exists, then we create the key, too.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Template_CheckShellNew(PTCI ptci, HKEY hkBase, PCTSTR ptszShellNew)
|
|
{
|
|
HKEY hk;
|
|
BOOL fRc;
|
|
if (_RegOpenKey(hkBase, ptszShellNew, &hk) == 0) {
|
|
if (Template_SubkeyExists(hk, c_tszNullFile) ||
|
|
Template_SubkeyExists(hk, c_tszFileName) ||
|
|
Template_SubkeyExists(hk, c_tszCommand) ||
|
|
Template_SubkeyExists(hk, c_tszData)) {
|
|
fRc = ptci->pfn(ptci, hk, ptszShellNew);
|
|
} else {
|
|
fRc = 0;
|
|
}
|
|
RegCloseKey(hk);
|
|
} else {
|
|
fRc = 0;
|
|
}
|
|
return fRc;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_AddHkeyTemplate
|
|
*
|
|
* We have a candidate location for a ShellNew.
|
|
*
|
|
* There is some weirdness here. The actual ShellNew can live at
|
|
* a sublevel. For example, the ".doc" extension contains several
|
|
* ShellNew's:
|
|
*
|
|
* HKCR\.doc = WordPad.Document.1
|
|
* HKCR\.doc\WordDocument\ShellNew
|
|
* HKCR\.doc\Word.Document.6\ShellNew
|
|
* HKCR\.doc\WordPad.Document.1\ShellNew
|
|
*
|
|
* Based on the main value (HKCR\.doc), we choose to use the template
|
|
* for "Wordpad.Document.1".
|
|
*
|
|
* pti->hkRoot - hkey at which to start (either HKCR or HKCR\CLSID)
|
|
* pti->tszKey - subkey to open (.ext or {guid})
|
|
*
|
|
* pti->hkRoot\pti->tszKey = actual key to open
|
|
*
|
|
* hkBase = the key at hkRoot\ptszKey
|
|
* hk = the key where ShellNew actually lives
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Template_AddHkeyTemplate(PTCI ptci)
|
|
{
|
|
HKEY hkBase;
|
|
BOOL fRc;
|
|
PTI pti = ptci->pti;
|
|
if (_RegOpenKey(pti->hkRoot, pti->tszKey, &hkBase) == 0) {
|
|
TCH tszProg[ctchProgMax+1];
|
|
if (GetRegStr(hkBase, 0, 0, tszProg, cbX(tszProg))) {
|
|
HKEY hk = NULL;
|
|
if (_RegOpenKey(hkBase, tszProg, &hk) == 0) {
|
|
lstrcatnBsA(pti->tszKey, tszProg);
|
|
} else {
|
|
_RegOpenKey(hkBase, 0, &hk); /* hk = AddRef(hkBase) */
|
|
}
|
|
if (hk) {
|
|
/* Now open the ShellNew subkey or the ShellNew- subkey */
|
|
fRc = fLorFF(Template_CheckShellNew(ptci, hk, c_tszShellNew),
|
|
Template_CheckShellNew(ptci, hk, c_tszShellNewDash));
|
|
RegCloseKey(hk);
|
|
} else {
|
|
fRc = 0;
|
|
}
|
|
} else {
|
|
fRc = 0;
|
|
}
|
|
} else {
|
|
fRc = 0;
|
|
}
|
|
return fRc;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_LocateExtension
|
|
*
|
|
* We have a filename extension (ptci->ptszExt).
|
|
*
|
|
* Get its program id (progid).
|
|
*
|
|
* We look in two places. If the progid has a registered CLSID
|
|
* (HKCR\progid\CLSID), then we look in HKCR\CLSID\{guid}.
|
|
*
|
|
* If the CLSID fails to locate anything, then we look under
|
|
* HKCR\.ext directly.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Template_LocateExtension(PTCI ptci)
|
|
{
|
|
BOOL fRc;
|
|
PTI pti = ptci->pti = (PTI)Misc_AllocPx(&ptdii->gxa);
|
|
if (pti) {
|
|
TCH tszProg[ctchProgMax + ctchKeyMax + 6]; /* 6 = strlen(\\CLSID) */
|
|
lstrcpyn(pti->tszExt, ptci->ptszExt, cA(pti->tszExt));
|
|
if (GetRegStr(hkCR, ptci->ptszExt, 0, tszProg, cbCtch(ctchProgMax)) &&
|
|
tszProg[0]) {
|
|
/*
|
|
* Make sure the progid exists, or we end up putting garbage
|
|
* into the listview.
|
|
*/
|
|
if (RegKeyExists(hkCR, tszProg)) {
|
|
|
|
/*
|
|
* Is this an OLE class?
|
|
*/
|
|
lstrcatnBsA(tszProg, c_tszClsid);
|
|
if (GetRegStr(hkCR, tszProg, 0,
|
|
pti->tszKey, cbX(pti->tszKey))) {
|
|
pti->hkRoot = pcdii->hkClsid;
|
|
fRc = Template_AddHkeyTemplate(ptci);
|
|
} else {
|
|
fRc = 0;
|
|
}
|
|
|
|
/*
|
|
* If we haven't succeeded yet, then try under the extension
|
|
* itself.
|
|
*/
|
|
if (!fRc) {
|
|
pti->hkRoot = hkCR;
|
|
lstrcpyn(pti->tszKey, ptci->ptszExt, cA(pti->tszKey));
|
|
fRc = Template_AddHkeyTemplate(ptci);
|
|
}
|
|
} else {
|
|
fRc = 0;
|
|
}
|
|
} else {
|
|
fRc = 0;
|
|
}
|
|
} else {
|
|
fRc = 0;
|
|
}
|
|
return fRc;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_AddTemplates_AddMe
|
|
*
|
|
* Add any templates that exist.
|
|
*
|
|
* For each filename extension, get its corresponding class.
|
|
* Then ask Template_LocateExtension to do the rest.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Template_AddTemplates_AddMe(PTCI ptci, HKEY hk, PCTSTR ptszShellNew)
|
|
{
|
|
return Template_AddTemplateInfo(ptci->hwnd, ptci->ptszExt,
|
|
ptci->pti,
|
|
ptszShellNew == c_tszShellNew) + 1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_AddTemplates
|
|
*
|
|
* Add any templates that exist.
|
|
*
|
|
* For each filename extension, get its corresponding class.
|
|
* Then ask Template_LocateExtension to do the rest.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Template_AddTemplates(HWND hwnd)
|
|
{
|
|
int i;
|
|
TCI tci;
|
|
TCH tszExt[10];
|
|
|
|
tci.pfn = Template_AddTemplates_AddMe;
|
|
tci.hwnd = hwnd;
|
|
tci.ptszExt = tszExt;
|
|
|
|
HCURSOR hcurPrev = SetCursor(LoadCursor(0, IDC_WAIT));
|
|
|
|
for (i = 0; ; i++) {
|
|
switch (RegEnumKey(HKEY_CLASSES_ROOT, i, tszExt, cbX(tszExt))) {
|
|
case ERROR_SUCCESS:
|
|
/*
|
|
* Don't show ".lnk" in the templates list because it's weird.
|
|
*/
|
|
if (tszExt[0] == TEXT('.') && lstrcmpi(tszExt, c_tszDotLnk)) {
|
|
Template_LocateExtension(&tci);
|
|
}
|
|
break;
|
|
|
|
case ERROR_MORE_DATA: /* Can't be a .ext if > 10 */
|
|
break;
|
|
|
|
default: goto endenum;
|
|
}
|
|
}
|
|
endenum:;
|
|
SetCursor(hcurPrev);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* File template callback info
|
|
*
|
|
*****************************************************************************/
|
|
|
|
typedef struct FTCI {
|
|
TCI tci;
|
|
PCTSTR ptszSrc;
|
|
PCTSTR ptszDst;
|
|
PCTSTR ptszLastBS;
|
|
PCTSTR ptszShellNew;
|
|
} FTCI, *PFTCI;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_CopyFile
|
|
*
|
|
* Copy a file with the hourglass.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Template_CopyFile(PFTCI pftci)
|
|
{
|
|
HCURSOR hcurPrev;
|
|
BOOL fRc;
|
|
hcurPrev = SetCursor(LoadCursor(0, MAKEINTRESOURCE(IDC_WAIT)));
|
|
fRc = CopyFile(pftci->ptszSrc, pftci->ptszDst, 0);
|
|
SetCursor(hcurPrev);
|
|
return fRc;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_AddFileTemplate_CheckMe
|
|
*
|
|
* Make sure the key isn't a Command key.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Template_AddFileTemplate_CheckMe(PTCI ptci, HKEY hk, PCTSTR ptszShellNew)
|
|
{
|
|
PFTCI pftci = (PFTCI)ptci;
|
|
pftci->ptszShellNew = ptszShellNew;
|
|
if (Template_SubkeyExists(hk, c_tszCommand)) {
|
|
ptci->ptszExt = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_IsTemplatable
|
|
*
|
|
* Determine whether there is an application that can handle this
|
|
* extension. We assume it's okay if the item is not self-executing.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Template_IsTemplatable(PCTSTR ptszFile)
|
|
{
|
|
LONG cb;
|
|
TCH tszShort[MAX_PATH];
|
|
DWORD ctch;
|
|
|
|
ctch = GetFullPathName(ptszFile, cA(tszShort), tszShort, NULL);
|
|
if (ctch && ctch < MAX_PATH) {
|
|
/* If this fails, just proceed with the value from GFPN */
|
|
GetShortPathName(ptszFile, tszShort, cA(tszShort));
|
|
|
|
TCH tszExe[MAX_PATH];
|
|
if (FindExecutable(tszShort, NULL, tszExe) >= (HINSTANCE)IntToPtr(HINSTANCE_ERROR)) {
|
|
return lstrcmpi(tszExe, tszShort) != 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_ReplaceTemplate
|
|
*
|
|
* Replace the current template with the new one.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
UINT PASCAL
|
|
Template_ReplaceTemplate(PFTCI pftci)
|
|
{
|
|
#define ptci (&pftci->tci)
|
|
UINT id;
|
|
if (ptci->ptszExt) {
|
|
if (MessageBoxId(GetParent(ptci->hwnd), IDS_CONFIRMNEWTEMPLATE,
|
|
pftci->ptszSrc,
|
|
MB_YESNO | MB_DEFBUTTON2 | MB_SETFOREGROUND)
|
|
== IDYES) {
|
|
HKEY hk;
|
|
lstrcatnBsA(ptci->pti->tszKey, pftci->ptszShellNew);
|
|
if (_RegOpenKey(ptci->pti->hkRoot, ptci->pti->tszKey, &hk) == 0) {
|
|
if (Template_CopyFile(pftci)) {
|
|
RegDeleteValue(hk, c_tszNullFile);
|
|
RegDeleteValue(hk, c_tszData);
|
|
RegSetValuePtsz(hk, c_tszFileName, pftci->ptszLastBS+1);
|
|
id = 0;
|
|
} else {
|
|
id = IDS_COPYFAIL;
|
|
}
|
|
RegCloseKey(hk);
|
|
} else {
|
|
id = IDS_REGFAIL;
|
|
}
|
|
} else {
|
|
id = 0;
|
|
}
|
|
} else {
|
|
id = IDS_CANNOTTEMPLATE;
|
|
}
|
|
return id;
|
|
}
|
|
#undef ptci
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_AddFileTemplate
|
|
*
|
|
* Add the file as a new template type.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
UINT PASCAL
|
|
Template_AddFileTemplate(HWND hwnd, PCTSTR ptszSrc)
|
|
{
|
|
#define pftci (&ftci)
|
|
UINT id;
|
|
FTCI ftci;
|
|
pftci->tci.pfn = Template_AddFileTemplate_CheckMe;
|
|
pftci->tci.hwnd = hwnd;
|
|
pftci->ptszSrc = ptszSrc;
|
|
pftci->ptszLastBS = ptszFilenameCqn(ptszSrc) - 1; /* -> \filename.ext */
|
|
if (pftci->ptszLastBS) {
|
|
pftci->tci.ptszExt = ptszStrRChr(pftci->ptszLastBS, '.'); /* -> .ext */
|
|
if (pftci->tci.ptszExt) {
|
|
HKEY hk;
|
|
if (_RegOpenKey(hkCR, pftci->tci.ptszExt, &hk) == 0) {
|
|
if (Template_IsTemplatable(ptszSrc)) {
|
|
PTI pti;
|
|
TCH tszDst[MAX_PATH];
|
|
pftci->ptszDst = tszDst;
|
|
SHGetPathFromIDList(pcdii->pidlTemplates, tszDst);
|
|
lstrcatnBsA(tszDst, pftci->ptszLastBS+1);
|
|
/* Snoop at the next pti to ensure we can get it later */
|
|
pti = (PTI)Misc_AllocPx(&ptdii->gxa);
|
|
if (pti) {
|
|
if (Template_LocateExtension(&pftci->tci)) {
|
|
id = Template_ReplaceTemplate(pftci);
|
|
} else {
|
|
if (Template_CopyFile(pftci)) {
|
|
HKEY hk2;
|
|
if (RegCreateKey(hk, c_tszShellNew, &hk2) == 0) {
|
|
RegSetValuePtsz(hk2, c_tszFileName, pftci->ptszLastBS+1);
|
|
RegCloseKey(hk2);
|
|
Misc_LV_SetCurSel(hwnd,
|
|
Template_AddTemplateInfo(hwnd,
|
|
pftci->tci.ptszExt, pti, 1));
|
|
Template_NudgeExplorer();
|
|
id = 0; /* No problemo */
|
|
} else {
|
|
id = IDS_REGFAIL;
|
|
}
|
|
} else {
|
|
id = IDS_COPYFAIL;
|
|
}
|
|
}
|
|
} else {
|
|
id = 0; /* out of memory! */
|
|
}
|
|
} else {
|
|
id = IDS_BADEXT;
|
|
}
|
|
RegCloseKey(hk);
|
|
} else {
|
|
id = IDS_BADEXT;
|
|
}
|
|
} else {
|
|
id = IDS_BADEXT;
|
|
}
|
|
} else {
|
|
id = 0; /* This can't happen! */
|
|
}
|
|
return id;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Tools_Template_OnDropFiles
|
|
*
|
|
* Put the file into the template edit control.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Tools_Template_OnDropFiles(HWND hwnd, HDROP hdrop)
|
|
{
|
|
if (DragQueryFile(hdrop, (UINT)-1, 0, 0) == 1) {
|
|
UINT id;
|
|
TCH tszSrc[MAX_PATH];
|
|
|
|
DragQueryFile(hdrop, 0, tszSrc, cA(tszSrc));
|
|
id = Template_AddFileTemplate(hwnd, tszSrc);
|
|
if (id) {
|
|
MessageBoxId(GetParent(hwnd), id, tszSrc, MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
} else {
|
|
MessageBoxId(GetParent(hwnd), IDS_TOOMANY, g_tszName,
|
|
MB_OK | MB_SETFOREGROUND);
|
|
}
|
|
DragFinish(hdrop);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Tools_Template_WndProc
|
|
*
|
|
* Subclass procedure so we can handle drag-drop to the template
|
|
* edit control.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
LRESULT EXPORT
|
|
Tools_Template_WndProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (wm) {
|
|
case WM_DROPFILES:
|
|
Tools_Template_OnDropFiles(hwnd, (HDROP)wParam);
|
|
return 0;
|
|
}
|
|
return CallWindowProc(ptdii->wpTemplate, hwnd, wm, wParam, lParam);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_GetIcon
|
|
*
|
|
* Produce the icon associated with an item. This is called when
|
|
* we need to rebuild the icon list after the icon cache has been
|
|
* purged.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int PASCAL
|
|
Template_GetIcon(LPARAM iti)
|
|
{
|
|
SHFILEINFO sfi;
|
|
PTI pti = ptiIti(iti);
|
|
sfi.iIcon = 0;
|
|
OutputDebugString(pti->tszExt);
|
|
SHGetFileInfo(pti->tszExt, 0, &sfi, cbX(sfi),
|
|
SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
|
|
return sfi.iIcon;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_OnInitDialog
|
|
*
|
|
* Turn the "drop a file here" gizmo into a valid drop target.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Template_OnInitDialog(HWND hwnd)
|
|
{
|
|
ptdii->wpTemplate = SubclassWindow(hwnd, Tools_Template_WndProc);
|
|
DragAcceptFiles(hwnd, 1);
|
|
|
|
if (Misc_InitPgxa(&ptdii->gxa, cbX(TI))) {
|
|
Template_AddTemplates(hwnd);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_OnDelete
|
|
*
|
|
* Really nuke it. The interaction between this and adding a new
|
|
* template is sufficiently weird that I don't want to try to do
|
|
* delayed-action.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Template_OnDelete(HWND hwnd, int iItem)
|
|
{
|
|
LV_ITEM lvi;
|
|
HKEY hk;
|
|
PTI pti;
|
|
TCH tszDesc[MAX_PATH];
|
|
lvi.pszText = tszDesc;
|
|
lvi.cchTextMax = cA(tszDesc);
|
|
Misc_LV_GetItemInfo(hwnd, &lvi, iItem, LVIF_PARAM | LVIF_TEXT);
|
|
pti = ptiPlvi(&lvi);
|
|
if (MessageBoxId(GetParent(hwnd), IDS_TEMPLATEDELETEWARN,
|
|
lvi.pszText, MB_YESNO | MB_DEFBUTTON2) == IDYES) {
|
|
if (_RegOpenKey(pti->hkRoot, pti->tszKey, &hk) == 0) {
|
|
RegDeleteTree(hk, c_tszShellNewDash);
|
|
RegDeleteTree(hk, c_tszShellNew);
|
|
ListView_DeleteItem(hwnd, iItem);
|
|
Misc_LV_EnsureSel(hwnd, iItem);
|
|
Common_SetDirty(GetParent(hwnd));
|
|
RegCloseKey(hk);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_OnSelChange
|
|
*
|
|
* Disable the Remove button if we can't remove the thing.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Template_OnSelChange(HWND hwnd, int iItem)
|
|
{
|
|
PTI pti = ptiIti(Misc_LV_GetParam(hwnd, iItem));
|
|
HKEY hk;
|
|
BOOL fEnable;
|
|
if (_RegOpenKey(pti->hkRoot, pti->tszKey, &hk) == 0) {
|
|
if (GetRegStr(hk, pti->isi == isiUnchecked ?
|
|
c_tszShellNewDash : c_tszShellNew, c_tszCommand, 0, 0)) {
|
|
fEnable = 0;
|
|
} else {
|
|
fEnable = 1;
|
|
}
|
|
RegCloseKey(hk);
|
|
} else {
|
|
fEnable = 0;
|
|
}
|
|
EnableWindow(GetDlgItem(GetParent(hwnd), IDC_LVDELETE), fEnable);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_OnApply
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Template_OnApply(HWND hdlg)
|
|
{
|
|
HWND hwnd = GetDlgItem(hdlg, IDC_TEMPLATE);
|
|
int cItems = ListView_GetItemCount(hwnd);
|
|
BOOL fDirty;
|
|
LV_ITEM lvi;
|
|
|
|
fDirty = 0;
|
|
for (lvi.iItem = 0; lvi.iItem < cItems; lvi.iItem++) {
|
|
PTI pti;
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
Misc_LV_GetItemInfo(hwnd, &lvi, lvi.iItem, LVIF_PARAM | LVIF_STATE);
|
|
pti = ptiPlvi(&lvi);
|
|
|
|
if (pti->isi != isiPlvi(&lvi)) {
|
|
PCTSTR ptszFrom, ptszTo;
|
|
if (pti->isi == isiUnchecked) {
|
|
ptszFrom = c_tszShellNewDash;
|
|
ptszTo = c_tszShellNew;
|
|
} else {
|
|
ptszFrom = c_tszShellNew;
|
|
ptszTo = c_tszShellNewDash;
|
|
}
|
|
if (Misc_RenameReg(pti->hkRoot, pti->tszKey, ptszFrom, ptszTo)) {
|
|
pti->isi = isiPlvi(&lvi);
|
|
}
|
|
fDirty = 1;
|
|
}
|
|
}
|
|
if (fDirty) {
|
|
Template_NudgeExplorer();
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Template_OnDestroy
|
|
*
|
|
* Free the memory we allocated.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Template_OnDestroy(HWND hdlg)
|
|
{
|
|
Misc_FreePgxa(&ptdii->gxa);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Oh yeah, we need this too.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#pragma BEGIN_CONST_DATA
|
|
|
|
LVCI lvciTemplate[] = {
|
|
{ IDC_LVDELETE, Template_OnDelete },
|
|
{ 0, 0 },
|
|
};
|
|
|
|
LVV lvvTemplate = {
|
|
0, /* Template_OnCommand */
|
|
0, /* Template_OnInitContextMenu */
|
|
0, /* Template_Dirtify */
|
|
Template_GetIcon,
|
|
Template_OnInitDialog,
|
|
Template_OnApply,
|
|
Template_OnDestroy,
|
|
Template_OnSelChange,
|
|
3,
|
|
rgdwHelp,
|
|
0, /* Double-click action */
|
|
lvvflIcons | /* We need icons */
|
|
lvvflCanCheck | /* And check boxes */
|
|
lvvflCanDelete, /* and you can delete them too */
|
|
lvciTemplate,
|
|
};
|
|
|
|
#pragma END_CONST_DATA
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Our window procedure.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
INT_PTR EXPORT
|
|
Template_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return LV_DlgProc(&lvvTemplate, hdlg, wm, wParam, lParam);
|
|
}
|