/*
 * 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);
}
