437 lines
12 KiB
C++
437 lines
12 KiB
C++
/*
|
|
* control - Dialog box property sheet for "control panel"
|
|
*/
|
|
|
|
#include "tweakui.h"
|
|
|
|
/*
|
|
* cchFriendlyMax is used to hold control panel file descriptions.
|
|
*/
|
|
#define cchFriendlyMax 256
|
|
|
|
typedef struct CPL { /* control panel */
|
|
TCHAR tszFile[MAX_PATH]; /* File name */
|
|
} CPL, *PCPL;
|
|
|
|
#define icplPlvi(plvi) ((UINT)(plvi)->lParam)
|
|
#define pcplIcpl(icpl) (&pcpii->pcpl[icpl])
|
|
#define pcplPlvi(plvi) pcplIcpl(icplPlvi(plvi))
|
|
|
|
typedef struct CPII {
|
|
Declare_Gxa(CPL, cpl);
|
|
} CPII, *PCPII;
|
|
|
|
CPII cpii;
|
|
#define pcpii (&cpii)
|
|
|
|
TCHAR g_tszBoring[64];
|
|
|
|
#pragma BEGIN_CONST_DATA
|
|
|
|
const static DWORD CODESEG rgdwHelp[] = {
|
|
0, 0,
|
|
};
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Control_VerQueryDescription
|
|
*
|
|
* pull out the file description if we have one.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Control_VerQueryDescription(LPVOID pvData, UINT uiLang, UINT uiCharSet,
|
|
LPTSTR ptszBuf, UINT ctch)
|
|
{
|
|
TCHAR tsz[128];
|
|
LPWSTR pwsz;
|
|
BOOL fRc;
|
|
UINT cb;
|
|
|
|
wsprintf(tsz, TEXT("\\StringFileInfo\\%04X%04X\\")
|
|
TEXT("FileDescription"), uiLang, uiCharSet);
|
|
fRc = VerQueryValue(pvData, tsz, (LPVOID *)&pwsz, &cb);
|
|
|
|
if (fRc && cb > 0) {
|
|
#ifdef UNICODE
|
|
lstrcpyn(ptszBuf, pwsz, ctch);
|
|
#else
|
|
WideCharToMultiByte(CP_ACP, 0, pwsz, cb / cbX(WCHAR),
|
|
ptszBuf, MAX_PATH, NULL, NULL);
|
|
lstrcpyn(ptszBuf, (LPSTR)pwsz, ctch);
|
|
#endif
|
|
}
|
|
|
|
return fRc;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Control_GetFileDescription
|
|
*
|
|
* pull out the file description if we have one.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Control_GetFileDescription(LPTSTR ptszFile, LPTSTR ptszBuf, UINT ctch)
|
|
{
|
|
DWORD dwHandle;
|
|
UINT cb;
|
|
|
|
/*
|
|
* Assume it doesn't work.
|
|
*/
|
|
ptszBuf[0] = TEXT('\0');
|
|
|
|
cb = GetFileVersionInfoSize(ptszFile, &dwHandle);
|
|
if (cb) {
|
|
LPVOID pvData = lAlloc(cb);
|
|
if (pvData) {
|
|
LPWORD rgwTrans;
|
|
UINT uiSize;
|
|
|
|
if (GetFileVersionInfo(ptszFile, dwHandle, cb, pvData) &&
|
|
VerQueryValue(pvData, TEXT("\\VarFileInfo\\Translation"),
|
|
(LPVOID *)&rgwTrans, &uiSize)) {
|
|
if (Control_VerQueryDescription(pvData,
|
|
rgwTrans[0], rgwTrans[1],
|
|
ptszBuf, ctch) ||
|
|
/*
|
|
* Lots of people forget to set the language properly,
|
|
* so we will try English/USA regardless. And if that
|
|
* doesn't work, try English/NULL because some people
|
|
* do that too.
|
|
*/
|
|
Control_VerQueryDescription(pvData,
|
|
0x0409, 0x040E,
|
|
ptszBuf, ctch) ||
|
|
Control_VerQueryDescription(pvData,
|
|
0x0409, 0x0000,
|
|
ptszBuf, ctch)) {
|
|
}
|
|
}
|
|
lFree(pvData);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Control_GetShowState
|
|
*
|
|
* Determine whether a *.CPL file is currently shown in the
|
|
* Control Panel.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Control_GetShowState(LPCTSTR ptszName)
|
|
{
|
|
TCHAR tsz[10];
|
|
|
|
GetPrivateProfileString(c_tszDontLoad, ptszName,
|
|
c_tszNil, tsz, cA(tsz), c_tszControlIni);
|
|
|
|
return tsz[0] ? FALSE : TRUE;
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Control_SetShowState
|
|
*
|
|
* Set the registry/INI flag that tells us to hide/show the *.CPL file.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Control_SetShowState(LPCTSTR ptszName, BOOL fShow)
|
|
{
|
|
WritePrivateProfileString(c_tszDontLoad, ptszName,
|
|
fShow ? NULL : c_tszNo, c_tszControlIni);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Control_AddCpl
|
|
*
|
|
* Add a single *.CPL to the list.
|
|
*
|
|
* The display name is the CPL filename, followed by an optional
|
|
* parenthesized version description string. For control panels
|
|
* that ship with Windows 95 whose version strings isn't very good, we substitute
|
|
* our own.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#pragma BEGIN_CONST_DATA
|
|
|
|
LPCTSTR c_rgpszCpl[] = {
|
|
c_tszAppWizCpl,
|
|
c_tszDeskCpl,
|
|
c_tszIntlCpl,
|
|
c_tszMainCpl,
|
|
c_tszTimeDateCpl,
|
|
};
|
|
|
|
int PASCAL
|
|
Control_AddCpl(HWND hwnd, LPTSTR ptszName)
|
|
{
|
|
//
|
|
// On Windows 2000, ncpa.cpl is a stub that exists only for legacy
|
|
// purposes. It does exactly the same thing as the "Network
|
|
// Connections" icon that already exists in the Control Panel.
|
|
//
|
|
if (g_fNT5 && lstrcmpi(ptszName, TEXT("ncpa.cpl")) == 0) {
|
|
return -1;
|
|
}
|
|
|
|
PCPL pcpl = (PCPL)Misc_AllocPx(&pcpii->gxa);
|
|
TCHAR tszDesc[MAX_PATH];
|
|
TCHAR tszFull[MAX_PATH + 3 + MAX_PATH]; /* 3 = " - " */
|
|
|
|
if (pcpl) {
|
|
lstrcpy(pcpl->tszFile, ptszFilenameCqn(ptszName));
|
|
CharLower(pcpl->tszFile);
|
|
|
|
Control_GetFileDescription(ptszName, tszDesc, MAX_PATH);
|
|
|
|
/*
|
|
* Now clean up various weird cases.
|
|
*/
|
|
if (lstrcmpi(tszDesc, g_tszBoring) == 0) {
|
|
int i;
|
|
for (i = 0; i < cA(c_rgpszCpl); i++) {
|
|
if (lstrcmpi(pcpl->tszFile, c_rgpszCpl[i]) == 0) {
|
|
LoadString(hinstCur, IDS_CPL_ADDRM + i, tszDesc, cA(tszDesc));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
wsprintf(tszFull, TEXT("%s - %s"), pcpl->tszFile, tszDesc);
|
|
|
|
return LV_AddItem(hwnd, pcpii->ccpl++, tszFull, -1,
|
|
Control_GetShowState(pcpl->tszFile));
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Control_InitControls2
|
|
*
|
|
* Enumerate all the special DLLs in the MMCPL section and add them
|
|
* to the list. Note that the buffer sizes are exactly the same sizes
|
|
* that SHELL32 uses, so we won't miss anything that the shell itself
|
|
* doesn't.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Control_InitControls2(HWND hwnd)
|
|
{
|
|
LPTSTR ptsz;
|
|
TCHAR tszKeys[512];
|
|
TCHAR tszName[64];
|
|
|
|
GetPrivateProfileString(TEXT("MMCPL"), NULL, c_tszNil,
|
|
tszKeys, cA(tszKeys), c_tszControlIni);
|
|
|
|
for (ptsz = tszKeys; ptsz[0]; ptsz += lstrlen(ptsz) + 1) {
|
|
/*
|
|
* Some legacy keys to ignore:
|
|
*
|
|
* NumApps= <number of applets>
|
|
* H= <height>
|
|
* W= <width>
|
|
* X= <x coordinate>
|
|
* Y= <y coordinate>
|
|
*/
|
|
if (lstrcmpi(ptsz, TEXT("NumApps")) == 0) {
|
|
continue;
|
|
}
|
|
if (ptsz[1] == TEXT('\0')) {
|
|
switch (ptsz[0]) {
|
|
case 'H':
|
|
case 'W':
|
|
case 'X':
|
|
case 'Y': continue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* End of wacky legacy keys.
|
|
*/
|
|
|
|
GetPrivateProfileString(TEXT("MMCPL"), ptsz, c_tszNil,
|
|
tszName, cA(tszName), c_tszControlIni);
|
|
Control_AddCpl(hwnd, tszName);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Control_InitControls3
|
|
*
|
|
* Enumerate all the *.CPL files in the System folder
|
|
* and add them to the list.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Control_InitControls3(HWND hwnd)
|
|
{
|
|
WIN32_FIND_DATA wfd;
|
|
HANDLE h;
|
|
TCHAR tszSystemDir[MAX_PATH];
|
|
TCHAR tszPrevDir[MAX_PATH];
|
|
|
|
if (GetCurrentDirectory(cA(tszPrevDir), tszPrevDir) && /* For restore */
|
|
GetSystemDirectory(tszSystemDir, MAX_PATH) &&
|
|
SetCurrentDirectory(tszSystemDir)) {
|
|
|
|
h = FindFirstFile(c_tszStarCpl, &wfd);
|
|
if (h != INVALID_HANDLE_VALUE) {
|
|
do {
|
|
Control_AddCpl(hwnd, wfd.cFileName);
|
|
} while (FindNextFile(h, &wfd)) ;
|
|
FindClose(h);
|
|
}
|
|
SetCurrentDirectory(tszPrevDir);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Control_OnInitDialog
|
|
*
|
|
* Enumerate all the *.CPL files and add them to the list.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL PASCAL
|
|
Control_OnInitDialog(HWND hwnd)
|
|
{
|
|
HCURSOR hcurPrev = GetCursor();
|
|
SetCursor(LoadCursor(0, IDC_WAIT));
|
|
|
|
ZeroMemory(pcpii, cbX(*pcpii));
|
|
|
|
LoadString(hinstCur, IDS_CPL_BORING, g_tszBoring, cA(g_tszBoring));
|
|
|
|
if (Misc_InitPgxa(&pcpii->gxa, cbX(CPL))) {
|
|
Control_InitControls2(hwnd);
|
|
Control_InitControls3(hwnd);
|
|
}
|
|
|
|
SetCursor(hcurPrev);
|
|
return 1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Control_OnDestroy
|
|
*
|
|
* Free the memory we allocated.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Control_OnDestroy(HWND hdlg)
|
|
{
|
|
Misc_FreePgxa(&pcpii->gxa);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Control_LV_Dirtify
|
|
*
|
|
* Mark this item as having been changed during the property sheet
|
|
* page's lifetime.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Control_LV_Dirtify(LPARAM icpl)
|
|
{
|
|
// pcpii->pcpl[icpl].cplfl |= cplflEdited;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Control_OnApply
|
|
*
|
|
* Write the changes out.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void PASCAL
|
|
Control_OnApply(HWND hdlg)
|
|
{
|
|
HWND hwnd = GetDlgItem(hdlg, IDC_ICONLV);
|
|
int cItems = ListView_GetItemCount(hwnd);
|
|
BOOL fChanged = 0;
|
|
LV_ITEM lvi;
|
|
|
|
for (lvi.iItem = 0; lvi.iItem < cItems; lvi.iItem++) {
|
|
PCPL pcpl;
|
|
lvi.stateMask = LVIS_STATEIMAGEMASK;
|
|
Misc_LV_GetItemInfo(hwnd, &lvi, lvi.iItem, LVIF_PARAM | LVIF_STATE);
|
|
pcpl = pcplPlvi(&lvi);
|
|
|
|
if (Control_GetShowState(pcpl->tszFile) != LV_IsChecked(&lvi)) {
|
|
fChanged = 1;
|
|
Control_SetShowState(pcpl->tszFile, LV_IsChecked(&lvi));
|
|
}
|
|
}
|
|
|
|
if (fChanged) {
|
|
ChangeNotifyCsidl(hdlg, CSIDL_CONTROLS, SHCNE_UPDATEDIR);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Oh yeah, we need this too.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#pragma BEGIN_CONST_DATA
|
|
|
|
LVV lvvControl = {
|
|
0, /* Control_OnCommand */
|
|
0, /* Control_LV_OnInitContextMenu */
|
|
Control_LV_Dirtify,
|
|
0, /* Control_LV_GetIcon */
|
|
Control_OnInitDialog,
|
|
Control_OnApply,
|
|
Control_OnDestroy,
|
|
0, /* Control_OnSelChange */
|
|
7, /* iMenu */
|
|
rgdwHelp,
|
|
0, /* Double-click action */
|
|
lvvflCanCheck, /* We need check boxes */
|
|
NULL,
|
|
};
|
|
|
|
#pragma END_CONST_DATA
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Our window procedure.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
INT_PTR EXPORT
|
|
Control_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return LV_DlgProc(&lvvControl, hdlg, wm, wParam, lParam);
|
|
}
|