|
|
#include "shellprv.h"
#pragma hdrstop
#include "control.h"
#include "uemapp.h"
#include <limits.h>
#define TF_CPL TF_CUSTOM2
typedef struct { ATOM aCPL; // CPL name atom (so we can match requests)
ATOM aApplet; // applet name atom (so we can match requests, may be zero)
HWND hwndStub; // window for this dude (so we can switch to it)
UINT flags; // see PCPLIF_ flags below
} CPLAPPLETID;
//
// PCPLIF_DEFAULT_APPLET
// There are two ways of getting the default applet, asking for it my name
// and passing an empty applet name. This flag should be set regardless,
// so that the code which switches to an already-active applet can always
// find a previous instance if it exists.
//
#define PCPLIF_DEFAULT_APPLET (0x1)
typedef struct { int icon; TCHAR cpl[ CCHPATHMAX ]; TCHAR applet[ MAX_CCH_CPLNAME ]; TCHAR *params; } CPLEXECINFO;
ATOM aCPLName = (ATOM)0; ATOM aCPLFlags = (ATOM)0;
void CPL_ParseCommandLine (CPLEXECINFO *info, LPTSTR pszCmdLine, BOOL extract_icon); BOOL CPL_LoadAndFindApplet (LPCPLMODULE *pcplm, HICON *phIcon, UINT *puControl, CPLEXECINFO *info);
BOOL CPL_FindCPLInfo(LPTSTR pszCmdLine, HICON *phIcon, UINT *ppapl, LPTSTR *pparm) { LPCPLMODULE pmod; CPLEXECINFO info;
CPL_ParseCommandLine(&info, pszCmdLine, TRUE);
if (CPL_LoadAndFindApplet(&pmod, phIcon, ppapl, &info)) { *pparm = info.params; CPL_FreeCPLModule(pmod); return TRUE; }
*pparm = NULL; return FALSE; }
typedef struct _fcc { LPTSTR lpszClassStub; CPLAPPLETID *target; HWND hwndMatch; } FCC, *LPFCC;
BOOL _FindCPLCallback(HWND hwnd, LPARAM lParam) { LPFCC lpfcc = (LPFCC)lParam; TCHAR szClass[32];
GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
if (lstrcmp(szClass, lpfcc->lpszClassStub) == 0) // Must be same class...
{ // Found a stub window
if (lpfcc->target->aCPL != 0) { HANDLE hHandle;
ATOM aCPL; hHandle = GetProp(hwnd, (LPCTSTR)(DWORD_PTR)aCPLName);
ASSERT((DWORD_PTR) hHandle < USHRT_MAX); aCPL = (ATOM)(DWORD_PTR) hHandle;
if (aCPL != 0 && aCPL == lpfcc->target->aCPL) { ATOM aApplet; hHandle = GetProp(hwnd, (LPCTSTR)(DWORD_PTR)aCPL); aApplet = (ATOM)(DWORD_PTR) hHandle; ASSERT((DWORD_PTR) hHandle < USHRT_MAX);
// users may request any applet by name
if (aApplet != 0 && aApplet == lpfcc->target->aApplet) { lpfcc->hwndMatch = hwnd; return FALSE; } //
// Users may request the default w/o specifying a name
//
if (lpfcc->target->flags & PCPLIF_DEFAULT_APPLET) { UINT flags = HandleToUlong(GetProp(hwnd, MAKEINTATOM(aCPLFlags)));
if (flags & PCPLIF_DEFAULT_APPLET) { lpfcc->hwndMatch = hwnd; return FALSE; } } } } } return TRUE; }
HWND FindCPL(HWND hwndStub, CPLAPPLETID *target) { FCC fcc; TCHAR szClassStub[32];
if (aCPLName == (ATOM)0) { aCPLName = GlobalAddAtom(TEXT("CPLName")); aCPLFlags = GlobalAddAtom(TEXT("CPLFlags"));
if (aCPLName == (ATOM)0 || aCPLFlags == (ATOM)0) return NULL; // This should never happen... didn't find hwnd
}
szClassStub[0] = '\0'; // a NULL hwnd has no class
if (hwndStub) { GetClassName(hwndStub, szClassStub, ARRAYSIZE(szClassStub)); } fcc.lpszClassStub = szClassStub; fcc.target = target; fcc.hwndMatch = (HWND)0;
EnumWindows(_FindCPLCallback, (LPARAM)&fcc);
return fcc.hwndMatch; }
//----------------------------------------------------------------------------
// parsing helper for comma lists
//
TCHAR *CPL_ParseToSeparator(TCHAR *dst, TCHAR *psrc, size_t dstmax, BOOL spacedelimits) { if (psrc) { TCHAR source[CCHPATHMAX], *src; TCHAR *delimiter, *closingquote = NULL;
StringCchCopy(source, ((dstmax < ARRAYSIZE(source)) ? dstmax : ARRAYSIZE(source)), psrc); src = source;
//
// eat whitespace
//
while(*src == TEXT(' ')) src++;
delimiter = src;
//
// ignore stuff inside quoted strings
//
if (*src == TEXT('"')) { //
// start after first quote, advance src past quote
//
closingquote = ++src;
while(*closingquote && *closingquote != TEXT('"')) closingquote++;
//
// see if loop above ended on a quote
//
if (*closingquote) { //
// temporary NULL termination
//
*closingquote = 0;
//
// start looking for delimiter again after quotes
//
delimiter = closingquote + 1; } else closingquote = NULL; }
if (spacedelimits) { delimiter += StrCSpn(delimiter, TEXT(", "));
if (!*delimiter) delimiter = NULL; } else delimiter = StrChr(delimiter, TEXT(','));
//
// temporary NULL termination
//
if (delimiter) *delimiter = 0;
if (dst) { StringCchCopy(dst, dstmax, src); dst[ dstmax - 1 ] = 0; }
//
// put back stuff we terminated above
//
if (delimiter) *delimiter = TEXT(',');
if (closingquote) *closingquote = TEXT('"');
//
// return start of next string
//
psrc = (delimiter ? (psrc + ((delimiter + 1) - source)) : NULL); } else if (dst) { *dst = 0; }
//
// new source location
//
return psrc; }
// parse the Control_RunDLL command line
// format: "CPL name, applet name, extra params"
// format: "CPL name, icon index, applet name, extra params"
//
// NOTE: [stevecat] 3/10/95
//
// The 'extra params' do not have to be delimited by a ","
// in NT for the case "CPL name applet name extra params"
//
// A workaround for applet names that include a space
// in their name would be to enclose that value in
// double quotes (see the CPL_ParseToSeparator routine.)
//
void CPL_ParseCommandLine(CPLEXECINFO *info, LPTSTR pszCmdLine, BOOL extract_icon) { //
// parse out the CPL name, spaces are valid separators
//
pszCmdLine = CPL_ParseToSeparator(info->cpl, pszCmdLine, CCHPATHMAX, TRUE);
if (extract_icon) { TCHAR icon[ 8 ];
//
// parse out the icon id/index, spaces are not valid separators
//
pszCmdLine = CPL_ParseToSeparator(icon, pszCmdLine, ARRAYSIZE(icon), FALSE);
info->icon = StrToInt(icon); } else info->icon = 0;
//
// parse out the applet name, spaces are not valid separators
//
info->params = CPL_ParseToSeparator(info->applet, pszCmdLine, MAX_CCH_CPLNAME, FALSE);
CPL_StripAmpersand(info->applet); }
BOOL CPL_LoadAndFindApplet(LPCPLMODULE *ppcplm, HICON *phIcon, UINT *puControl, CPLEXECINFO *info) { TCHAR szControl[MAX_CCH_CPLNAME]; LPCPLMODULE pcplm; LPCPLITEM pcpli; int nControl = 0; // fall thru to default
int NumControls;
ENTERCRITICAL;
pcplm = CPL_LoadCPLModule(info->cpl);
if (!pcplm || !pcplm->hacpli) { DebugMsg(DM_ERROR, TEXT("Control_RunDLL: ") TEXT("CPL_LoadCPLModule failed \"%s\""), info->cpl); LEAVECRITICAL; goto Error0; }
//
// Look for the specified applet
// no applet specified selects applet 0
//
if (*info->applet) { NumControls = DSA_GetItemCount(pcplm->hacpli);
if (info->applet[0] == TEXT('@')) { nControl = StrToLong(info->applet+1);
if (nControl >= 0 && nControl < NumControls) { goto GotControl; } }
//
// Check for the "Setup" argument and send the special CPL_SETUP
// message to the applet to tell it we are running under Setup.
//
if (!lstrcmpi (TEXT("Setup"), info->params)) CPL_CallEntry(pcplm, NULL, CPL_SETUP, 0L, 0L);
for (nControl=0; nControl < NumControls; nControl++) { pcpli = DSA_GetItemPtr(pcplm->hacpli, nControl); StringCchCopy(szControl, ARRAYSIZE(szControl), pcpli->pszName); CPL_StripAmpersand(szControl);
// if there is only one control, then use it. This solves
// some compat issues with CP names changing.
if (lstrcmpi(info->applet, szControl) == 0 || 1 == NumControls) break; }
//
// If we get to the end of the list, bail out
//
// LEGACY WARNING: It might be necessary to handle some old applet names in a special
// way. This would be bad because the names are localized. We would need to somehow
// call into the CPL's to ask them if they support the given name. Only the CPL
// itself would know the correct legacy name mapping. Adding a new CPL message might
// cause as many legacy CPL problems as it solves so we would need to do something tricky
// like adding an exported function. We could then GetProcAddress on this exported function.
// If the export exists, we would pass it the legacy name and it would return a number.
//
// Example: "control mmsys.cpl,Sounds" must work even though mmsys.cpl no longer contains
// an applet called "Sounds". "control mmsys.cpl,Multimedia" must work even though
// mmsys.cpl no longer contains an applet called "Multimedia". You can't simply
// rename the applet becuase these two CPL's were both merged into one CPL. Renaming
// could never solve more than half the problem.
if (nControl >= NumControls) { DebugMsg(DM_ERROR, TEXT("Control_RunDLL: ") TEXT("Cannot find specified applet")); LEAVECRITICAL; goto Error1; } }
GotControl: if (phIcon != NULL) { pcpli = DSA_GetItemPtr(pcplm->hacpli, nControl); *phIcon = CopyIcon(pcpli->hIcon); }
LEAVECRITICAL; //
// yes, we really do want to pass negative indices through...
//
*puControl = (UINT)nControl; *ppcplm = pcplm;
return TRUE;
Error1: CPL_FreeCPLModule(pcplm); Error0: return FALSE; }
BOOL CPL_Identify(CPLAPPLETID *identity, CPLEXECINFO *info, HWND stub) { identity->aApplet = (ATOM)0; identity->hwndStub = stub; identity->flags = 0;
if ((identity->aCPL = GlobalAddAtom(info->cpl)) == (ATOM)0) return FALSE;
if (*info->applet) { if ((identity->aApplet = GlobalAddAtom(info->applet)) == (ATOM)0) return FALSE; } else { //
// no applet name means use the default
//
identity->flags = PCPLIF_DEFAULT_APPLET; }
return TRUE; }
void CPL_UnIdentify(CPLAPPLETID *identity) { if (identity->aCPL) { GlobalDeleteAtom(identity->aCPL); identity->aCPL = (ATOM)0; }
if (identity->aApplet) { GlobalDeleteAtom(identity->aApplet); identity->aApplet = (ATOM)0; }
identity->hwndStub = NULL; identity->flags = 0; }
// It's time for Legacy Mode!!! In NT5 we removed a bunch of CPL files
// from the product. These files are used by name by many programs. As a result,
// the old names need to keep working even though the files no longer exist.
// We handle this by checking if the file exists. If it does not exist, we run
// the cpl name through a mapping table and then try again. The mapping table can
// potentially change the CPL name, the applet number, and the params.
typedef struct { LPTSTR oldInfo_cpl; LPTSTR oldInfo_applet; LPTSTR oldInfo_params; LPTSTR newInfo_cpl; LPTSTR newInfo_applet; LPTSTR newInfo_params; } RUNDLLCPLMAPPING;
// For the oldInfo member, a NULL means to match any value from the pinfo structure.
// If the oldInfo structure mathces the pinfo structure then it will be updated using
// the data from newInfo structure. For the newInfo member, a NULL means to leave the
// corresponding pinfo member unchanged.
const RUNDLLCPLMAPPING g_rgRunDllCPLMapping[] = { { TEXT("MODEM.CPL"), NULL, NULL, TEXT("TELEPHON.CPL"), TEXT("@0"), TEXT("1") }, { TEXT("UPS.CPL"), NULL, NULL, TEXT("POWERCFG.CPL"), NULL, NULL } };
BOOL CPL_CheckLegacyMappings(CPLEXECINFO * pinfo) { LPTSTR p; int i;
TraceMsg(TF_CPL, "Attempting Legacy CPL conversion on %s", pinfo->cpl);
// we want only the filename, strip off any path information
p = PathFindFileName(pinfo->cpl); StringCchCopy(pinfo->cpl, ARRAYSIZE(pinfo->cpl), p);
for (i = 0; i < ARRAYSIZE(g_rgRunDllCPLMapping); i++) { if (0 == StrCmpI(pinfo->cpl, g_rgRunDllCPLMapping[i].oldInfo_cpl)) { if (!g_rgRunDllCPLMapping[i].oldInfo_applet || 0 == StrCmpI(pinfo->applet, g_rgRunDllCPLMapping[i].oldInfo_applet)) { if (!g_rgRunDllCPLMapping[i].oldInfo_params || (pinfo->params && 0 == StrCmpI(pinfo->params, g_rgRunDllCPLMapping[i].oldInfo_params) ) ) { if (pinfo->params) { TraceMsg(TF_CPL, "%s,%s,%s matches item %d", pinfo->cpl, pinfo->applet, pinfo->params, i); } else { TraceMsg(TF_CPL, "%s,%s matches item %d", pinfo->cpl, pinfo->applet, i); }
// The current entry matches the request. Map to the new info and then
// ensure the new CPL exists.
StringCchCopy(pinfo->cpl, ARRAYSIZE(pinfo->cpl), g_rgRunDllCPLMapping[i].newInfo_cpl);
if (g_rgRunDllCPLMapping[i].newInfo_applet) { StringCchCopy(pinfo->applet, ARRAYSIZE(pinfo->applet), g_rgRunDllCPLMapping[i].newInfo_applet); }
if (g_rgRunDllCPLMapping[i].newInfo_params) { // the params pointer is normally a pointer into the remaining chunk of a string
// buffer. As such, we don't need to delete the memory it points to. Also, this
// argument is read only so it should be safe for us to point it at our constant
// data.
pinfo->params = g_rgRunDllCPLMapping[i].newInfo_params; }
if (pinfo->params) { TraceMsg(TF_CPL, "CPL mapped to %s,%s,%s", pinfo->cpl, pinfo->applet, pinfo->params); } else { TraceMsg(TF_CPL, "CPL mapped to %s,%s", pinfo->cpl, pinfo->applet); }
return PathFindOnPath(pinfo->cpl, NULL); } } } }
return FALSE; }
// Goes through all of the work of identifying and starting a control
// applet. Accepts a flag specifying whether or not to load a new DLL if it
// is not already present. This code will ALLWAYS switch to an existing
// instance of the applet if bFindExisting is specified.
//
// WARNING: this function butchers the command line you pass in!
BOOL CPL_RunMeBaby(HWND hwndStub, HINSTANCE hAppInstance, LPTSTR pszCmdLine, int nCmdShow, BOOL bAllowLoad, BOOL bFindExisting) { int nApplet; LPCPLMODULE pcplm; LPCPLITEM pcpli; CPLEXECINFO info; CPLAPPLETID identity; TCHAR szApplet[ MAX_CCH_CPLNAME ]; BOOL bResult = FALSE; HWND hwndOtherStub; HRESULT hrInit;
if (SHRestricted(REST_NOCONTROLPANEL)) { ShellMessageBox(HINST_THISDLL, hwndStub, MAKEINTRESOURCE(IDS_RESTRICTIONS), MAKEINTRESOURCE(IDS_RESTRICTIONSTITLE), MB_OK|MB_ICONSTOP); return FALSE; }
hrInit = SHCoInitialize();
//
// parse the command line we got
//
CPL_ParseCommandLine(&info, pszCmdLine, FALSE);
//
// no applet to run means open the controls folder
//
if (!*info.cpl) { InvokeFolderPidl(MAKEINTIDLIST(CSIDL_CONTROLS), nCmdShow); bResult = TRUE; goto Error0; }
// expand CPL name to a full path if it isn't already
if (PathIsFileSpec(info.cpl)) { if (!PathFindOnPath(info.cpl, NULL)) { if (!CPL_CheckLegacyMappings(&info)) goto Error0; } } else if (!PathFileExists(info.cpl)) { if (!CPL_CheckLegacyMappings(&info)) goto Error0; }
if (!CPL_Identify(&identity, &info, hwndStub)) goto Error0;
//
// If we have already loaded this CPL, then jump to the existing window
//
hwndOtherStub = FindCPL(hwndStub, &identity);
//
// If we found a window and the caller says its ok to find an existing
// window then set the focus to it
//
if (bFindExisting && hwndOtherStub) { //
// try to find a CPL window on top of it
//
HWND hwndTarget = GetLastActivePopup(hwndOtherStub);
if (hwndTarget && IsWindow(hwndTarget)) {
DebugMsg(DM_WARNING, TEXT("Control_RunDLL: ") TEXT("Switching to already loaded CPL applet")); SetForegroundWindow(hwndTarget); bResult = TRUE; goto Error1; }
//
// couldn't find it, must be exiting or some sort of error...
// so ignore it.
//
DebugMsg(DM_WARNING, TEXT("Control_RunDLL: ") TEXT("Bogus CPL identity in array; purging after (presumed) RunDLL crash")); }
//
// stop here if we're not allowed to load the cpl
//
if (!bAllowLoad) goto Error1;
//
// i guess we didn't stop up there
//
if (!CPL_LoadAndFindApplet(&pcplm, NULL, &nApplet, &info)) goto Error1;
//
// get the name that the applet thinks it should have
//
pcpli = DSA_GetItemPtr(pcplm->hacpli, nApplet);
if (FAILED(StringCchCopy(szApplet, ARRAYSIZE(szApplet), pcpli->pszName))) goto Error2;
CPL_StripAmpersand(szApplet);
// handle "default applet" cases before running anything
if (identity.aApplet) { // we were started with an explicitly named applet
if (!nApplet) { // we were started with the name of the default applet
identity.flags |= PCPLIF_DEFAULT_APPLET; } } else { // we were started without a name, assume the default applet
identity.flags |= PCPLIF_DEFAULT_APPLET;
// get the applet's name (now that we've loaded it's CPL)
if ((identity.aApplet = GlobalAddAtom(szApplet)) == (ATOM)0) { // bail 'cause we could nuke a CPL if we don't have this
goto Error2; } }
// mark the window so we'll be able to verify that it's really ours
if (aCPLName == (ATOM)0) { aCPLName = GlobalAddAtom(TEXT("CPLName")); aCPLFlags = GlobalAddAtom(TEXT("CPLFlags"));
if (aCPLName == (ATOM)0 || aCPLFlags == (ATOM)0) goto Error2; // This should never happen... blow off applet
}
if (!SetProp(hwndStub, // Mark its name
MAKEINTATOM(aCPLName), (HANDLE)(DWORD_PTR)identity.aCPL)) { goto Error2; }
if (!SetProp(hwndStub, // Mark its applet
MAKEINTATOM(identity.aCPL), (HANDLE)(DWORD_PTR)identity.aApplet)) { goto Error2; } if (identity.flags) { if (aCPLFlags == (ATOM)0) aCPLFlags = GlobalAddAtom(TEXT("CPLFlags")); // Mark its flags
SetProp(hwndStub, MAKEINTATOM(aCPLFlags), (HANDLE)UIntToPtr(identity.flags)); }
//
// Send the stub window a message so it will have the correct title and
// icon in the alt-tab window, etc...
//
if (hwndStub) { DWORD dwPID; SendMessage(hwndStub, STUBM_SETICONTITLE, (WPARAM)pcpli->hIcon, (LPARAM)szApplet); GetWindowThreadProcessId(hwndStub, &dwPID); if (dwPID == GetCurrentProcessId()) { RUNDLL_NOTIFY sNotify;
sNotify.hIcon = pcpli->hIcon; sNotify.lpszTitle = szApplet;
// HACK: It will look like the stub window is sending itself
// a WM_NOTIFY message. Oh well.
//
SendNotify(hwndStub, hwndStub, RDN_TASKINFO, (NMHDR FAR*)&sNotify); } }
if (info.params) { DebugMsg(DM_TRACE, TEXT("Control_RunDLL: ") TEXT("Sending CPL_STARTWPARAMS to applet with: %s"), info.params);
bResult = BOOLFROMPTR(CPL_CallEntry(pcplm, hwndStub, CPL_STARTWPARMS, (LONG)nApplet, (LPARAM)info.params)); }
// Check whether we need to run as a different windows version
{ PPEB Peb = NtCurrentPeb(); PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pcplm->minst.hinst; PIMAGE_NT_HEADERS pHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)pcplm->minst.hinst + pDosHeader->e_lfanew);
if (pHeader->FileHeader.SizeOfOptionalHeader != 0 && pHeader->OptionalHeader.Win32VersionValue != 0) { //
// Stolen from ntos\mm\procsup.c
//
Peb->OSMajorVersion = pHeader->OptionalHeader.Win32VersionValue & 0xFF; Peb->OSMinorVersion = (pHeader->OptionalHeader.Win32VersionValue >> 8) & 0xFF; Peb->OSBuildNumber = (USHORT) ((pHeader->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF); Peb->OSPlatformId = (pHeader->OptionalHeader.Win32VersionValue >> 30) ^ 0x2; } }
#ifdef UNICODE
//
// If the cpl didn't respond to CPL_STARTWPARMSW (unicode version),
// maybe it is an ANSI only CPL
//
if (info.params && (!bResult)) { int cchParams = WideCharToMultiByte(CP_ACP, 0, info.params, -1, NULL, 0, NULL, NULL); LPSTR lpstrParams = LocalAlloc(LMEM_FIXED, sizeof(*lpstrParams) * cchParams); if (lpstrParams != NULL) { WideCharToMultiByte(CP_ACP, 0, info.params, -1, lpstrParams, cchParams, NULL, NULL);
DebugMsg(DM_TRACE, TEXT("Control_RunDLL: ") TEXT("Sending CPL_STARTWPARAMSA to applet with: %hs"), lpstrParams);
bResult = BOOLFROMPTR(CPL_CallEntry(pcplm, hwndStub, CPL_STARTWPARMSA, (LONG)nApplet, (LPARAM)lpstrParams));
LocalFree(lpstrParams); } } #endif
if (!bResult) { DebugMsg(DM_TRACE, TEXT("Control_RunDLL: ") TEXT("Sending CPL_DBLCLK to applet"));
CPL_CallEntry(pcplm, hwndStub, CPL_DBLCLK, (LONG)nApplet, pcpli->lData);
// some 3x applets return the wrong value so we can't fail here
bResult = TRUE; }
bResult = TRUE; // make it!
RemoveProp(hwndStub, (LPCTSTR)(UINT_PTR)identity.aCPL); Error2: CPL_FreeCPLModule(pcplm); Error1: CPL_UnIdentify(&identity); Error0:
SHCoUninitialize(hrInit);
return bResult; }
//
// Check the following reg location and see if this CPL is registered to run in proc:
// HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\InProcCPLs
//
STDAPI_(BOOL) CPL_IsInProc(LPCTSTR pszCmdLine) { BOOL bInProcCPL = FALSE; TCHAR szTempCmdLine[2 * MAX_PATH]; CPLEXECINFO info = {0}; LPTSTR pszCPLFile = NULL; ASSERT(pszCmdLine);
// Make a copy of the command line
StringCchCopy(szTempCmdLine, ARRAYSIZE(szTempCmdLine), pszCmdLine);
// Parse the command line using standard parsing function
CPL_ParseCommandLine(&info, szTempCmdLine, FALSE);
// Find the file name of this cpl
pszCPLFile = PathFindFileName(info.cpl); if (pszCPLFile) { // Open the reg key
HKEY hkeyInProcCPL = NULL; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\InProcCPLs"), 0, KEY_READ, &hkeyInProcCPL)) { // Look up in the registry for this cpl name
LONG cbData; if (ERROR_SUCCESS == SHQueryValueEx(hkeyInProcCPL, pszCPLFile, NULL, NULL, NULL, &cbData)) bInProcCPL = TRUE;
RegCloseKey(hkeyInProcCPL); } } return bInProcCPL; }
BOOL UsePCHealthFaultUploading(LPCTSTR pszCmdLine) { // Do we want exceptions to go unhandled so PCHealth will upload the faults?
BOOL fUsePCHealth = FALSE; // By default no, because
LPCTSTR pszFilename = PathFindFileName(pszCmdLine);
if (pszFilename) { DWORD dwType; DWORD dwFlags; DWORD cbSize = sizeof(dwFlags);
DWORD dwError = SHGetValue(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\Flags"), pszFilename, &dwType, (void *)&dwFlags, &cbSize); if ((ERROR_SUCCESS == dwError) && (REG_DWORD == dwType)) { // The 0x00000001 bit will indicate if they want to not have exceptions caught for them.
if (0x00000001 & dwFlags) { fUsePCHealth = TRUE; } } }
return fUsePCHealth; }
//
// Starts a remote control applet on a new RunDLL process
// Or on another thread InProcess
//
STDAPI_(BOOL) CPL_RunRemote(LPCTSTR pszCmdLine, HWND hwnd, BOOL fRunAsNewUser) { BOOL bRet = FALSE; TCHAR szShell32[MAX_PATH]; //
// First build a path to shell32.dll in SYSTEM32.
//
if (0 != GetSystemDirectory(szShell32, ARRAYSIZE(szShell32))) { if (PathAppend(szShell32, TEXT("shell32.dll"))) { TCHAR szRunParams[2 * MAX_PATH]; BOOL fUsePCHealth = UsePCHealthFaultUploading(pszCmdLine); HRESULT hr;
hr = StringCchPrintf(szRunParams, ARRAYSIZE(szRunParams), TEXT("%s%s,Control_RunDLL%s %s"), (fUsePCHealth ? TEXT("/d ") : TEXT("")), szShell32, (fRunAsNewUser ? TEXT("AsUser") : TEXT("")), pszCmdLine);
if (SUCCEEDED(hr)) { if (!fRunAsNewUser && CPL_IsInProc(pszCmdLine)) { // launch this cpl in process from another thread
bRet = SHRunDLLThread(hwnd, szRunParams, SW_SHOWNORMAL); } else { // launch this cpl on another thread
bRet = SHRunDLLProcess(hwnd, szRunParams, SW_SHOWNORMAL, IDS_CONTROLPANEL, fRunAsNewUser); } } } } return bRet; }
//
// Attempts to open the specified control applet.
// Tries to switch to an existing instance before starting a new one, unless the user
// specifies the fRunAsNewUser in which case we always launch a new process.
//
STDAPI_(BOOL) SHRunControlPanelEx(LPCTSTR pszOrigCmdLine, HWND hwnd, BOOL fRunAsNewUser) { BOOL bRes = FALSE; LPTSTR pszCmdLine = NULL;
// check to see if the caller passed a resource id instead of a string
if (!IS_INTRESOURCE(pszOrigCmdLine)) { pszCmdLine = StrDup(pszOrigCmdLine); } else { TCHAR szCmdLine[MAX_PATH];
if (LoadString(HINST_THISDLL, PtrToUlong((void *)pszOrigCmdLine), szCmdLine, ARRAYSIZE(szCmdLine))) pszCmdLine = StrDup(szCmdLine); }
//
// CPL_RunMeBaby whacks on the command line while parsing...use a dup
//
if (pszCmdLine) {
if (!fRunAsNewUser) { // if fRunAsNewUser is NOT specified, then try to switch to an active CPL
// which matches our pszCmdLine
bRes = CPL_RunMeBaby(NULL, NULL, pszCmdLine, SW_SHOWNORMAL, FALSE, TRUE); }
if (!bRes) { // launch a new cpl in a separate process
bRes = CPL_RunRemote(pszCmdLine, hwnd, fRunAsNewUser); } LocalFree(pszCmdLine); }
if (bRes && UEMIsLoaded() && !IS_INTRESOURCE(pszOrigCmdLine)) { UEMFireEvent(&UEMIID_SHELL, UEME_RUNCPL, UEMF_XEVENT, -1, (LPARAM)pszOrigCmdLine); }
return bRes; }
// This function is a TCHAR export from shell32 (header defn is in shsemip.h)
//
// UNDOCUMENTED: You may pass a shell32 resource ID in place of a pszCmdLine
//
STDAPI_(BOOL) SHRunControlPanel(LPCTSTR pszOrigCmdLine, HWND hwnd) { return SHRunControlPanelEx(pszOrigCmdLine, hwnd, FALSE); }
//
// Attempts to open the specified control applet.
// This function is intended to be called by RunDLL for isolating applets.
// Tries to switch to an existing instance before starting a new one.
//
// The command lines for Control_RunDLL are as follows:
//
// 1) rundll32 shell32.dll,Control_RunDLL fred.cpl,@n,arguments
//
// This launches the (n+1)th applet in fred.cpl.
//
// If "@n" is not supplied, the default is @0.
//
// 2) rundll32 shell32.dll,Control_RunDLL fred.cpl,Ba&rney,arguments
//
// This launches the applet in fred.cpl named "Barney". Ampersands are
// stripped from the name.
//
// 3) rundll32 shell32.dll,Control_RunDLL fred.cpl,Setup
//
// This loads fred.cpl and sends it a CPL_SETUP message.
//
// In cases (1) and (2), the "arguments" are passed to the applet via
// the CPL_STARTWPARAMS (start with parameters) message. It is the
// applet's job to parse the arguments and do something interesting.
//
// It is traditional for the command line of a cpl to be the index of
// the page that should initially be shown to the user, but that's just
// tradition.
//
STDAPI_(void) Control_RunDLL(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow) { TCHAR szCmdLine[MAX_PATH * 2]; SHAnsiToTChar(pszCmdLine, szCmdLine, ARRAYSIZE(szCmdLine));
CPL_RunMeBaby(hwndStub, hAppInstance, szCmdLine, nCmdShow, TRUE, TRUE); }
STDAPI_(void) Control_RunDLLW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow) { TCHAR szCmdLine[MAX_PATH * 2]; SHUnicodeToTChar(lpwszCmdLine, szCmdLine, ARRAYSIZE(szCmdLine));
CPL_RunMeBaby(hwndStub, hAppInstance, szCmdLine, nCmdShow, TRUE, TRUE); }
// This is the entry that gets called when we run a cpl as a new user.
//
STDAPI_(void) Control_RunDLLAsUserW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow) { CPL_RunMeBaby(hwndStub, hAppInstance, lpwszCmdLine, nCmdShow, TRUE, FALSE); }
// data passed around dialog and worker thread for Control_FillCache_RunDLL
typedef struct { IShellFolder * psfControl; IEnumIDList * penumControl; HWND dialog; } FillCacheData;
//
// important work of Control_FillCache_RunDLL
// jogs the control panel enumerator so it will fill the presentation cache
// also forces the applet icons to be extracted into the shell icon cache
//
DWORD CALLBACK Control_FillCacheThreadProc(void *pv) { FillCacheData *data = (FillCacheData *)pv; LPITEMIDLIST pidlApplet; ULONG dummy;
while(data->penumControl->lpVtbl->Next(data->penumControl, 1, &pidlApplet, &dummy) == NOERROR) { SHMapPIDLToSystemImageListIndex(data->psfControl, pidlApplet, NULL); ILFree(pidlApplet); }
if (data->dialog) EndDialog(data->dialog, 0);
return 0; }
//
// dlgproc for Control_FillCache_RunDLL UI
// just something to keep the user entertained while we load a billion DLLs
//
BOOL_PTR CALLBACK _Control_FillCacheDlg(HWND dialog, UINT message, WPARAM wparam, LPARAM lparam) { switch(message) { case WM_INITDIALOG: { DWORD dummy; HANDLE thread; ((FillCacheData *)lparam)->dialog = dialog; thread = CreateThread(NULL, 0, Control_FillCacheThreadProc, (void*)lparam, 0, &dummy); if (thread) CloseHandle(thread); else EndDialog(dialog, -1); } break; case WM_COMMAND: break; default: return FALSE; } return TRUE; }
//
// enumerates control applets in a manner that fills the presentation cache
// this is so the first time a user opens the control panel it comes up fast
// intended to be called at final setup on first boot
//
// FUNCTION WORKS FOR BOTH ANSI/UNICODE, it never uses pszCmdLine
//
STDAPI_(void) Control_FillCache_RunDLL(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow) { IShellFolder *psfDesktop; HKEY hk; // nuke the old data so that any bogus cached info from a beta goes away
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER, 0, KEY_WRITE, &hk) == ERROR_SUCCESS) { RegDeleteValue(hk, TEXT("Presentation Cache")); RegCloseKey(hk); } SHGetDesktopFolder(&psfDesktop); Shell_GetImageLists(NULL, NULL); // make sure icon cache is around
if (psfDesktop) { LPITEMIDLIST pidlControl = SHCloneSpecialIDList(hwndStub, CSIDL_CONTROLS, FALSE); if (pidlControl) { FillCacheData data = {0}; if (SUCCEEDED(psfDesktop->lpVtbl->BindToObject(psfDesktop, pidlControl, NULL, &IID_IShellFolder, &data.psfControl))) { if (S_OK == data.psfControl->lpVtbl->EnumObjects( data.psfControl, NULL, SHCONTF_NONFOLDERS, &data.penumControl)) { if (nCmdShow == SW_HIDE || DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_CPL_FILLCACHE), hwndStub, _Control_FillCacheDlg, (LPARAM)&data) == -1) { Control_FillCacheThreadProc(&data); } data.penumControl->lpVtbl->Release(data.penumControl); } data.psfControl->lpVtbl->Release(data.psfControl); } ILFree(pidlControl); } } }
STDAPI_(void) Control_FillCache_RunDLLW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow) { Control_FillCache_RunDLL(hwndStub,hAppInstance,NULL,nCmdShow); }
|