/* * 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= * H= * W= * X= * Y= */ 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); }