406 lines
15 KiB
C
406 lines
15 KiB
C
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
#include "control.h"
|
||
|
#include <cpl.h>
|
||
|
#include <cplp.h>
|
||
|
#include <shlwapi.h>
|
||
|
#include <shlwapip.h>
|
||
|
#include "rcids.h"
|
||
|
|
||
|
BOOL ImmDisableIME(DWORD dwThreadId);
|
||
|
|
||
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||
|
// LEAVE THESE IN ENGLISH
|
||
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||
|
const TCHAR c_szCtlPanelClass[] = TEXT("CtlPanelClass");
|
||
|
const TCHAR c_szExplorer[] = TEXT("explorer.exe");
|
||
|
const TCHAR c_szRunDLL32[] = TEXT("rundll32.exe");
|
||
|
const TCHAR c_szRunDLLShell32Etc[] = TEXT("Shell32.dll,Control_RunDLL ");
|
||
|
const TCHAR c_szControlPanelFolder[] =
|
||
|
TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\"");
|
||
|
const TCHAR c_szDoPrinters[] =
|
||
|
TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}\"");
|
||
|
const TCHAR c_szDoFonts[] =
|
||
|
TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{D20EA4E1-3957-11d2-A40B-0C5020524152}\"");
|
||
|
const TCHAR c_szDoAdminTools[] =
|
||
|
TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{D20EA4E1-3957-11d2-A40B-0C5020524153}\"");
|
||
|
const TCHAR c_szDoSchedTasks[] =
|
||
|
TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{D6277990-4C6A-11CF-8D87-00AA0060F5BF}\"");
|
||
|
const TCHAR c_szDoNetConnections[] =
|
||
|
TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}\"");
|
||
|
const TCHAR c_szDoNetplwizUsers[] =
|
||
|
TEXT("netplwiz.dll,UsersRunDll");
|
||
|
const TCHAR c_szDoFolderOptions[] =
|
||
|
TEXT("shell32.dll,Options_RunDLL 0");
|
||
|
const TCHAR c_szDoScannerCamera[] =
|
||
|
TEXT("\"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{E211B736-43FD-11D1-9EFB-0000F8757FCD}\"");
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
LPCTSTR szOldForm;
|
||
|
DWORD dwOS;
|
||
|
LPCTSTR szFile;
|
||
|
LPCTSTR szParameters;
|
||
|
} COMPATCPL;
|
||
|
|
||
|
#define OS_ANY ((DWORD)-1)
|
||
|
|
||
|
COMPATCPL const c_aCompatCpls[] =
|
||
|
{
|
||
|
{ TEXT("DESKTOP"), OS_ANY, TEXT("desk.cpl"), NULL },
|
||
|
{ TEXT("COLOR"), OS_ANY, TEXT("desk.cpl"), TEXT(",2") },
|
||
|
{ TEXT("DATE/TIME"), OS_ANY, TEXT("timedate.cpl"), NULL },
|
||
|
{ TEXT("PORTS"), OS_ANY, TEXT("sysdm.cpl"), TEXT(",1") },
|
||
|
{ TEXT("INTERNATIONAL"), OS_ANY, TEXT("intl.cpl"), NULL },
|
||
|
{ TEXT("MOUSE"), OS_ANY, TEXT("main.cpl"), NULL },
|
||
|
{ TEXT("KEYBOARD"), OS_ANY, TEXT("main.cpl"), TEXT("@1") },
|
||
|
{ TEXT("NETWARE"), OS_ANY, TEXT("nwc.cpl"), NULL },
|
||
|
{ TEXT("TELEPHONY"), OS_ANY, TEXT("telephon.cpl"), NULL },
|
||
|
{ TEXT("INFRARED"), OS_ANY, TEXT("irprops.cpl"), NULL },
|
||
|
{ TEXT("USERPASSWORDS"), OS_ANYSERVER, TEXT("lusrmgr.msc"), NULL },
|
||
|
{ TEXT("USERPASSWORDS"), OS_WHISTLERORGREATER, TEXT("nusrmgr.cpl"), NULL },
|
||
|
{ TEXT("USERPASSWORDS2"), OS_ANY, c_szRunDLL32, c_szDoNetplwizUsers },
|
||
|
{ TEXT("PRINTERS"), OS_ANY, c_szExplorer, c_szDoPrinters },
|
||
|
{ TEXT("FONTS"), OS_ANY, c_szExplorer, c_szDoFonts },
|
||
|
{ TEXT("ADMINTOOLS"), OS_ANY, c_szExplorer, c_szDoAdminTools },
|
||
|
{ TEXT("SCHEDTASKS"), OS_ANY, c_szExplorer, c_szDoSchedTasks },
|
||
|
{ TEXT("NETCONNECTIONS"), OS_ANY, c_szExplorer, c_szDoNetConnections },
|
||
|
{ TEXT("FOLDERS"), OS_ANY, c_szRunDLL32, c_szDoFolderOptions },
|
||
|
{ TEXT("SCANNERCAMERA"), OS_ANY, c_szExplorer, c_szDoScannerCamera },
|
||
|
{ TEXT("STICPL.CPL"), OS_ANY, c_szExplorer, c_szDoScannerCamera },
|
||
|
};
|
||
|
|
||
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||
|
|
||
|
// Timer
|
||
|
#define TIMER_QUITNOW 1
|
||
|
#define TIMEOUT 10000
|
||
|
|
||
|
#define DM_CPTRACE 0
|
||
|
|
||
|
|
||
|
DWORD GetRegisteredCplPath(LPCTSTR pszNameIn, LPTSTR pszPathOut, UINT cchPathOut)
|
||
|
{
|
||
|
const HKEY rghkeyRoot[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
|
||
|
const TCHAR szSubkey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
|
||
|
|
||
|
DWORD dwResult = ERROR_INSUFFICIENT_BUFFER;
|
||
|
|
||
|
if (0 < cchPathOut)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
*pszPathOut = TEXT('\0');
|
||
|
|
||
|
for (i = 0; i < ARRAYSIZE(rghkeyRoot) && TEXT('\0') == *pszPathOut; i++)
|
||
|
{
|
||
|
HKEY hkey;
|
||
|
dwResult = RegOpenKeyEx(rghkeyRoot[i],
|
||
|
szSubkey,
|
||
|
0,
|
||
|
KEY_QUERY_VALUE,
|
||
|
&hkey);
|
||
|
|
||
|
if (ERROR_SUCCESS == dwResult)
|
||
|
{
|
||
|
TCHAR szName[MAX_PATH]; // Destination for value name.
|
||
|
TCHAR szPath[MAX_PATH * 2]; // Destination for value data.
|
||
|
DWORD dwIndex = 0;
|
||
|
DWORD cbPath;
|
||
|
DWORD cchName;
|
||
|
DWORD dwType;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
cchName = ARRAYSIZE(szName);
|
||
|
cbPath = sizeof(szPath);
|
||
|
|
||
|
dwResult = RegEnumValue(hkey,
|
||
|
dwIndex++,
|
||
|
szName,
|
||
|
&cchName,
|
||
|
NULL,
|
||
|
&dwType,
|
||
|
(LPBYTE)szPath,
|
||
|
&cbPath);
|
||
|
|
||
|
if (ERROR_SUCCESS == dwResult && sizeof(TCHAR) < cbPath)
|
||
|
{
|
||
|
if (REG_SZ == dwType || REG_EXPAND_SZ == dwType)
|
||
|
{
|
||
|
if (0 == lstrcmpi(pszNameIn, szName))
|
||
|
{
|
||
|
//
|
||
|
// We have a match. Expand the path if necessary.
|
||
|
//
|
||
|
TCHAR szExpanded[ARRAYSIZE(szPath)];
|
||
|
DWORD cchExpanded = ExpandEnvironmentStrings(szPath, szExpanded, ARRAYSIZE(szExpanded));
|
||
|
//
|
||
|
// Account for adding enclosing double quotes. Needed
|
||
|
// in case path contains embedded spaces.
|
||
|
//
|
||
|
if (cchExpanded && ((cchExpanded + 2) < cchPathOut))
|
||
|
{
|
||
|
wsprintf(pszPathOut, TEXT("\"%s\""), szExpanded);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Invalid data type. Someone has hacked the registry.
|
||
|
// Continue searching.
|
||
|
//
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
while(ERROR_SUCCESS == dwResult && TEXT('\0') == *pszPathOut);
|
||
|
|
||
|
RegCloseKey(hkey);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
LRESULT CALLBACK DummyControlPanelProc(HWND hwnd, UINT uMsg, WPARAM wparam, LPARAM lparam)
|
||
|
{
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case WM_CREATE:
|
||
|
DebugMsg(DM_CPTRACE, TEXT("cp.dcpp: Created..."));
|
||
|
// We only want to hang around for a little while.
|
||
|
SetTimer(hwnd, TIMER_QUITNOW, TIMEOUT, NULL);
|
||
|
return 0;
|
||
|
case WM_DESTROY:
|
||
|
DebugMsg(DM_CPTRACE, TEXT("cp.dcpp: Destroyed..."));
|
||
|
// Quit the app when this window goes away.
|
||
|
PostQuitMessage(0);
|
||
|
return 0;
|
||
|
case WM_TIMER:
|
||
|
DebugMsg(DM_CPTRACE, TEXT("cp.dcpp: Timer %d"), wparam);
|
||
|
if (wparam == TIMER_QUITNOW)
|
||
|
{
|
||
|
// Get this window to go away.
|
||
|
DestroyWindow(hwnd);
|
||
|
}
|
||
|
return 0;
|
||
|
case WM_COMMAND:
|
||
|
DebugMsg(DM_CPTRACE, TEXT("cp.dcpp: Command %d"), wparam);
|
||
|
// NB Hack for hollywood - they send a menu command to try
|
||
|
// and open the printers applet. They try to search control panels
|
||
|
// menu for the printers item and then post the associated command.
|
||
|
// As our fake window doesn't have a menu they can't find the item
|
||
|
// and post us a -1 instead (ripping on the way).
|
||
|
if (wparam == (WPARAM)-1)
|
||
|
{
|
||
|
SHELLEXECUTEINFO sei = {0};
|
||
|
sei.cbSize = sizeof(SHELLEXECUTEINFO);
|
||
|
sei.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_WAITFORINPUTIDLE;
|
||
|
sei.lpFile = c_szExplorer;
|
||
|
sei.lpParameters = c_szDoPrinters;
|
||
|
sei.nShow = SW_SHOWNORMAL;
|
||
|
ShellExecuteEx(&sei);
|
||
|
}
|
||
|
return 0;
|
||
|
default:
|
||
|
DebugMsg(DM_CPTRACE, TEXT("cp.dcpp: %x %x %x %x"), hwnd, uMsg, wparam, lparam);
|
||
|
return DefWindowProc(hwnd, uMsg, wparam, lparam);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
HWND _CreateDummyControlPanel(HINSTANCE hinst)
|
||
|
{
|
||
|
WNDCLASS wc;
|
||
|
|
||
|
wc.style = 0;
|
||
|
wc.lpfnWndProc = DummyControlPanelProc;
|
||
|
wc.cbClsExtra = 0;
|
||
|
wc.cbWndExtra = 0;
|
||
|
wc.hInstance = hinst;
|
||
|
wc.hIcon = NULL;
|
||
|
wc.hCursor = NULL;
|
||
|
wc.hbrBackground = NULL;
|
||
|
wc.lpszMenuName = NULL;
|
||
|
wc.lpszClassName = c_szCtlPanelClass;
|
||
|
|
||
|
RegisterClass(&wc);
|
||
|
return CreateWindow(c_szCtlPanelClass, NULL, 0, 0, 0, 0, 0, NULL, NULL, hinst, NULL);
|
||
|
}
|
||
|
|
||
|
void ProcessPolicy(void)
|
||
|
{
|
||
|
HINSTANCE hInst;
|
||
|
APPLET_PROC pfnCPLApplet;
|
||
|
|
||
|
hInst = LoadLibrary (TEXT("desk.cpl"));
|
||
|
|
||
|
if (!hInst) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pfnCPLApplet = (APPLET_PROC) GetProcAddress (hInst, "CPlApplet");
|
||
|
|
||
|
if (pfnCPLApplet) {
|
||
|
|
||
|
(*pfnCPLApplet)(NULL, CPL_POLICYREFRESH, 0, 0);
|
||
|
}
|
||
|
|
||
|
FreeLibrary (hInst);
|
||
|
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
int WinMainT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
|
||
|
{
|
||
|
SHELLEXECUTEINFO sei = {0};
|
||
|
TCHAR szParameters[MAX_PATH * 2];
|
||
|
MSG msg;
|
||
|
HWND hwndDummy;
|
||
|
|
||
|
DebugMsg(DM_TRACE, TEXT("cp.wm: Control starting."));
|
||
|
|
||
|
ImmDisableIME(0);
|
||
|
|
||
|
hwndDummy = _CreateDummyControlPanel(hInstance);
|
||
|
|
||
|
// we need to check for PANEL passed in as an arg. The run dialog
|
||
|
// autocomplete shows "Control Panel" as a choice and we used to
|
||
|
// interpret this as Control with panel as an arg. So if we have
|
||
|
// panel as an arg then we do the same processing as when we have
|
||
|
// "Control" only.
|
||
|
if (*lpCmdLine && lstrcmpi(lpCmdLine, TEXT("PANEL")))
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
//
|
||
|
// Policy hook. Userenv.dll will call control.exe with the
|
||
|
// /policy command line switch. If so, we need to load the
|
||
|
// desk.cpl applet and refresh the colors / bitmap.
|
||
|
//
|
||
|
|
||
|
if (lstrcmpi(TEXT("/policy"), lpCmdLine) == 0) {
|
||
|
ProcessPolicy();
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// COMPAT HACK: special case some applets since apps depend on them
|
||
|
//
|
||
|
for (i = 0; !sei.lpFile && i < ARRAYSIZE(c_aCompatCpls); i++)
|
||
|
{
|
||
|
COMPATCPL const * pItem = &c_aCompatCpls[i];
|
||
|
if (lstrcmpi(pItem->szOldForm, lpCmdLine) == 0
|
||
|
&& (pItem->dwOS == OS_ANY || IsOS(pItem->dwOS)))
|
||
|
{
|
||
|
sei.lpFile = pItem->szFile;
|
||
|
sei.lpParameters = pItem->szParameters;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!sei.lpFile)
|
||
|
{
|
||
|
int cch;
|
||
|
|
||
|
//
|
||
|
// Not a special-case CPL.
|
||
|
// See if it's registered under "Control Panel\Cpls".
|
||
|
// If so, we use the registered path.
|
||
|
//
|
||
|
|
||
|
lstrcpy(szParameters, c_szRunDLLShell32Etc);
|
||
|
cch = lstrlen(szParameters);
|
||
|
|
||
|
sei.lpFile = c_szRunDLL32;
|
||
|
sei.lpParameters = szParameters;
|
||
|
|
||
|
if (ERROR_SUCCESS != GetRegisteredCplPath(lpCmdLine,
|
||
|
szParameters + cch,
|
||
|
ARRAYSIZE(szParameters) - cch))
|
||
|
{
|
||
|
//
|
||
|
// Not registered. Pass command line through.
|
||
|
//
|
||
|
lstrcpyn(szParameters + cch, lpCmdLine, ARRAYSIZE(szParameters) - cch);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Open the Control Panel folder
|
||
|
sei.lpFile = c_szExplorer;
|
||
|
sei.lpParameters = c_szControlPanelFolder;
|
||
|
}
|
||
|
|
||
|
// HACK: NerdPerfect tries to open a hidden control panel to talk to
|
||
|
// we are blowing off fixing the communication stuff so just make
|
||
|
// sure the folder does not appear hidden
|
||
|
if (nCmdShow == SW_HIDE)
|
||
|
nCmdShow = SW_SHOWNORMAL;
|
||
|
|
||
|
sei.cbSize = sizeof(sei);
|
||
|
sei.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_WAITFORINPUTIDLE;
|
||
|
sei.nShow = nCmdShow;
|
||
|
|
||
|
ShellExecuteEx(&sei);
|
||
|
|
||
|
if (IsWindow(hwndDummy))
|
||
|
{
|
||
|
while (GetMessage(&msg, NULL, 0, 0))
|
||
|
{
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DebugMsg(DM_TRACE, TEXT("cp.wm: Control exiting."));
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
#ifdef WIN32
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Stolen from the CRT, used to shrink our code.
|
||
|
int _stdcall ModuleEntry(void)
|
||
|
{
|
||
|
STARTUPINFO si;
|
||
|
LPTSTR pszCmdLine = GetCommandLine();
|
||
|
|
||
|
if ( *pszCmdLine == TEXT('\"') ) {
|
||
|
/*
|
||
|
* Scan, and skip over, subsequent characters until
|
||
|
* another double-quote or a null is encountered.
|
||
|
*/
|
||
|
while ( *++pszCmdLine && (*pszCmdLine
|
||
|
!= TEXT('\"')) );
|
||
|
/*
|
||
|
* If we stopped on a double-quote (usual case), skip
|
||
|
* over it.
|
||
|
*/
|
||
|
if ( *pszCmdLine == TEXT('\"') )
|
||
|
pszCmdLine++;
|
||
|
}
|
||
|
else {
|
||
|
while (*pszCmdLine > TEXT(' '))
|
||
|
pszCmdLine++;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Skip past any white space preceeding the second token.
|
||
|
*/
|
||
|
while (*pszCmdLine && (*pszCmdLine <= TEXT(' '))) {
|
||
|
pszCmdLine++;
|
||
|
}
|
||
|
|
||
|
si.dwFlags = 0;
|
||
|
GetStartupInfo(&si);
|
||
|
|
||
|
ExitProcess(WinMainT(GetModuleHandle(NULL), NULL, pszCmdLine,
|
||
|
si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT));
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|