911 lines
29 KiB
C++
911 lines
29 KiB
C++
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1996 - 1997.
|
||
|
//
|
||
|
// File: LoadWC.cpp
|
||
|
//
|
||
|
// Contents: exe to load webcheck
|
||
|
//
|
||
|
// Classes:
|
||
|
//
|
||
|
// Functions:
|
||
|
//
|
||
|
// History: 12-12/96 rayen (Raymond Endres) Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#define _SHELL32_
|
||
|
#include <windows.h>
|
||
|
#include <ccstock.h>
|
||
|
#include <debug.h>
|
||
|
#include <docobj.h>
|
||
|
#include <webcheck.h>
|
||
|
#include <shlguid.h>
|
||
|
#include <shlobj.h>
|
||
|
#include <shellp.h>
|
||
|
|
||
|
// need to do this so we can #include <runonce.c>
|
||
|
BOOL g_fCleanBoot = FALSE;
|
||
|
BOOL g_fEndSession = FALSE;
|
||
|
|
||
|
//
|
||
|
// Channels are enabled for the IE4 upgrades.
|
||
|
//
|
||
|
#define ENABLE_CHANNELS
|
||
|
|
||
|
#define MLUI_INIT
|
||
|
#include <mluisupp.h>
|
||
|
|
||
|
//
|
||
|
// NOTE: ActiveSetup relies on our window name and class name
|
||
|
// to shut us down properly in softboot. Do not change it.
|
||
|
//
|
||
|
const TCHAR c_szClassName[] = TEXT("LoadWC");
|
||
|
const TCHAR c_szWebCheckWindow[] = TEXT("MS_WebcheckMonitor");
|
||
|
const TCHAR c_szWebcheckKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Webcheck");
|
||
|
|
||
|
// message send to dynamically start sens/lce (must not conflict with dialmon)
|
||
|
#define WM_START_SENSLCE (WM_USER+200)
|
||
|
|
||
|
// only used in debug code to grovel with shell service object
|
||
|
#ifdef DEBUG
|
||
|
const TCHAR c_szWebCheck[] = TEXT("WebCheck");
|
||
|
const TCHAR c_szShellReg[] = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ShellServiceObjectDelayLoad");
|
||
|
#endif
|
||
|
|
||
|
typedef struct {
|
||
|
HINSTANCE hInstance; // handle to current instance
|
||
|
HWND hwnd; // main window handle
|
||
|
int nCmdShow; // hidden or not?
|
||
|
HINSTANCE hWebcheck; // handle to webcheck dll
|
||
|
BOOL fUninstallOnly; // TRUE -> run uninstall stubs only, then quit
|
||
|
BOOL fIntShellMode; // TRUE -> integrated shell mode, else browser-only
|
||
|
BOOL fStartSensLce;
|
||
|
} GLOBALS;
|
||
|
|
||
|
GLOBALS g;
|
||
|
|
||
|
// webcheck function we dynaload
|
||
|
typedef HRESULT (WINAPI *PFNSTART)(BOOL fForceExternals);
|
||
|
typedef HRESULT (WINAPI *PFNSTOP)(void);
|
||
|
|
||
|
// Code to run install/uninstall stubs, from shell\inc.
|
||
|
|
||
|
#define HINST_THISDLL g.hInstance
|
||
|
|
||
|
#include "resource.h"
|
||
|
//#include <stubsup.h>
|
||
|
#include <inststub.h>
|
||
|
|
||
|
int WINAPI WinMainT(HINSTANCE, HINSTANCE, LPSTR, int);
|
||
|
LRESULT APIENTRY WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
void vLoadWebCheck(void);
|
||
|
void vUnloadWebCheck(void);
|
||
|
BOOL bParseCommandLine(LPSTR lpCmdLine, int nCmdShow);
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// ModuleEntry
|
||
|
//----------------------------------------------------------------------------
|
||
|
extern "C" int _stdcall ModuleEntry(void)
|
||
|
{
|
||
|
int i;
|
||
|
STARTUPINFOA si;
|
||
|
LPTSTR pszCmdLine;
|
||
|
|
||
|
pszCmdLine = GetCommandLine();
|
||
|
|
||
|
// g_hProcessHeap = GetProcessHeap();
|
||
|
|
||
|
//
|
||
|
// We don't want the "No disk in drive X:" requesters, so we set
|
||
|
// the critical error mask such that calls will just silently fail
|
||
|
//
|
||
|
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||
|
|
||
|
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;
|
||
|
GetStartupInfoA(&si);
|
||
|
|
||
|
i = WinMainT(GetModuleHandle(NULL), NULL, pszCmdLine,
|
||
|
si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
|
||
|
|
||
|
// Since we now have a way for an extension to tell us when it is finished,
|
||
|
// we will terminate all processes when the main thread goes away.
|
||
|
|
||
|
ExitProcess(i);
|
||
|
|
||
|
// DebugMsg(DM_TRACE, TEXT("c.me: Cabinet main thread exiting without ExitProcess."));
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Registry helper function
|
||
|
//----------------------------------------------------------------------------
|
||
|
BOOL ReadRegValue(HKEY hkeyRoot, const TCHAR *pszKey, const TCHAR *pszValue,
|
||
|
void *pData, DWORD dwBytes)
|
||
|
{
|
||
|
long lResult;
|
||
|
HKEY hkey;
|
||
|
DWORD dwType;
|
||
|
|
||
|
lResult = RegOpenKey(hkeyRoot, pszKey, &hkey);
|
||
|
if (lResult != ERROR_SUCCESS) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
lResult = RegQueryValueEx(hkey, pszValue, NULL, &dwType, (BYTE *)pData,
|
||
|
&dwBytes);
|
||
|
RegCloseKey(hkey);
|
||
|
|
||
|
if (lResult != ERROR_SUCCESS)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL WriteRegValue(HKEY hkeyRoot, const TCHAR *pszKey, const TCHAR *pszValue,
|
||
|
DWORD dwType, void *pData, DWORD dwBytes)
|
||
|
{
|
||
|
HKEY hkey;
|
||
|
|
||
|
long lResult = RegOpenKey(hkeyRoot, pszKey, &hkey);
|
||
|
|
||
|
if (ERROR_SUCCESS == lResult)
|
||
|
{
|
||
|
lResult = RegSetValueEx(hkey, pszValue, 0, dwType, (BYTE *)pData, dwBytes);
|
||
|
RegCloseKey(hkey);
|
||
|
}
|
||
|
|
||
|
return ERROR_SUCCESS == lResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
void MakeWindowsRootPath(LPSTR pszBuffer)
|
||
|
{
|
||
|
LPSTR pszEnd = NULL;
|
||
|
if (*pszBuffer == '\\' && *(pszBuffer+1) == '\\') {
|
||
|
pszEnd = pszBuffer + 2;
|
||
|
while (*pszEnd && (*pszEnd != '\\'))
|
||
|
pszEnd++;
|
||
|
if (*pszEnd) {
|
||
|
pszEnd++;
|
||
|
while (*pszEnd && (*pszEnd != '\\'))
|
||
|
pszEnd++;
|
||
|
if (*pszEnd)
|
||
|
pszEnd++;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
LPSTR pszNext = CharNext(pszBuffer);
|
||
|
if (*pszNext == ':' && *(pszNext+1) == '\\')
|
||
|
pszEnd = pszNext + 2;
|
||
|
}
|
||
|
if (pszEnd != NULL)
|
||
|
*pszEnd = '\0';
|
||
|
else {
|
||
|
/* ??? Windows dir is neither UNC nor a root path?
|
||
|
* Just make sure it ends in a backslash.
|
||
|
*/
|
||
|
LPSTR pszLast = pszBuffer;
|
||
|
if (*pszBuffer) {
|
||
|
pszLast = CharPrev(pszBuffer, pszBuffer + lstrlen(pszBuffer));
|
||
|
}
|
||
|
if (*pszLast != '\\')
|
||
|
lstrcat(pszLast, "\\");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// InitShellFolders
|
||
|
//
|
||
|
// More of making loadwc.exe a browser-only mode catch-all. This code makes
|
||
|
// sure that the Shell Folders key in the per-user registry is fully populated
|
||
|
// with the absolute paths to all the special folders for IE, even if
|
||
|
// shell32.dll doesn't understand all of them.
|
||
|
//
|
||
|
// As the shell would do in SHGetSpecialFolderLocation, we check the
|
||
|
// User Shell Folders key for a path, and if that's present we copy it to the
|
||
|
// Shell Folders key, expanding %USERPROFILE% if necessary. If the value is
|
||
|
// not present under User Shell Folders, we generate the default location
|
||
|
// (usually under the Windows directory) and store that location under
|
||
|
// Shell Folders.
|
||
|
//----------------------------------------------------------------------------
|
||
|
struct FolderDescriptor {
|
||
|
UINT idsDirName; /* Resource ID for directory name */
|
||
|
LPCTSTR pszRegValue; /* Name of reg value to set path in */
|
||
|
BOOL fDefaultInRoot : 1; /* TRUE if default location is root directory */
|
||
|
BOOL fWriteToUSF : 1; /* TRUE if we should write to User Shell Folders to work around Win95 bug */
|
||
|
} aFolders[] = {
|
||
|
{ IDS_CSIDL_PERSONAL_L, TEXT("Personal"), TRUE, TRUE } ,
|
||
|
{ IDS_CSIDL_FAVORITES_L, TEXT("Favorites"), FALSE, TRUE },
|
||
|
{ IDS_CSIDL_APPDATA_L, TEXT("AppData"), FALSE, FALSE },
|
||
|
{ IDS_CSIDL_CACHE_L, TEXT("Cache"), FALSE, FALSE },
|
||
|
{ IDS_CSIDL_COOKIES_L, TEXT("Cookies"), FALSE, FALSE },
|
||
|
{ IDS_CSIDL_HISTORY_L, TEXT("History"), FALSE, FALSE },
|
||
|
};
|
||
|
|
||
|
void InitShellFolders(void)
|
||
|
{
|
||
|
LONG err;
|
||
|
HKEY hkeySF = NULL;
|
||
|
HKEY hkeyUSF = NULL;
|
||
|
TCHAR szDefaultDir[MAX_PATH];
|
||
|
TCHAR szRootDir[MAX_PATH+1]; // possible extra '\'
|
||
|
LPSTR pszPathEnd;
|
||
|
LPSTR pszRootEnd;
|
||
|
|
||
|
/* Get the windows directory and simulate PathAddBackslash (which we
|
||
|
* can't get out of shlwapi, because loadwc.exe also needs to be able
|
||
|
* to load after IE has been uninstalled and shlwapi deleted).
|
||
|
*
|
||
|
* Also build the root directory of the drive that the Windows directory
|
||
|
* is on, so we can put My Documents there if necessary.
|
||
|
*/
|
||
|
*szDefaultDir = TEXT('\0');
|
||
|
GetWindowsDirectory(szDefaultDir, ARRAYSIZE(szDefaultDir));
|
||
|
lstrcpy(szRootDir, szDefaultDir);
|
||
|
MakeWindowsRootPath(szRootDir);
|
||
|
pszRootEnd = szRootDir + lstrlen(szRootDir);
|
||
|
|
||
|
pszPathEnd = CharPrev(szDefaultDir, szDefaultDir + lstrlen(szDefaultDir));
|
||
|
if (*pszPathEnd != '\\') {
|
||
|
pszPathEnd = CharNext(pszPathEnd);
|
||
|
*(pszPathEnd++) = '\\';
|
||
|
}
|
||
|
// pszPathEnd now points to where we can append the relative path
|
||
|
UINT cchPathSpace = ARRAYSIZE(szDefaultDir) - (UINT)(pszPathEnd - szDefaultDir);
|
||
|
UINT cchRootSpace = ARRAYSIZE(szRootDir) - (UINT)(pszRootEnd - szRootDir);
|
||
|
|
||
|
err = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
|
||
|
0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeySF);
|
||
|
if (err == ERROR_SUCCESS) {
|
||
|
err = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders",
|
||
|
0, KEY_QUERY_VALUE, &hkeyUSF);
|
||
|
if (err == ERROR_SUCCESS) {
|
||
|
for (UINT i=0; i<ARRAYSIZE(aFolders); i++) {
|
||
|
TCHAR szRawFolderName[MAX_PATH];
|
||
|
TCHAR szExpandedFolderName[MAX_PATH];
|
||
|
DWORD dwType;
|
||
|
DWORD cbData = sizeof(szRawFolderName);
|
||
|
LPSTR pszPath;
|
||
|
|
||
|
err = RegQueryValueEx(hkeyUSF, aFolders[i].pszRegValue,
|
||
|
NULL, &dwType, (LPBYTE)szRawFolderName,
|
||
|
&cbData);
|
||
|
if (err == ERROR_SUCCESS) {
|
||
|
if ((dwType != REG_EXPAND_SZ && dwType != REG_SZ) ||
|
||
|
!ExpandEnvironmentStrings(szRawFolderName,
|
||
|
szExpandedFolderName,
|
||
|
ARRAYSIZE(szExpandedFolderName)))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
pszPath = szExpandedFolderName;
|
||
|
}
|
||
|
else {
|
||
|
if (!MLLoadString(aFolders[i].idsDirName,
|
||
|
aFolders[i].fDefaultInRoot ? pszRootEnd : pszPathEnd,
|
||
|
aFolders[i].fDefaultInRoot ? cchRootSpace : cchPathSpace)) {
|
||
|
continue;
|
||
|
}
|
||
|
if (aFolders[i].fDefaultInRoot)
|
||
|
pszPath = szRootDir;
|
||
|
else
|
||
|
pszPath = szDefaultDir;
|
||
|
|
||
|
if (GetFileAttributes(pszPath) == 0xffffffff)
|
||
|
CreateDirectory(pszPath, NULL);
|
||
|
|
||
|
/* The Win95 shell has a bug where for some shell folders,
|
||
|
* if there isn't a path recorded under User Shell Folders,
|
||
|
* the shell folder is assumed not to exist. So, for those
|
||
|
* folders only, we also write the default path to USF.
|
||
|
* We do not do this generically because no value under
|
||
|
* USF is supposed to mean "use the one in the Windows
|
||
|
* directory", whereas an absolute path means "use that
|
||
|
* path"; if there's a path under USF, it will be used
|
||
|
* literally, which is a problem if the folder is set up
|
||
|
* to use the shared folder location but roams to a machine
|
||
|
* with Windows installed in a different directory.
|
||
|
*/
|
||
|
if (aFolders[i].fWriteToUSF) {
|
||
|
RegSetValueEx(hkeyUSF, aFolders[i].pszRegValue, 0, REG_SZ,
|
||
|
(LPBYTE)pszPath, lstrlen(pszPath)+1);
|
||
|
}
|
||
|
}
|
||
|
RegSetValueEx(hkeySF, aFolders[i].pszRegValue, 0, REG_SZ,
|
||
|
(LPBYTE)pszPath, lstrlen(pszPath)+1);
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hkeyUSF);
|
||
|
}
|
||
|
RegCloseKey(hkeySF);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Function to determine whether we're in integrated-shell mode or browser-only
|
||
|
* mode. The method for doing this (looking for DllGetVersion exported from
|
||
|
* shell32.dll) is taken from shdocvw. We don't actually call that entrypoint,
|
||
|
* we just look for it.
|
||
|
*/
|
||
|
BOOL IsIntegratedShellMode()
|
||
|
{
|
||
|
FARPROC pfnDllGetVersion = NULL;
|
||
|
HMODULE hmodShell = LoadLibrary("shell32.dll");
|
||
|
if (hmodShell != NULL) {
|
||
|
pfnDllGetVersion = GetProcAddress(hmodShell, "DllGetVersion");
|
||
|
FreeLibrary(hmodShell);
|
||
|
}
|
||
|
|
||
|
return (pfnDllGetVersion != NULL);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Convert the string to a DWORD.
|
||
|
//
|
||
|
DWORD StringToDW(LPCTSTR psz)
|
||
|
{
|
||
|
DWORD dwRet = 0;
|
||
|
|
||
|
while (*psz >= TEXT('0') && *psz <= TEXT('9'))
|
||
|
{
|
||
|
dwRet = dwRet * 10 + *psz - TEXT('0');
|
||
|
*psz++;
|
||
|
}
|
||
|
|
||
|
return dwRet;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Is the version string from IE4
|
||
|
//
|
||
|
|
||
|
BOOL IsVersionIE4(LPCTSTR pszVersion)
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
|
||
|
//
|
||
|
// IE3.0 is 4.70 and Ie4.0x is >= 4.71.1218.xxxx
|
||
|
//
|
||
|
|
||
|
if (pszVersion[0] == TEXT('4') && pszVersion[1] == TEXT('.'))
|
||
|
{
|
||
|
DWORD dw = StringToDW(pszVersion+2);
|
||
|
|
||
|
if (dw > 71 || (dw == 71 && pszVersion[4] == TEXT('.') &&
|
||
|
StringToDW(pszVersion+5) >= 1218))
|
||
|
{
|
||
|
fRet = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Determine if this is an IE4 upgrade.
|
||
|
//
|
||
|
BOOL IsIE4Upgrade()
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
|
||
|
TCHAR szVersion[MAX_PATH];
|
||
|
|
||
|
if (ReadRegValue(HKEY_LOCAL_MACHINE,
|
||
|
TEXT("Software\\Microsoft\\IE Setup\\Setup"),
|
||
|
TEXT("PreviousIESysFile"), (void *)szVersion,
|
||
|
sizeof(szVersion)))
|
||
|
{
|
||
|
fRet = IsVersionIE4(szVersion);
|
||
|
}
|
||
|
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This is an IE5 or later function. If the user's machine is running IE4 they
|
||
|
// have uninstalled back to IE4.
|
||
|
//
|
||
|
BOOL IsUninstallToIE4()
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
|
||
|
TCHAR szVersion[MAX_PATH];
|
||
|
|
||
|
if (ReadRegValue(HKEY_LOCAL_MACHINE,
|
||
|
TEXT("Software\\Microsoft\\Internet Explorer"),
|
||
|
TEXT("Version"), (void *)szVersion,
|
||
|
sizeof(szVersion)))
|
||
|
{
|
||
|
fRet = IsVersionIE4(szVersion);
|
||
|
}
|
||
|
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
/* Function to launch miscellaneous applications for browser only mode.
|
||
|
* We run IEXPLORE.EXE -channelband, looking in the registry for the path
|
||
|
* to IEXPLORE, and WELCOME.EXE /f, located in the same directory.
|
||
|
*/
|
||
|
|
||
|
#ifdef ENABLE_CHANNELS
|
||
|
const TCHAR c_szChanBarRegPath[] = TEXT("Software\\Microsoft\\Internet Explorer\\Main");
|
||
|
const TCHAR c_szChanBarKey[] = TEXT("Show_ChannelBand");
|
||
|
#endif
|
||
|
|
||
|
void LaunchBrowserOnlyApps()
|
||
|
{
|
||
|
TCHAR szPath[MAX_PATH];
|
||
|
|
||
|
/* Don't launch any of these guys if this is a "redist mode" install,
|
||
|
* i.e. if a game or something installed browser components silently
|
||
|
* without the user really realizing it's there.
|
||
|
*/
|
||
|
if (ReadRegValue(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\IE Setup\\Setup",
|
||
|
"InstallMode", (void *)szPath, sizeof(szPath))
|
||
|
&& !lstrcmp(szPath, "R")) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
LPTSTR pszPathEnd;
|
||
|
LONG cbPath = sizeof(szPath);
|
||
|
|
||
|
/* Get the default value from the App Paths\IEXPLORE.EXE reg key, which
|
||
|
* is the absolute path to the EXE.
|
||
|
*/
|
||
|
if (RegQueryValue(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\IEXPLORE.EXE",
|
||
|
szPath, &cbPath) != ERROR_SUCCESS) {
|
||
|
pszPathEnd = szPath;
|
||
|
lstrcpy(szPath, "IEXPLORE.EXE"); /* can't get from reg, hope it's on the path */
|
||
|
}
|
||
|
else {
|
||
|
/* Find the last backslash in the path. This is a manual
|
||
|
* version of strrchr(szPath, '\\').
|
||
|
*/
|
||
|
LPTSTR pszLastBackslash = NULL;
|
||
|
for (pszPathEnd = szPath; *pszPathEnd; pszPathEnd = CharNext(pszPathEnd)) {
|
||
|
if (*pszPathEnd == '\\')
|
||
|
pszLastBackslash = pszPathEnd;
|
||
|
}
|
||
|
if (pszLastBackslash == NULL)
|
||
|
pszPathEnd = szPath;
|
||
|
else
|
||
|
pszPathEnd = pszLastBackslash + 1; /* point after last backslash */
|
||
|
}
|
||
|
|
||
|
#ifdef ENABLE_CHANNELS
|
||
|
|
||
|
/* Don't launch the channel band app if the user doesn't want it.
|
||
|
* They want it if the reg value is missing, or if it's "yes".
|
||
|
* On WinNT, we default to "no" for browser-only installs.
|
||
|
*/
|
||
|
TCHAR szValue[20];
|
||
|
BOOL fShowChannelBand=FALSE;
|
||
|
|
||
|
if (ReadRegValue(HKEY_CURRENT_USER, c_szChanBarRegPath,
|
||
|
c_szChanBarKey, (void *)szValue, sizeof(szValue)))
|
||
|
{
|
||
|
if (!lstrcmpi(szValue, "yes"))
|
||
|
{
|
||
|
fShowChannelBand=TRUE;
|
||
|
}
|
||
|
}
|
||
|
//
|
||
|
// In general, don't auto launch the channel bar post IE4.
|
||
|
//
|
||
|
// Exception: Show the channelband if there is no Show_ChannelBand key and
|
||
|
// the user upgraded over IE4 and this is W95 or W98. This is required
|
||
|
// because IE4 would launch a channel bar in this scenario w/o writting the
|
||
|
// Show_ChannelBand key. We don't want to turn of the channel bar for these
|
||
|
// users.
|
||
|
//
|
||
|
// Another exception: Loadwc doesn't get uninstalled when IE is
|
||
|
// uninstalled. If the user uninstalls IE5+ and goes back to IE4 we want
|
||
|
// this version of loadwc to revert to IE4 loadwc behavior.
|
||
|
//
|
||
|
else
|
||
|
{
|
||
|
OSVERSIONINFO vi;
|
||
|
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||
|
GetVersionEx(&vi);
|
||
|
|
||
|
if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT &&
|
||
|
(IsIE4Upgrade() || IsUninstallToIE4()))
|
||
|
{
|
||
|
fShowChannelBand=TRUE;
|
||
|
|
||
|
//
|
||
|
// Set the registry key so this code only runs once and upgrades to
|
||
|
// IE5 don't have to worry about this scenario.
|
||
|
//
|
||
|
|
||
|
WriteRegValue(HKEY_CURRENT_USER, c_szChanBarRegPath, c_szChanBarKey,
|
||
|
REG_SZ, TEXT("yes"), sizeof(TEXT("yes")));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WriteRegValue(HKEY_CURRENT_USER, c_szChanBarRegPath, c_szChanBarKey,
|
||
|
REG_SZ, TEXT("no"), sizeof(TEXT("no")));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fShowChannelBand)
|
||
|
{
|
||
|
int cLen = lstrlen(szPath);
|
||
|
lstrcpyn(szPath + cLen, " -channelband", ARRAYSIZE(szPath) - cLen);
|
||
|
WinExec(szPath, SW_SHOWNORMAL);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* Check the registry to see if the welcome app should be launched. Again,
|
||
|
* only launch if value is missing or positive (non-zero dword, this time).
|
||
|
*/
|
||
|
DWORD dwShow = 0;
|
||
|
if (!ReadRegValue(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Tips",
|
||
|
"ShowIE4", (void *)&dwShow, sizeof(dwShow))
|
||
|
|| dwShow) {
|
||
|
lstrcpyn(pszPathEnd, "WELCOME.EXE /f", ARRAYSIZE(szPath) - (UINT)(pszPathEnd - szPath));
|
||
|
WinExec(szPath, SW_SHOWNORMAL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// WinMain
|
||
|
//----------------------------------------------------------------------------
|
||
|
int WINAPI WinMainT(
|
||
|
HINSTANCE hInstance, // handle to current instance
|
||
|
HINSTANCE hPrevInstance, // handle to previous instance
|
||
|
LPSTR lpCmdLine, // pointer to command line
|
||
|
int nCmdShow // show state of window
|
||
|
)
|
||
|
{
|
||
|
HWND hwndOtherInstance;
|
||
|
|
||
|
// Save the globals
|
||
|
g.hInstance = hInstance;
|
||
|
g.nCmdShow = SW_HIDE;
|
||
|
g.fUninstallOnly = FALSE;
|
||
|
g.fStartSensLce = FALSE;
|
||
|
|
||
|
g.fIntShellMode = IsIntegratedShellMode();
|
||
|
g.hWebcheck = NULL;
|
||
|
|
||
|
MLLoadResources(g.hInstance, TEXT("loadwclc.dll"));
|
||
|
|
||
|
// Parse the command line, for DEBUG options and for uninstall-only switch.
|
||
|
// Now also sets fStartSensLce
|
||
|
if (!bParseCommandLine(lpCmdLine, nCmdShow))
|
||
|
return 0;
|
||
|
|
||
|
// look for webcheck window. This is ultimately the guy we need to
|
||
|
// find to load sens/lce late in the game.
|
||
|
hwndOtherInstance = FindWindow(c_szWebCheckWindow, c_szWebCheckWindow);
|
||
|
|
||
|
if(NULL == hwndOtherInstance)
|
||
|
{
|
||
|
// can't find webcheck, look for loadwc. If we find him but not
|
||
|
// webcheck, we either don't have the MOP or we're still in the 15
|
||
|
// second delay. Send the messages to loadwc and he'll take care
|
||
|
// of it.
|
||
|
hwndOtherInstance = FindWindow(c_szClassName, c_szClassName);
|
||
|
}
|
||
|
|
||
|
if(hwndOtherInstance)
|
||
|
{
|
||
|
// an instance is already running. Tell it about Sens/LCE loading
|
||
|
// requirements and bail out
|
||
|
if(g.fStartSensLce)
|
||
|
{
|
||
|
PostMessage(hwndOtherInstance, WM_START_SENSLCE, 0, 0);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Set up the absolute paths for all the shell folders we care about,
|
||
|
// in case we're in browser-only mode and the shell doesn't support
|
||
|
// the new ones.
|
||
|
if (!g.fUninstallOnly)
|
||
|
InitShellFolders();
|
||
|
|
||
|
// Run all install/uninstall stubs for browser-only mode.
|
||
|
// If IE4 has been uninstalled, we'll be run with the -u switch; this
|
||
|
// means to run install/uninstall stubs only, no webcheck stuff.
|
||
|
if (!g.fIntShellMode) {
|
||
|
RunInstallUninstallStubs2(NULL);
|
||
|
}
|
||
|
|
||
|
if (g.fUninstallOnly)
|
||
|
return 0;
|
||
|
|
||
|
// Launch the channel bar and welcome apps in browser-only mode.
|
||
|
if (!g.fIntShellMode) {
|
||
|
LaunchBrowserOnlyApps();
|
||
|
}
|
||
|
|
||
|
// Register the window class for the main window.
|
||
|
WNDCLASS wc;
|
||
|
if (!hPrevInstance)
|
||
|
{
|
||
|
wc.style = 0;
|
||
|
wc.lpfnWndProc = WndProc;
|
||
|
wc.cbClsExtra = 0;
|
||
|
wc.cbWndExtra = 0;
|
||
|
wc.hInstance = hInstance;
|
||
|
wc.hIcon = NULL;
|
||
|
wc.hCursor = NULL;
|
||
|
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
||
|
wc.lpszMenuName = NULL;
|
||
|
wc.lpszClassName = c_szClassName;
|
||
|
|
||
|
if (!RegisterClass(&wc))
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Create the main window.
|
||
|
g.hwnd = CreateWindow(c_szClassName,
|
||
|
c_szClassName,
|
||
|
WS_OVERLAPPEDWINDOW,
|
||
|
CW_USEDEFAULT,
|
||
|
CW_USEDEFAULT,
|
||
|
CW_USEDEFAULT,
|
||
|
CW_USEDEFAULT,
|
||
|
(HWND) NULL,
|
||
|
(HMENU) NULL,
|
||
|
hInstance,
|
||
|
(LPVOID) NULL);
|
||
|
if (!g.hwnd)
|
||
|
return 0;
|
||
|
|
||
|
// Show the window and paint its contents.
|
||
|
ShowWindow(g.hwnd, g.nCmdShow);
|
||
|
|
||
|
// Start the message loop
|
||
|
MSG msg;
|
||
|
while (GetMessage(&msg, (HWND) NULL, 0, 0)) {
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
|
||
|
MLFreeResources(g.hInstance);
|
||
|
|
||
|
// Return the exit code to Windows
|
||
|
return (int)msg.wParam;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// WndProc
|
||
|
//----------------------------------------------------------------------------
|
||
|
LRESULT APIENTRY WndProc(
|
||
|
HWND hwnd,
|
||
|
UINT uMsg,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam
|
||
|
)
|
||
|
{
|
||
|
switch (uMsg) {
|
||
|
case WM_CREATE:
|
||
|
DWORD dwTime;
|
||
|
if(!ReadRegValue(HKEY_CURRENT_USER, c_szWebcheckKey, "DelayLoad", &dwTime, sizeof(DWORD)))
|
||
|
dwTime = 15;
|
||
|
SetTimer(hwnd, 1, 1000 * dwTime, NULL);
|
||
|
break;
|
||
|
|
||
|
case WM_START_SENSLCE:
|
||
|
g.fStartSensLce = TRUE;
|
||
|
break;
|
||
|
|
||
|
case WM_TIMER:
|
||
|
KillTimer(hwnd, 1);
|
||
|
vLoadWebCheck();
|
||
|
return 0;
|
||
|
|
||
|
case WM_ENDSESSION:
|
||
|
if (!wParam) // if not fEndSession, bail
|
||
|
break;
|
||
|
// else fall through to WM_DESTROY
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
vUnloadWebCheck();
|
||
|
PostQuitMessage(0);
|
||
|
return 0;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// vLoadWebCheck
|
||
|
//----------------------------------------------------------------------------
|
||
|
void vLoadWebCheck(void)
|
||
|
{
|
||
|
if(g.hWebcheck)
|
||
|
return;
|
||
|
|
||
|
g.hWebcheck = LoadLibrary(TEXT("webcheck.dll"));
|
||
|
if(g.hWebcheck)
|
||
|
{
|
||
|
PFNSTART pfn = (PFNSTART)GetProcAddress(g.hWebcheck, (LPCSTR)7);
|
||
|
if(pfn)
|
||
|
{
|
||
|
pfn(g.fStartSensLce);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// clean up dll
|
||
|
FreeLibrary(g.hWebcheck);
|
||
|
g.hWebcheck = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// vUnloadWebCheck
|
||
|
//----------------------------------------------------------------------------
|
||
|
void vUnloadWebCheck(void)
|
||
|
{
|
||
|
if (!g.hWebcheck)
|
||
|
return;
|
||
|
|
||
|
PFNSTOP pfn = (PFNSTOP)GetProcAddress(g.hWebcheck, (LPCSTR)8);
|
||
|
if(pfn)
|
||
|
{
|
||
|
pfn();
|
||
|
}
|
||
|
|
||
|
// [darrenmi] don't bother unloading webcheck. We only do this in
|
||
|
// response to a shut down so it's not a big deal. On NT screen saver
|
||
|
// proxy has a thread that wakes up after the call to StopService - if
|
||
|
// we've unloaded the dll before then, we're toast.
|
||
|
|
||
|
// clean up dll
|
||
|
//FreeLibrary(g.hWebcheck);
|
||
|
//g.hWebcheck = NULL;
|
||
|
}
|
||
|
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
// StringFromGuid
|
||
|
// returns an ANSI string from a CLSID or GUID
|
||
|
//
|
||
|
// Parameters:
|
||
|
// REFIID - [in] clsid to make string out of.
|
||
|
// LPSTR - [in] buffer in which to place resultant GUID.
|
||
|
//
|
||
|
// Output:
|
||
|
// int - number of chars written out.
|
||
|
//=--------------------------------------------------------------------------=
|
||
|
#ifdef DEBUG
|
||
|
int StringFromGuid(
|
||
|
const CLSID* piid,
|
||
|
LPTSTR pszBuf
|
||
|
)
|
||
|
{
|
||
|
return wsprintf(pszBuf, TEXT("{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"), piid->Data1,
|
||
|
piid->Data2, piid->Data3, piid->Data4[0], piid->Data4[1], piid->Data4[2],
|
||
|
piid->Data4[3], piid->Data4[4], piid->Data4[5], piid->Data4[6], piid->Data4[7]);
|
||
|
}
|
||
|
#endif // DEBUG
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// bParseCmdLine
|
||
|
//
|
||
|
// Parse the command line
|
||
|
// -u run install/uninstall stubs only, then quit
|
||
|
// DEBUG options:
|
||
|
// -v visible window (easy to shutdown)
|
||
|
// -a add webcheck to shell service object
|
||
|
// -r remove webcheck from shell service object
|
||
|
// -s fix shell folders only
|
||
|
// -? these options
|
||
|
//----------------------------------------------------------------------------
|
||
|
BOOL bParseCommandLine(LPSTR lpCmdLine, int nCmdShow)
|
||
|
{
|
||
|
if (!lpCmdLine)
|
||
|
return TRUE;
|
||
|
|
||
|
CharUpper(lpCmdLine); /* easier to parse */
|
||
|
while (*lpCmdLine) {
|
||
|
if (*lpCmdLine != '-' && *lpCmdLine != '/')
|
||
|
break;
|
||
|
|
||
|
lpCmdLine++;
|
||
|
|
||
|
switch (*(lpCmdLine++)) {
|
||
|
case 'E':
|
||
|
// ignore 'embedding' command line
|
||
|
break;
|
||
|
case 'L':
|
||
|
case 'M':
|
||
|
g.fStartSensLce = TRUE;
|
||
|
break;
|
||
|
case 'U':
|
||
|
g.fUninstallOnly = TRUE;
|
||
|
break;
|
||
|
#ifdef DEBUG
|
||
|
case 'V':
|
||
|
g.nCmdShow = nCmdShow;
|
||
|
break;
|
||
|
case 'A':
|
||
|
{
|
||
|
HKEY hkey;
|
||
|
DWORD dwRet;
|
||
|
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szShellReg, 0, 0, 0, KEY_READ | KEY_WRITE, NULL, &hkey, &dwRet))
|
||
|
{
|
||
|
// NOTE: Does it matter if we set this as ANSI or Unicode? No, stored in Unicode.
|
||
|
// NOTE: Does sizeof include the terminating null? Yes.
|
||
|
int iRet;
|
||
|
TCHAR szCLSID[GUIDSTR_MAX];
|
||
|
iRet = StringFromGuid(&CLSID_WebCheck, szCLSID);
|
||
|
ASSERT(GUIDSTR_MAX == (iRet + 1));
|
||
|
|
||
|
if (ERROR_SUCCESS == RegSetValueEx(hkey, c_szWebCheck, 0, REG_SZ, (CONST BYTE*)szCLSID, sizeof(szCLSID)))
|
||
|
{
|
||
|
MessageBox(NULL, "Webcheck was added to the shell service object list", "LoadWC", MB_OK);
|
||
|
}
|
||
|
RegCloseKey(hkey);
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'R':
|
||
|
{
|
||
|
HKEY hkey;
|
||
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szShellReg, 0, KEY_READ | KEY_WRITE, &hkey))
|
||
|
{
|
||
|
if (ERROR_SUCCESS == RegDeleteValue(hkey, c_szWebCheck))
|
||
|
MessageBox(NULL, "Webcheck was removed from the shell service object list", "LoadWC", MB_OK);
|
||
|
RegCloseKey(hkey);
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'S':
|
||
|
InitShellFolders();
|
||
|
return FALSE;
|
||
|
|
||
|
case '?':
|
||
|
default:
|
||
|
MessageBox(NULL, "Command line options:\n-v\tvisible window\n-a\tadd webcheck as shell service\n-r\tremove webcheck as shell service\n-s\tfixup shell folders only", "LoadWC", MB_OK);
|
||
|
return FALSE;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
while (*lpCmdLine == ' ' || *lpCmdLine == '\t') {
|
||
|
lpCmdLine++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|