Code/Resource
Windows Develop
Linux-Unix program
Internet-Socket-Network
Web Server
Browser Client
Ftp Server
Ftp Client
Browser Plugins
Proxy Server
Email Server
Email Client
WEB Mail
Firewall-Security
Telnet Server
Telnet Client
ICQ-IM-Chat
Search Engine
Sniffer Package capture
Remote Control
xml-soap-webservice
P2P
WEB(ASP,PHP,...)
TCP/IP Stack
SNMP
Grid Computing
SilverLight
DNS
Cluster Service
Network Security
Communication-Mobile
Game Program
Editor
Multimedia program
Graph program
Compiler program
Compress-Decompress algrithms
Crypt_Decrypt algrithms
Mathimatics-Numerical algorithms
MultiLanguage
Disk/Storage
Java Develop
assembly language
Applications
Other systems
Database system
Embeded-SCM Develop
FlashMX/Flex
source in ebook
Delphi VCL
OS Develop
MiddleWare
MPI
MacOS develop
LabView
ELanguage
Software/Tools
E-Books
Artical/Document
initcab.c
Package: shell.rar [view]
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 69k
Category:
Windows Kernel
Development Platform:
Visual C++
- //--------------------------------------------------------------------------
- // Init the Cabinet (ie the top level browser).
- //---------------------------------------------------------------------------
- //---------------------------------------------------------------------------
- // Includes...
- #include "cabinet.h"
- #include "rcids.h"
- #include "cabwnd.h"
- #include <regstr.h>
- #include "startmnu.h"
- #include <shdguid.h> // for IID_IShellService
- #include <shlguid.h>
- #include "..shdocvwwinlist.h" // BUGBUG: get rid of this
- #include <desktray.h>
- #include <wininet.h>
- #include <dbgmem.h>
- #define DM_SHUTDOWN DM_TRACE // shutdown
- // copied from desktop.cpp
- #define PEEK_NORMAL 0
- #define PEEK_QUIT 1
- // on NT5 we need this event to be global so that it is shared between hydra
- // sessions
- #define SZ_SCMCREATEDEVENT_NT5 TEXT("Global\ScmCreatedEvent")
- #define SZ_SCMCREATEDEVENT TEXT("ScmCreatedEvent")
- // exports from shdocvw.dll
- STDAPI_(void) RunInstallUninstallStubs(void);
- // from win32kernelutctime.c (private)
- DWORD APIENTRY RefreshDaylightInformation(BOOL fChangeTime);
- // shell32.dll exports, shelldllbinder.c
- STDAPI_(void) SHFreeUnusedLibraries();
- int ExplorerWinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPTSTR pszCmdLine, int nCmdShow);
- //Do not change this stock5.lib use this as a BOOL not a bit.
- BOOL g_bMirroredOS = FALSE;
- HINSTANCE hinstCabinet = 0;
- CRITICAL_SECTION g_csDll = { 0 };
- HKEY g_hkeyExplorer = NULL;
- BOOL g_fLogonCycle = FALSE;
- BOOL g_fCleanShutdown = TRUE;
- BOOL g_fExitExplorer = TRUE; // set to FALSE on WM_ENDSESSION shutdown case
- BOOL g_fEndSession = FALSE; // set to TRUE if we rx a WM_ENDSESSION during RunOnce etc
- BOOL g_fFakeShutdown = FALSE; // set to TRUE if we do Ctrl+Alt+Shift+Cancel shutdown
- BOOL g_fRuningOnTerminalServer = FALSE; // Assume we are not running on Hydra
- BOOL Cabinet_IsExplorerWindow(HWND hwnd)
- {
- TCHAR szClass[32];
- GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
- return lstrcmpi(szClass, TEXT("ExploreWClass")) == 0;
- }
- // BUGBUG: does not account for "Browser" windows
- BOOL Cabinet_IsFolderWindow(HWND hwnd)
- {
- TCHAR szClass[32];
- GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
- return lstrcmpi(szClass, TEXT("CabinetWClass")) == 0;
- }
- //---------------------------------------------------------------------------
- typedef enum {
- RRA_DEFAULT = 0x0000,
- RRA_DELETE = 0x0001, // delete each reg value when we're done with it
- RRA_WAIT = 0x0002, // Wait for current item to finish before launching next item
- RRA_SHELLSERVICEOBJECTS = 0x0004, // treat as a shell service object instead of a command sting
- RRA_NOUI = 0x0008, // prevents ShellExecuteEx from displaying error dialogs
- RRA_RUNSUBKEYS = 0x0010, // Run items in sub keys in alphabetical order
- } RRA_FLAGS;
- // The following handles running an application and optionally waiting for it
- // to terminate.
- void ShellExecuteRegApp(LPTSTR szCmdLine, RRA_FLAGS fFlags)
- {
- TCHAR szQuotedCmdLine[MAX_PATH+2];
- SHELLEXECUTEINFO ei;
- LPTSTR pszArgs;
- //
- // We used to call CreateProcess( NULL, szCmdLine, ...) here,
- // but thats not useful for people with apppaths stuff.
- //
- // Don't let empty strings through, they will endup doing something dumb
- // like opening a command prompt or the like
- if (!szCmdLine || !*szCmdLine)
- return;
- // Gross, but if the process command fails, copy the command line to let
- // shell execute report the errors
- if (PathProcessCommand(szCmdLine, szQuotedCmdLine, ARRAYSIZE(szQuotedCmdLine),
- PPCF_ADDARGUMENTS|PPCF_FORCEQUALIFY) == -1)
- lstrcpy(szQuotedCmdLine, szCmdLine);
- pszArgs = PathGetArgs(szQuotedCmdLine);
- if (*pszArgs)
- *(pszArgs - 1) = 0; // Strip args
- PathUnquoteSpaces(szQuotedCmdLine);
- ei.cbSize = sizeof(SHELLEXECUTEINFO);
- ei.hwnd = NULL;
- ei.lpVerb = NULL;
- ei.lpFile = szQuotedCmdLine;
- ei.lpParameters = pszArgs;
- ei.lpDirectory = NULL;
- ei.nShow = SW_SHOWNORMAL;
- ei.fMask = (fFlags & RRA_NOUI)?
- (SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI) : SEE_MASK_NOCLOSEPROCESS;
- // Hydra comment:
- // If we were sure that this func would not be called for anything but handling entries in RunOnce, then
- // I would have out the system in in stall-mode and back to execute-mode right here.
- // However, although I do not see this func being used by anything other than entries in RunOnce,
- // there is no guaranty.
- if (ShellExecuteEx(&ei))
- {
- if ( NULL != ei.hProcess)
- {
- if (fFlags & RRA_WAIT)
- {
- MsgWaitForMultipleObjectsLoop(ei.hProcess, INFINITE);
- }
- CloseHandle(ei.hProcess);
- }
- }
- }
- // The following code manages shell service objects. We load inproc dlls
- // from the registry key and QI them for IOleCommandTarget. Note that all
- // Shell Service Objects are loaded on the desktop thread.
- // CGID_ShellServiceObject notifications are sent to these objects letting
- // them know about shell status.
- HDSA g_hdsaShellServiceObjects=NULL;
- void LoadShellServiceObject(LPCTSTR szValueName, LPCTSTR szCmdLine, RRA_FLAGS fFlags)
- {
- SHELLSERVICEOBJECT sso = {0};
- DebugMsg(DM_TRACE, TEXT("%s %s"), szValueName, szCmdLine);
- if (!g_hdsaShellServiceObjects &&
- !(g_hdsaShellServiceObjects = DSA_Create(sizeof(SHELLSERVICEOBJECT), 2)))
- {
- // Fail
- return;
- }
- if (SHCLSIDFromString(szCmdLine, &sso.clsid) == S_OK)
- {
- if (SUCCEEDED(CoCreateInstance(&sso.clsid, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
- &IID_IOleCommandTarget, (void **)&sso.pct)))
- {
- lstrcpyn(sso.szName, szValueName, ARRAYSIZE(sso.szName));
- if (DSA_AppendItem(g_hdsaShellServiceObjects, &sso) == -1)
- {
- DebugMsg( DM_ERROR, TEXT("Cannot add to dsa <%s>"), szValueName );
- sso.pct->lpVtbl->Release(sso.pct);
- }
- }
- }
- }
- //
- // While we are doing our RunOnce processing, we want to change the
- // system cursor. We can't use SetClassLong on the desktop class
- // because that's illegal under Win32. And we can't use SetSystemCursor
- // because on NT, CopyImage on a system cursor doesn't actually copy
- // the cursor. It merely returns the original cursor handle back,
- // which leaves us in a bit of a fix because the original cursor is
- // about to be obliterated by SetSystemCursor!
- //
- // So instead, we create a full-virtual-screen window that always ducks
- // to the bottom of the Z-order. We can't use SetShellWindow and make
- // USER do the ducking for us, because RunOnce applets might get confused
- // if they see a GetShellWindow before the shell is initialized.
- //
- // We can't use a shlwapi worker window because we need to make the
- // class background brush COLOR_DESKTOP to ensure that we don't get
- // ugly white flashes if the user quickly drags a window around our
- // fake desktop.
- //
- // You'd think this would be easy, but there are a lot of subtleties.
- //
- LRESULT RegAppsWaitWndProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
- {
- switch (wm) {
- case WM_WINDOWPOSCHANGING:
- ((LPWINDOWPOS)lp)->hwndInsertAfter = HWND_BOTTOM; // force to bottom
- break; // proceed with default action
- // Subtlety: Must erase background with PaintDesktop so user's
- // wallpaper shows through.
- //
- // Double subtlety: Don't paint directly through the HDC that comes
- // in via the wParam, because that HDC is >not clipped<. Consequently,
- // you get horrible flickering since we repaint the entire desktop.
- //
- // Triple subtlety: You have to do this in the WM_ERASEBKGND handler,
- // not the WM_PAINT handler, because MsgWaitForMultipleObjectsLoop
- // waits only for QS_SENDMESSAGE and not QS_PAINT.
- case WM_ERASEBKGND:
- {
- PAINTSTRUCT ps;
- BeginPaint(hwnd, &ps);
- PaintDesktop(ps.hdc);
- EndPaint(hwnd, &ps);
- }
- return 0;
- case WM_ENDSESSION:
- g_fEndSession = (BOOL)wp;
- break;
- }
- return DefWindowProc(hwnd, wm, wp, lp);
- }
- #define REGAPPSWAIT_CLASS TEXT("RegAppsWait")
- HWND CreateRegAppsWaitWindow(void)
- {
- WNDCLASS wc;
- // Should never try to do this if the main desktop is already up
- ASSERT(!GetShellWindow());
- wc.style = 0;
- wc.lpfnWndProc = RegAppsWaitWndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = hinstCabinet;
- wc.hIcon = 0;
- //
- // Doesn't matter what cursor we choose because NT USER will say
- // "Stupid app not waiting for QS_POSTMESSAGE so I will always display
- // an hourglass cursor." But do the right thing in case NT USER
- // decides actually to pay attention to our class cursor.
- //
- wc.hCursor = LoadCursor(NULL, IDC_APPSTARTING);
- // Subtlety: Don't use (HBRUSH)(COLOR_DESKTOP+1). If the user
- // drags a window across the desktop, USER will first paint the
- // window with the class background brush and only later will
- // actually send the WM_ERASEBKGND message. If the user's
- // desktop wallpaper has a different color from COLOR_DESKTOP,
- // you will see ugly flashing as the exposed bits are first
- // painted in COLOR_DESKTOP, and then later with the wallpaper.
- wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
- wc.lpszMenuName = 0;
- wc.lpszClassName = REGAPPSWAIT_CLASS;
- RegisterClass(&wc);
- return CreateWindow(
- REGAPPSWAIT_CLASS, /* Class Name */
- NULL, /* Title */
- WS_POPUP | WS_CLIPCHILDREN | WS_VISIBLE,/* Style */
- GetSystemMetrics(SM_XVIRTUALSCREEN), /* Position */
- GetSystemMetrics(SM_YVIRTUALSCREEN), /* Position */
- GetSystemMetrics(SM_CXVIRTUALSCREEN), /* Size */
- GetSystemMetrics(SM_CYVIRTUALSCREEN), /* Size */
- NULL, /* Parent */
- NULL, /* Menu */
- hinstCabinet, /* Instance */
- 0); /* Special parameters */
- }
- void DestroyRegAppsWaitWindow(HWND hwnd)
- {
- DestroyWindow(hwnd);
- UnregisterClass(REGAPPSWAIT_CLASS, hinstCabinet);
- }
- BOOL RunRegAppsAndObjects(HKEY hkeyParent, LPCTSTR szSubkey, RRA_FLAGS fFlags)
- {
- HKEY hkey;
- BOOL fShellInit = FALSE;
- if (RegOpenKey(hkeyParent, szSubkey, &hkey) == ERROR_SUCCESS)
- {
- DWORD cbData, cbValue, dwType, i;
- TCHAR szValueName[80], szCmdLine[MAX_PATH];
- // BUGBUG: should we do this in retail too or is it too scary :)
- #ifdef DEBUG
- //
- // we only support named values so explicitly purge default values
- //
- cbData = SIZEOF(szCmdLine);
- if (RegQueryValue(hkey, NULL, szCmdLine, &cbData) == ERROR_SUCCESS)
- {
- AssertMsg((cbData <= 2), TEXT("BOGUS default entry in <%s> '%s'"), szSubkey, szCmdLine);
- RegDeleteValue(hkey, NULL);
- }
- #endif
- if ( fFlags & RRA_RUNSUBKEYS )
- {
- // run the contents of each sub key. Keys must be run in alphabetical order. The sub keys
- // are used to prioritize the launching of items. We only run one level of subkey so we need
- // to turn off the subkey flag.
- RRA_FLAGS fSubkeyFlags = fFlags & ~(RRA_RUNSUBKEYS);
- for (i=0; !g_fEndSession ; i++)
- {
- LONG lEnum;
- cbValue = ARRAYSIZE(szValueName);
- // BUGBUG: This is a dirty assumption. This assumes several unsafe things:
- // 1.) none of the programs being run will changes this section of the registry.
- // 2.) NT enumerates registry items in alphabetic order.
- // Since it isn't safe to make assumption #1 this needs to be made more robust.
- lEnum = RegEnumKey( hkey, i, szValueName, cbValue );
- if( ERROR_MORE_DATA == lEnum )
- {
- // ERROR_MORE_DATA means the value name or data was too large.
- // Skip to the next item.
- DebugMsg( DM_ERROR, TEXT("Explorer: RunRegAppsAndObjects cannot run oversize entry in <%s> '%s'"), szSubkey, szValueName );
- continue;
- }
- else if ( ERROR_SUCCESS != lEnum )
- {
- // could be ERROR_NO_MORE_ENTRIES, or some kind of failure
- // we can't recover from any other registry problem, anyway
- break;
- }
- RunRegAppsAndObjects( hkey, szValueName, fSubkeyFlags );
- if ( fFlags & RRA_DELETE )
- {
- // delete the sub key.
- SHDeleteKey( hkey, szValueName );
- i--;
- }
- }
- }
- else
- {
- //
- // now enumerate all of the values.
- //
- for (i = 0; !g_fEndSession ; i++)
- {
- LONG lEnum;
- cbValue = ARRAYSIZE(szValueName);
- cbData = SIZEOF(szCmdLine);
- lEnum = RegEnumValue( hkey, i, szValueName, &cbValue, NULL, &dwType, (LPBYTE)szCmdLine, &cbData );
- if( ERROR_MORE_DATA == lEnum )
- {
- // ERROR_MORE_DATA means the value name or data was too large
- // skip to the next item
- DebugMsg( DM_ERROR, TEXT("Cannot run oversize entry in <%s>"), szSubkey );
- continue;
- }
- else if ( lEnum != ERROR_SUCCESS )
- {
- // could be ERROR_NO_MORE_ENTRIES, or some kind of failure
- // we can't recover from any other registry problem, anyway
- break;
- }
- if (dwType == REG_SZ)
- {
- DebugMsg(DM_TRACE, TEXT("%s %s"), szSubkey, szCmdLine);
- // only run things marked with a "*" in clean boot
- if (g_fCleanBoot && (szValueName[0] != TEXT('*')))
- continue;
- // NB Things marked with a '!' mean delete after
- // the CreateProcess not before. This is to allow
- // certain apps (runonce.exe) to be allowed to rerun
- // to if the machine goes down in the middle of execing
- // them. Be very afraid of this switch.
- if ((fFlags & RRA_DELETE) && (szValueName[0] != TEXT('!')))
- {
- // This delete can fail if the user doesn't have the privilege
- if (RegDeleteValue(hkey, szValueName) == ERROR_SUCCESS)
- {
- // adjust for shift in value index only if delete succeeded
- i--;
- }
- }
- if (fFlags & RRA_SHELLSERVICEOBJECTS)
- LoadShellServiceObject(szValueName, szCmdLine, fFlags);
- else
- {
- #ifdef WINNT
- // Hydra-Specific stuff
- BOOL hydraInAppInstallMode = FALSE;
- // In here, We only put the Hydra server in app-install-mode if RunOnce entries are
- // being processed
- if (!lstrcmpi(szSubkey, REGSTR_PATH_RUNONCE))
- {
- // See if we are on NT5, and if the terminal-services is enabled
- if (g_fRuningOnTerminalServer)
- {
- if (hydraInAppInstallMode = SetTermsrvAppInstallMode(TRUE))
- {
- fFlags |= RRA_WAIT; // Changing timing blows up IE 4.0, but IE5 is ok!
- }
- }
- }
- #endif // WINNT
- ShellExecuteRegApp(szCmdLine, fFlags);
- #ifdef WINNT
- // Hydra-Specific stuff
- if (hydraInAppInstallMode)
- {
- SetTermsrvAppInstallMode(FALSE);
- }
- #endif // WINNT
- }
- // Post delete '!' things.
- if ((fFlags & RRA_DELETE) && (szValueName[0] == TEXT('!'))) {
- // This delete can fail if the user doesn't have the privilege
- if (RegDeleteValue(hkey, szValueName) == ERROR_SUCCESS)
- {
- // adjust for shift in value index only if delete succeeded
- i--; // adjust for shift in value index
- }
- }
- }
- }
- }
- RegCloseKey(hkey);
- }
- // if we rx'd a WM_ENDSESSION whilst running any of these keys we must exit the
- // process.
- if ( g_fEndSession )
- ExitProcess(0);
- return fShellInit;
- }
- BOOL LoadShellServiceObjects(HKEY hkeyParent, LPCTSTR szSubkey)
- {
- return RunRegAppsAndObjects(hkeyParent, szSubkey, RRA_SHELLSERVICEOBJECTS);
- }
- // clsid - NULL, send to everyone
- // else restrict cmd to given class.
- void CTExecShellServiceObjects(const CLSID *pclsid, DWORD nCmdID, DWORD nCmdexecopt, DWORD flags)
- {
- int iCount;
- int i;
- int iEnd, iStart;
- HDSA hdsaShellServiceObjects;
- if (!g_hdsaShellServiceObjects)
- {
- return;
- }
- // We use a temp variable to protect agains re-entancy (eg netshell calls PeekMessage during the
- // Exec callback). Basically this is single threaded since the tray thread is the only guy who ever
- // calls this function, but we have to be careful that we dont re-enter ourself.
- hdsaShellServiceObjects = g_hdsaShellServiceObjects;
- g_hdsaShellServiceObjects = NULL;
- iCount = DSA_GetItemCount(hdsaShellServiceObjects);
- if (iCount)
- {
- // Loop through all shell service objects and send the command target the
- // command id.
- if (flags & CTEXECSSOF_REVERSE)
- {
- iStart = iCount-1;
- iEnd = 0-1;
- }
- else
- {
- iStart = 0;
- iEnd = iCount;
- }
- for (i=iStart; i != iEnd; (flags & CTEXECSSOF_REVERSE ? i-- : i++))
- {
- PSHELLSERVICEOBJECT psso = (PSHELLSERVICEOBJECT)DSA_GetItemPtr(hdsaShellServiceObjects, i);
- if (!pclsid || IsEqualGUID(&psso->clsid, pclsid))
- {
- psso->pct->lpVtbl->Exec(psso->pct,
- &CGID_ShellServiceObject,
- nCmdID, nCmdexecopt,
- NULL, NULL);
- if (nCmdID==SSOCMDID_CLOSE)
- psso->pct->lpVtbl->Release(psso->pct);
- }
- }
- }
- g_hdsaShellServiceObjects = hdsaShellServiceObjects;
- }
- //---------------------------------------------------------------------------
- void CreateShellDirectories()
- {
- TCHAR szPath[MAX_PATH];
- // Create the shell directories if they don't exist
- SHGetSpecialFolderPath(NULL, szPath, CSIDL_DESKTOPDIRECTORY, TRUE);
- SHGetSpecialFolderPath(NULL, szPath, CSIDL_PROGRAMS, TRUE);
- SHGetSpecialFolderPath(NULL, szPath, CSIDL_STARTMENU, TRUE);
- SHGetSpecialFolderPath(NULL, szPath, CSIDL_STARTUP, TRUE);
- SHGetSpecialFolderPath(NULL, szPath, CSIDL_RECENT, TRUE);
- SHGetSpecialFolderPath(NULL, szPath, CSIDL_FAVORITES, TRUE);
- }
- //----------------------------------------------------------------------------
- // returns:
- // TRUE if the user wants to abort the startup sequence
- // FALSE keep going
- //
- // note: this is a switch, once on it will return TRUE to all
- // calls so these keys don't need to be pressed the whole time
- BOOL AbortStartup()
- {
- static BOOL bAborted = FALSE; // static so it sticks!
- // DebugMsg(DM_TRACE, "Abort Startup?");
- if (bAborted)
- return TRUE; // don't do funky startup stuff
- else {
- bAborted = (g_fCleanBoot || ((GetAsyncKeyState(VK_CONTROL) < 0) || (GetAsyncKeyState(VK_SHIFT) < 0)));
- return bAborted;
- }
- }
- // BUGBUG: hwndOwner is no longer used (NULL is passed in) remove the hwndOwner code
- // once we are certain that this isn't needed
- BOOL EnumFolder_Startup(IShellFolder * psf, HWND hwndOwner, LPITEMIDLIST pidlFolder, LPITEMIDLIST pidlItem)
- {
- LPCONTEXTMENU pcm;
- HRESULT hres;
- // MSG msg;
- hres = psf->lpVtbl->GetUIObjectOf(psf, hwndOwner, 1, &pidlItem, & IID_IContextMenu, NULL, &pcm);
- if (SUCCEEDED(hres))
- {
- HMENU hmenu = CreatePopupMenu();
- if (hmenu)
- {
- #define CMD_ID_FIRST 1
- #define CMD_ID_LAST 0x7fff
- INT idCmd;
- pcm->lpVtbl->QueryContextMenu(pcm, hmenu, 0, CMD_ID_FIRST, CMD_ID_LAST, CMF_DEFAULTONLY);
- idCmd = GetMenuDefaultItem(hmenu, MF_BYCOMMAND, 0);
- if (idCmd)
- {
- CMINVOKECOMMANDINFOEX ici;
- ZeroMemory(&ici, SIZEOF(ici));
- ici.cbSize = SIZEOF(ici);
- ici.hwnd = hwndOwner;
- ici.lpVerb = (LPSTR)MAKEINTRESOURCE(idCmd - 1);
- ici.nShow = SW_NORMAL;
- pcm->lpVtbl->InvokeCommand(pcm, (LPCMINVOKECOMMANDINFO)&ici);
- }
- DestroyMenu(hmenu);
- }
- pcm->lpVtbl->Release(pcm);
- }
- if (AbortStartup())
- return FALSE;
- return TRUE;
- }
- //----------------------------------------------------------------------------
- // BUGBUG: hwndOwner is no longer used (NULL is passed in) remove the hwndOwner code
- // once we are certain that this isn't needed
- void EnumFolder(HWND hwndOwner, LPITEMIDLIST pidlFolder, DWORD grfFlags, PFNENUMFOLDERCALLBACK pfn)
- {
- IShellFolder *psf = BindToFolder(pidlFolder);
- if (psf)
- {
- LPENUMIDLIST penum;
- HRESULT hres = psf->lpVtbl->EnumObjects(psf, hwndOwner, grfFlags, &penum);
- if (SUCCEEDED(hres))
- {
- LPITEMIDLIST pidl;
- UINT celt;
- while (penum->lpVtbl->Next(penum, 1, &pidl, &celt)==NOERROR && celt==1)
- {
- if (!pfn(psf, hwndOwner, pidlFolder, pidl))
- {
- SHFree(pidl);
- break;
- }
- SHFree(pidl);
- }
- penum->lpVtbl->Release(penum);
- }
- psf->lpVtbl->Release(psf);
- }
- }
- //----------------------------------------------------------------------------
- // BUGBUG: hwndOwner is no longer used (NULL is passed in) remove the hwndOwner code
- // once we are certain that this isn't needed
- void _ExecuteStartupPrograms(HWND hwndOwner)
- {
- LPITEMIDLIST pidlStartup;
- if (AbortStartup())
- return;
- pidlStartup = SHCloneSpecialIDList(NULL, CSIDL_COMMON_STARTUP, TRUE);
- if (pidlStartup)
- {
- EnumFolder(hwndOwner, pidlStartup, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, EnumFolder_Startup);
- ILFree(pidlStartup);
- }
- //
- // Execute non-localized "Common StartUp" group if exists.
- //
- pidlStartup = SHCloneSpecialIDList(NULL, CSIDL_COMMON_ALTSTARTUP, FALSE);
- if (pidlStartup)
- {
- EnumFolder(hwndOwner, pidlStartup, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, EnumFolder_Startup);
- ILFree(pidlStartup);
- }
- pidlStartup = SHCloneSpecialIDList(NULL, CSIDL_STARTUP, TRUE);
- if (pidlStartup)
- {
- EnumFolder(hwndOwner, pidlStartup, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, EnumFolder_Startup);
- ILFree(pidlStartup);
- }
- //
- // Execute non-localized "StartUp" group if exists.
- //
- pidlStartup = SHCloneSpecialIDList(NULL, CSIDL_ALTSTARTUP, FALSE);
- if (pidlStartup)
- {
- EnumFolder(hwndOwner, pidlStartup, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, EnumFolder_Startup);
- ILFree(pidlStartup);
- }
- }
- // BUGBUG:: A bunch of this code can get reduced down... ie boiled
- const LPTSTR c_aszForceCheckWinIni[] = {TEXT("GROUPS.B$$"), NULL};
- void CheckWinIniForAssocs(void);
- void BoilThatDustSpec(LPTSTR pStart, int nCmdShow)
- {
- BOOL bFinished;
- bFinished = FALSE;
- while (!bFinished && !AbortStartup())
- {
- SHELLEXECUTEINFO ei;
- LPTSTR pEnd;
- pEnd = pStart;
- while ((*pEnd) && (*pEnd != TEXT(' ')) && (*pEnd != TEXT(',')))
- pEnd = (LPTSTR)OFFSETOF(CharNext(pEnd));
- if (*pEnd == 0)
- bFinished = TRUE;
- else
- *pEnd = 0;
- if (lstrlen(pStart) != 0)
- {
- LPTSTR pszFile;
- TCHAR szFile[MAX_PATH];
- const LPTSTR *ppszForce;
- // Load and Run lines are done relative to windows directory.
- GetWindowsDirectory(szFile, ARRAYSIZE(szFile));
- SetCurrentDirectory(szFile);
- pszFile = PathFindFileName(pStart);
- lstrcpy(szFile, pszFile);
- PathRemoveFileSpec(pStart);
- // App hacks to get borlands Setup program to work
- for (ppszForce = c_aszForceCheckWinIni; *ppszForce; ppszForce++)
- {
- if (lstrcmpi(szFile, *ppszForce) == 0)
- {
- DebugMsg(DM_TRACE, TEXT("c.boil: Apphack %s force winini scan"), szFile);
- CheckWinIniForAssocs();
- break;
- }
- }
- ei.cbSize = sizeof(SHELLEXECUTEINFO);
- ei.hwnd = NULL;
- ei.lpVerb = NULL;
- ei.lpFile = szFile;
- ei.lpParameters = NULL;
- ei.lpDirectory = pStart;
- ei.nShow = nCmdShow;
- ei.fMask = 0;
- if (!ShellExecuteEx(&ei))
- {
- ShellMessageBox(hinstCabinet, NULL, MAKEINTRESOURCE(IDS_WINININORUN),
- MAKEINTRESOURCE(IDS_DESKTOP),
- MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL,
- (LPTSTR)szFile);
- }
- }
- pStart = pEnd+1;
- }
- }
- void _DoRunEquals()
- {
- TCHAR szBuffer[255]; // max size of load= run= lines...
- if (g_fCleanBoot)
- return;
- /* "Load" apps before "Run"ning any. */
- GetProfileString(TEXT("windows"), TEXT("Load"), TEXT(""), szBuffer, ARRAYSIZE(szBuffer));
- if (*szBuffer)
- BoilThatDustSpec(szBuffer, SW_SHOWMINNOACTIVE);
- GetProfileString(TEXT("windows"), TEXT("Run"), TEXT(""), szBuffer, ARRAYSIZE(szBuffer));
- if (*szBuffer)
- BoilThatDustSpec(szBuffer, SW_SHOWNORMAL);
- }
- //---------------------------------------------------------------------------
- // Use IERnonce.dll to process RunOnceEx key
- //
- typedef void (WINAPI *RUNONCEEXPROCESS)(HWND, HINSTANCE, LPSTR, int);
- void ProcessRunOnceEx()
- {
- HKEY hkey;
- if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCEEX,
- 0, KEY_QUERY_VALUE, &hkey))
- {
- DWORD dwNumSubKeys = 0;
- RegQueryInfoKey(hkey, NULL, NULL, NULL, &dwNumSubKeys, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL);
- RegCloseKey(hkey);
- if (dwNumSubKeys)
- {
- HANDLE hLib;
- TCHAR szPath[MAX_PATH];
- GetSystemDirectory(szPath, ARRAYSIZE(szPath));
- PathAppend(szPath, TEXT("iernonce.dll"));
- hLib = LoadLibrary(szPath);
- if (hLib)
- {
- RUNONCEEXPROCESS pfnRunOnceExProcess;
- #ifdef WINNT // Hydra-Specific
- BOOL hydraInAppInstallMode = FALSE;
- // See if we are on NT5, and if the terminal-services is enabled
- if (g_fRuningOnTerminalServer)
- {
- hydraInAppInstallMode = SetTermsrvAppInstallMode(TRUE);
- }
- #endif // WINNT
- pfnRunOnceExProcess = (RUNONCEEXPROCESS)GetProcAddress(hLib, "RunOnceExProcess");
- if (pfnRunOnceExProcess)
- {
- // the four param in the function is due to the function cab be called
- // from RunDLL which will path in those params. But RunOnceExProcess ignore all
- // of them. Therefore, I don't pass any meaningful thing here.
- //
- pfnRunOnceExProcess(NULL, NULL, NULL, 0);
- }
- FreeLibrary(hLib);
- #ifdef WINNT // Hydra-Specific
- if (hydraInAppInstallMode)
- {
- SetTermsrvAppInstallMode(FALSE) ;
- }
- #endif // WINNT
- }
- }
- }
- }
- #define REGTIPS REGSTR_PATH_EXPLORER TEXT("\Tips")
- #define SZ_REGKEY_RUNSRVWIZ TEXT("SOFTWARE\Microsoft\Windows NT\CurrentVersion\Setup\Welcome")
- // BUGBUG: This can be removed as soon as the policy editor and setup are updated to
- // place welcome under one of the prioritized HKCURun subkeys.
- UINT _RunWelcome()
- {
- HKEY hkey;
- BOOL fShow = FALSE;
- UINT uPeek = PEEK_NORMAL;
- if (RegOpenKey(HKEY_CURRENT_USER, REGTIPS, &hkey) == ERROR_SUCCESS)
- {
- DWORD cbData = SIZEOF(fShow);
- RegQueryValueEx(hkey, TEXT("Show"), NULL, NULL, (LPBYTE)&fShow, &cbData);
- RegCloseKey(hkey);
- }
- if (fShow)
- {
- DWORD dwType;
- DWORD dwData;
- DWORD cbSize = sizeof(dwData);
- TCHAR szCmdLine[MAX_PATH * 2];
- PROCESS_INFORMATION pi;
- STARTUPINFO startup = {0};;
- startup.cb = SIZEOF(startup);
- startup.wShowWindow = SW_SHOWNORMAL;
- if ( IsOS(OS_WIN2000PRO) || IsOS(OS_WINDOWS) )
- {
- // Only run welcome.exe if we are on Professional (or win9x)
- GetWindowsDirectory(szCmdLine, ARRAYSIZE(szCmdLine));
- PathAppend(szCmdLine, TEXT("Welcome.exe"));
- }
- else if ( (IsOS(OS_WIN2000SERVER) || IsOS(OS_WIN2000ADVSERVER)) &&
- IsUserAnAdmin() &&
- ((ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_RUNSRVWIZ, TEXT("SrvWiz"), &dwType, (LPBYTE)&dwData, &cbSize)) || (dwData != 0)))
- {
- // launch Configure Your Server for system administrators on Win2000 Server and Advanced Server
- GetSystemDirectory(szCmdLine, ARRAYSIZE(szCmdLine));
- PathAppend(szCmdLine, TEXT("mshta.exe res://srvwiz.dll/default.hta"));
- }
- else
- {
- // If neither or the above are true don't try to run anything.
- return 0;
- }
- if (CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &pi))
- {
- WaitForSingleObject(pi.hProcess, INFINITE);
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
- }
- }
- return uPeek;
- }
- #ifdef WINNT
- // On NT, run the TASKMAN= line from the registry
- void _AutoRunTaskMan(void)
- {
- HKEY hkeyWinLogon;
- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"),
- 0, KEY_READ, &hkeyWinLogon) == ERROR_SUCCESS)
- {
- TCHAR szBuffer[MAX_PATH];
- DWORD cbBuffer = SIZEOF(szBuffer);
- if (RegQueryValueEx(hkeyWinLogon, TEXT("Taskman"), 0, NULL, (LPBYTE)szBuffer, &cbBuffer) == ERROR_SUCCESS)
- {
- if (szBuffer[0])
- {
- PROCESS_INFORMATION pi;
- STARTUPINFO startup = {0};
- startup.cb = SIZEOF(startup);
- startup.wShowWindow = SW_SHOWNORMAL;
- if (CreateProcess(NULL, szBuffer, NULL, NULL, FALSE, 0,
- NULL, NULL, &startup, &pi))
- {
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
- }
- }
- }
- RegCloseKey(hkeyWinLogon);
- }
- }
- #else
- #define _AutoRunTaskMan() // nothing on Win95
- #endif
- #ifdef DEBUG
- //---------------------------------------------------------------------------
- // Copy the exception info so we can get debug info for Raised exceptions
- // which don't go through the debugger.
- void _CopyExceptionInfo(LPEXCEPTION_POINTERS pep)
- {
- PEXCEPTION_RECORD per;
- per = pep->ExceptionRecord;
- DebugMsg(DM_ERROR, TEXT("Exception %x at %#08x."), per->ExceptionCode, per->ExceptionAddress);
- if (per->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
- {
- // If the first param is 1 then this was a write.
- // If the first param is 0 then this was a read.
- if (per->ExceptionInformation[0])
- {
- DebugMsg(DM_ERROR, TEXT("Invalid write to %#08x."), per->ExceptionInformation[1]);
- }
- else
- {
- DebugMsg(DM_ERROR, TEXT("Invalid read of %#08x."), per->ExceptionInformation[1]);
- }
- }
- }
- #else
- #define _CopyExceptionInfo(x) TRUE
- #endif
- // try to create this by sending a wm_command directly to
- // the desktop.
- BOOL MyCreateFromDesktop(HINSTANCE hInst, LPCTSTR pszCmdLine, int nCmdShow)
- {
- NEWFOLDERINFO fi = {0};
- BOOL bRet = FALSE;
- fi.nShow = nCmdShow;
- // since we have browseui fill out the fi,
- // SHExplorerParseCmdLine() does a GetCommandLine()
- if (SHExplorerParseCmdLine(&fi))
- bRet = SHCreateFromDesktop(&fi);
- // should we also have it cleanup after itself??
- // SHExplorerParseCmdLine() can allocate this buffer...
- if (fi.uFlags & COF_PARSEPATH)
- LocalFree(fi.pszPath);
- ILFree(fi.pidl);
- ILFree(fi.pidlRoot);
- return bRet;
- }
- BOOL g_fDragFullWindows=FALSE;
- int g_cxEdge=0;
- int g_cyEdge=0;
- int g_cySize=0;
- int g_cxTabSpace=0;
- int g_cyTabSpace=0;
- int g_cxBorder=0;
- int g_cyBorder=0;
- int g_cxPrimaryDisplay=0;
- int g_cyPrimaryDisplay=0;
- int g_cxDlgFrame=0;
- int g_cyDlgFrame=0;
- int g_cxFrame=0;
- int g_cyFrame=0;
- int g_cxMinimized=0;
- int g_fCleanBoot=0;
- int g_cxVScroll=0;
- int g_cyHScroll=0;
- void Cabinet_InitGlobalMetrics(WPARAM wParam, LPTSTR lpszSection)
- {
- BOOL fForce = (!lpszSection || !*lpszSection);
- if (fForce || wParam == SPI_SETDRAGFULLWINDOWS) {
- SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &g_fDragFullWindows, 0);
- }
- if (fForce || !lstrcmpi(lpszSection, TEXT("WindowMetrics")) ||
- wParam == SPI_SETNONCLIENTMETRICS) {
- // REVIEW, before it's all over, make sure all these vars are used somewhere.
- g_cxEdge = GetSystemMetrics(SM_CXEDGE);
- g_cyEdge = GetSystemMetrics(SM_CYEDGE);
- #ifdef NASHFLAT_TASKBAR
- g_cxTabSpace = (g_cxEdge * 5);
- #else
- g_cxTabSpace = (g_cxEdge * 3) / 2;
- #endif
- g_cyTabSpace = (g_cyEdge * 3) / 2; // cause the graphic designers really really want 3.
- g_cySize = GetSystemMetrics(SM_CYSIZE);
- g_cxBorder = GetSystemMetrics(SM_CXBORDER);
- g_cyBorder = GetSystemMetrics(SM_CYBORDER);
- g_cxVScroll = GetSystemMetrics(SM_CXVSCROLL);
- g_cyHScroll = GetSystemMetrics(SM_CYHSCROLL);
- g_cxDlgFrame = GetSystemMetrics(SM_CXDLGFRAME);
- g_cyDlgFrame = GetSystemMetrics(SM_CYDLGFRAME);
- g_cxFrame = GetSystemMetrics(SM_CXFRAME);
- g_cyFrame = GetSystemMetrics(SM_CYFRAME);
- g_cxMinimized = GetSystemMetrics(SM_CXMINIMIZED);
- g_cxPrimaryDisplay = GetSystemMetrics(SM_CXSCREEN);
- g_cyPrimaryDisplay = GetSystemMetrics(SM_CYSCREEN);
- }
- }
- //---------------------------------------------------------------------------
- void _CreateAppGlobals()
- {
- Cabinet_InitGlobalMetrics(0, NULL);
- #ifdef WINNT
- g_bRunOnNT5 = BOOLIFY(IsOS(OS_NT5));
- #else
- g_bRunOnMemphis = BOOLIFY(IsOS(OS_MEMPHIS));
- #endif
- //
- // Check if the mirroring APIs exist on the current
- // platform.
- //
- g_bMirroredOS = IS_MIRRORING_ENABLED();
- // make sure we got our #defines right...
- ASSERT(BOOLIFY(g_bRunOnNT) == BOOLIFY(IsOS(OS_NT)));
- ASSERT(BOOLIFY(g_bRunOnNT5) == BOOLIFY(IsOS(OS_NT5)));
- ASSERT(BOOLIFY(g_bRunOnMemphis) == BOOLIFY(IsOS(OS_MEMPHIS)));
- }
- //
- // This function checks if any of the shell windows is already created by
- // another instance of explorer and returns TRUE if so.
- //
- BOOL IsAnyShellWindowAlreadyPresent()
- {
- return GetShellWindow() || FindWindow(TEXT("Proxy Desktop"), NULL);
- }
- // See if the Shell= line indicates that we are the shell
- BOOL ExplorerIsShell()
- {
- TCHAR *pszPathName, szPath[MAX_PATH];
- TCHAR *pszModuleName, szModulePath[MAX_PATH];
- ASSERT(!IsAnyShellWindowAlreadyPresent());
- GetModuleFileName(NULL, szModulePath, ARRAYSIZE(szModulePath));
- pszModuleName = PathFindFileName(szModulePath);
- GetPrivateProfileString(TEXT("boot"), TEXT("shell"), pszModuleName, szPath, ARRAYSIZE(szPath), TEXT("system.ini"));
- PathRemoveArgs(szPath);
- PathRemoveBlanks(szPath);
- pszPathName = PathFindFileName(szPath);
- // NB Special case shell=install.exe - assume we are the shell.
- // Symantec un-installers temporarily set shell=installer.exe so
- // we think we're not the shell when we are. They fail to clean up
- // a bunch of links if we don't do this.
- return StrCmpNI(pszPathName, pszModuleName, lstrlen(pszModuleName)) == 0 ||
- lstrcmpi(pszPathName, TEXT("install.exe")) == 0;
- }
- // Returns TRUE of this is the first time the explorer is run
- BOOL ShouldStartDesktopAndTray()
- {
- // We need to be careful on which window we look for. If we look for
- // our desktop window class and Progman is running we will find the
- // progman window. So Instead we should ask user for the shell window.
- // We can not depend on any values being set here as this is the
- // start of a new process. This wont be called when we start new
- // threads.
- return !IsAnyShellWindowAlreadyPresent() && ExplorerIsShell();
- }
- void DisplayCleanBootMsg()
- {
- TCHAR szMsg[1024];
- TCHAR szTitle[80];
- int ids;
- int cb;
- LPTSTR pszMsg = szMsg;
- szMsg[0] = TEXT('');
- for (ids=IDS_CLEANBOOTMSG1; ids <= IDS_CLEANBOOTMSG4 ; ids++)
- {
- cb = LoadString(hinstCabinet, ids, pszMsg,
- ARRAYSIZE(szMsg) - (int)(pszMsg - szMsg));
- if (cb == 0)
- break;
- pszMsg += cb;
- }
- // Make sure it is NULL terminated
- *pszMsg = TEXT('');
- LoadString(hinstCabinet, IDS_DESKTOP, szTitle, ARRAYSIZE(szTitle));
- // Now display the message.
- MessageBox(NULL, szMsg, szTitle,
- MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
- }
- //---------------------------------------------------------------------------
- const CHAR c_szTimeChangedRunDLL[] = "rundll32 shell32.dll,Control_RunDLL timedate.cpl,,/m";
- void DoDaylightCheck(BOOL fStartupInit)
- {
- DWORD changed;
- DebugMsg(DM_TRACE, TEXT("c.ddc(%d): calling k32.rdi"), fStartupInit);
- #ifdef WINNT
- changed = FALSE;
- #else
- // Win95 base does not automatically handle timezone cutover
- // we have poke it every so often...
- changed = RefreshDaylightInformation(TRUE);
- #endif
- if (changed > 0)
- {
- DebugMsg(DM_TRACE, TEXT("c.ddc(%d): rdi changed - %lu"), fStartupInit, changed);
- // something actually changed, tell everbody
- if (!fStartupInit)
- {
- SendMessage((HWND)-1, WM_TIMECHANGE, 0, 0);
- // if the local time changed tell the user
- if (changed > 1)
- WinExec(c_szTimeChangedRunDLL, SW_SHOWNORMAL);
- }
- else
- {
- // there should only be "server" processes around anyway
- PostMessage((HWND)-1, WM_TIMECHANGE, 0, 0);
- // if the local time changed queue a runonce to tell the user
- if (changed > 1)
- {
- HKEY runonce;
- if (RegCreateKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, &runonce) ==
- ERROR_SUCCESS)
- {
- RegSetValueEx(runonce, TEXT("WarnTimeChanged"), 0, REG_SZ,
- (LPBYTE)c_szTimeChangedRunDLL, SIZEOF(c_szTimeChangedRunDLL));
- RegCloseKey(runonce);
- }
- }
- }
- }
- }
- BOOL IsExecCmd(LPCTSTR pszCmd)
- {
- return *pszCmd && !StrStrI(pszCmd, TEXT("-embedding"));
- }
- // run the cmd line passed up from win.com
- void _RunWinComCmdLine(LPCTSTR pszCmdLine, UINT nCmdShow)
- {
- if (IsExecCmd(pszCmdLine))
- {
- SHELLEXECUTEINFO ei = { SIZEOF(ei), 0, NULL, NULL, pszCmdLine, NULL, NULL, nCmdShow};
- ei.lpParameters = PathGetArgs(pszCmdLine);
- if (*ei.lpParameters)
- *((LPTSTR)ei.lpParameters - 1) = 0; // const -> non const
- ShellExecuteEx(&ei);
- }
- }
- // stolen from the CRT, used to shirink our code
- #ifdef DEBUG // For leak detection
- BOOL g_fInitTable = FALSE;
- LEAKDETECTFUNCS LeakDetFunctionTable;
- #endif
- // ccover uses runtime libs, that in turn require main()
- #ifdef CCOVER
- STDAPI_(int) ModuleEntry(void);
- void __cdecl main() {
- ModuleEntry();
- };
- #endif
- STDAPI_(int) ModuleEntry(void)
- {
- int i;
- STARTUPINFOA si;
- LPTSTR pszCmdLine;
- #ifdef DEBUG
- // leak detection
- if(!g_fInitTable)
- {
- if(GetLeakDetectionFunctionTable(&LeakDetFunctionTable))
- g_fInitTable = TRUE;
- }
- if(g_fInitTable)
- LeakDetFunctionTable.pfnDebugMemLeak(DML_TYPE_THREAD | DML_BEGIN, TEXT(__FILE__), __LINE__);
- #endif
- #ifdef WINNT
- // Hydra-Specific
- g_fRuningOnTerminalServer = IsTerminalServicesEnabled();
- #endif
- pszCmdLine = GetCommandLine();
- //
- // 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 = ExplorerWinMain(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.
- #ifdef DEBUG
- // we stop leak detection on main shell thread here
- // we need to change this
- if (g_fInitTable)
- LeakDetFunctionTable.pfnDebugMemLeak(DML_TYPE_THREAD | DML_END, TEXT(__FILE__), __LINE__);
- #endif
- if (g_fExitExplorer) // desktop told us not to exit
- {
- TraceMsg(DM_SHUTDOWN, "c.me: call ExitProcess");
- #ifdef CCOVER
- cov_write();
- #endif
- ExitProcess(i);
- }
- DebugMsg(DM_TRACE, TEXT("c.me: Cabinet main thread exiting without ExitProcess."));
- return i;
- }
- void _InitComctl32()
- {
- INITCOMMONCONTROLSEX icce;
- // init the controls
- icce.dwICC = ICC_COOL_CLASSES | ICC_WIN95_CLASSES | ICC_PAGESCROLLER_CLASS;
- icce.dwSize = sizeof(icce);
- InitCommonControlsEx(&icce);
- }
- // cached "handle" to the desktop
- HANDLE g_hDesktop = NULL;
- extern IDeskTray* const c_pdtray;
- BOOL CreateDesktopAndTray()
- {
- BOOL fRet = TRUE;
- if (g_dwProfileCAP & 0x00008000)
- StartCAPAll();
- if (!v_hwndTray)
- {
- InitTrayClass(hinstCabinet);
- if (!InitTray(hinstCabinet))
- return FALSE;
- }
- ASSERT(v_hwndTray);
- if (!v_hwndDesktop)
- {
- ASSERT(!g_hDesktop);
- // cache the handle to the desktop...
- g_hDesktop = SHCreateDesktop(c_pdtray);
- if (g_hDesktop == NULL)
- fRet = FALSE;
- }
- if (g_dwProfileCAP & 0x80000000)
- StopCAPAll();
- return fRet;
- }
- //
- // The "Session key" is a volatile registry key unique to this session.
- // A session is a single continuous logon. If Explorer crashes and is
- // auto-restarted, the two Explorers share the same session. But if you
- // log off and back on, that new Explorer is a new session.
- //
- // Note that Win9x doesn't support volatile registry keys, so we have to
- // fake it. IsFirstInstanceAfterLogon() answers the question *and*
- // initializes the session key.
- //
- //
- // The s_SessionKeyName is the name of the session key relative to
- // REGSTR_PATH_EXPLORERSessionInfo. On NT, this is normally the
- // Authentication ID, but we pre-initialize it to something safe so
- // we don't fault if for some reason we can't get to it. Since
- // Win95 supports only one session at a time, it just stays at the
- // default value.
- //
- // Sometimes we want to talk about the full path (SessionInfoBlahBlah)
- // and sometimes just the partial path (BlahBlah) so we wrap it inside
- // this goofy structure.
- //
- union SESSIONKEYNAME {
- TCHAR szPath[12+16+1];
- struct {
- TCHAR szSessionInfo[12]; // strlen("SessionInfo\")
- TCHAR szName[16+1]; // 16 = two DWORDs converted to hex
- };
- } s_SessionKeyName = {
- { TEXT("SessionInfo\.Default") }
- };
- HKEY GetSessionKey(REGSAM samDesired)
- {
- HKEY hkExp;
- HKEY hkSession = NULL;
- DWORD dwDisposition;
- LONG lRes;
- //
- // Must create this key in multiple steps, because we want
- // SessionInfo to be volatile, but REGSTR_PATH_EXPLORER to be
- // nonvolatile.
- //
- lRes = RegCreateKeyEx(HKEY_CURRENT_USER,
- REGSTR_PATH_EXPLORER, 0,
- NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED,
- NULL, &hkExp, &dwDisposition);
- if (lRes == ERROR_SUCCESS)
- {
- lRes = RegCreateKeyEx(hkExp, s_SessionKeyName.szPath, 0,
- NULL,
- REG_OPTION_VOLATILE,
- samDesired,
- NULL,
- &hkSession,
- &dwDisposition );
- RegCloseKey(hkExp);
- }
- return hkSession;
- }
- // Removes the session key from the registry.
- void NukeSessionKey(void)
- {
- HKEY hkExp;
- LONG lRes;
- lRes = RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, &hkExp);
- if (lRes == ERROR_SUCCESS)
- {
- SHDeleteKey(hkExp, s_SessionKeyName.szPath);
- RegCloseKey(hkExp);
- }
- }
- BOOL IsFirstInstanceAfterLogon()
- {
- BOOL fResult = FALSE;
- #ifdef WINNT
- LONG lRes;
- HANDLE hToken;
- //
- // Build the name of the session key. We use the authentication ID
- // which is guaranteed to be unique forever. We can't use the
- // Hydra session ID since that can be recycled.
- //
- if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
- {
- TOKEN_STATISTICS stats;
- DWORD cbOut;
- if (GetTokenInformation(hToken, TokenStatistics, &stats, sizeof(stats), &cbOut))
- {
- HKEY hkSession;
- wsprintf(s_SessionKeyName.szName, TEXT("%08x%08x"),
- stats.AuthenticationId.HighPart,
- stats.AuthenticationId.LowPart);
- hkSession = GetSessionKey(KEY_WRITE);
- if (hkSession) {
- HKEY hkStartup;
- DWORD dwDisposition;
- lRes = RegCreateKeyEx(hkSession, TEXT("StartupHasBeenRun"), 0,
- NULL,
- REG_OPTION_VOLATILE,
- KEY_WRITE,
- NULL,
- &hkStartup,
- &dwDisposition );
- if (lRes == ERROR_SUCCESS)
- {
- RegCloseKey(hkStartup);
- if (dwDisposition == REG_CREATED_NEW_KEY)
- fResult = TRUE;
- }
- RegCloseKey(hkSession);
- }
- }
- CloseHandle(hToken);
- }
- #else
- // on win95, we use the overloaded RegisterShellHook to thunk to the 16 bit side to do
- // the work for us. this gets fixed when the tray shuts down properly...
- fResult = RegisterShellHook(NULL,(BOOL) 4 );
- if (fResult) {
- // Clean out the "volatile" session info since Win9x doesn't support
- // volatile regkeys.
- NukeSessionKey();
- }
- #endif
- return fResult;
- }
- //
- // dwValue is FALSE if this is startup, TRUE if this is shutdown,
- //
- void WriteCleanShutdown(DWORD dwValue)
- {
- RegSetValueEx(g_hkeyExplorer, TEXT("CleanShutdown"), 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(dwValue));
- // If we are shutting down for real (i.e., not fake), then clean up the
- // session key so we don't leak a bazillion volatile keys into the
- // registry on a Hydra system when people log on and off and on and off...
- if (dwValue && !g_fFakeShutdown) {
- NukeSessionKey();
- }
- }
- BOOL ReadCleanShutdown()
- {
- DWORD dwValue = 1; // default: it was clean
- DWORD dwSize = sizeof(dwValue);
- RegQueryValueEx(g_hkeyExplorer, TEXT("CleanShutdown"), NULL, NULL, (LPBYTE)&dwValue, &dwSize);
- return (BOOL)dwValue;
- }
- // APP HACK APP HACK
- // installing SP3 over ie4 on NT4 trashes the RSA key.
- // same code is in mainloop.c of iexplore.exe
- #ifdef WINNT
- #define RSA_PATH_TO_KEY TEXT("Software\Microsoft\Cryptography\Defaults\Provider\Microsoft Base Cryptographic Provider v1.0")
- #define CSD_REG_PATH TEXT("System\CurrentControlSet\Control\Windows")
- #define CSD_REG_VALUE TEXT("CSDVersion")
- // the signatures we are looking for in the regsitry so that we can patch up
- #ifdef _M_IX86
- static BYTE SP3Sig[] = {0xbd, 0x9f, 0x13, 0xc5, 0x92, 0x12, 0x2b, 0x72,
- 0x4a, 0xba, 0xb6, 0x2a, 0xf9, 0xfc, 0x54, 0x46,
- 0x6f, 0xa1, 0xb4, 0xbb, 0x43, 0xa8, 0xfe, 0xf8,
- 0xa8, 0x23, 0x7d, 0xd1, 0x85, 0x84, 0x22, 0x6e,
- 0xb4, 0x58, 0x00, 0x3e, 0x0b, 0x19, 0x83, 0x88,
- 0x6a, 0x8d, 0x64, 0x02, 0xdf, 0x5f, 0x65, 0x7e,
- 0x3b, 0x4d, 0xd4, 0x10, 0x44, 0xb9, 0x46, 0x34,
- 0xf3, 0x40, 0xf4, 0xbc, 0x9f, 0x4b, 0x82, 0x1e,
- 0xcc, 0xa7, 0xd0, 0x2d, 0x22, 0xd7, 0xb1, 0xf0,
- 0x2e, 0xcd, 0x0e, 0x21, 0x52, 0xbc, 0x3e, 0x81,
- 0xb1, 0x1a, 0x86, 0x52, 0x4d, 0x3f, 0xfb, 0xa2,
- 0x9d, 0xae, 0xc6, 0x3d, 0xaa, 0x13, 0x4d, 0x18,
- 0x7c, 0xd2, 0x28, 0xce, 0x72, 0xb1, 0x26, 0x3f,
- 0xba, 0xf8, 0xa6, 0x4b, 0x01, 0xb9, 0xa4, 0x5c,
- 0x43, 0x68, 0xd3, 0x46, 0x81, 0x00, 0x7f, 0x6a,
- 0xd7, 0xd1, 0x69, 0x51, 0x47, 0x25, 0x14, 0x40,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- #else // other than _M_IX86
- static BYTE SP3Sig[] = {0x8a, 0x06, 0x01, 0x6d, 0xc2, 0xb5, 0xa2, 0x66,
- 0x12, 0x1b, 0x9c, 0xe4, 0x58, 0xb1, 0xf8, 0x7d,
- 0xad, 0x17, 0xc1, 0xf9, 0x3f, 0x87, 0xe3, 0x9c,
- 0xdd, 0xeb, 0xcc, 0xa8, 0x6b, 0x62, 0xd0, 0x72,
- 0xe7, 0xf2, 0xec, 0xd6, 0xd6, 0x36, 0xab, 0x2d,
- 0x28, 0xea, 0x74, 0x07, 0x0e, 0x6c, 0x6d, 0xe1,
- 0xf8, 0x17, 0x97, 0x13, 0x8d, 0xb1, 0x8b, 0x0b,
- 0x33, 0x97, 0xc5, 0x46, 0x66, 0x96, 0xb4, 0xf7,
- 0x03, 0xc5, 0x03, 0x98, 0xf7, 0x91, 0xae, 0x9d,
- 0x00, 0x1a, 0xc6, 0x86, 0x30, 0x5c, 0xc8, 0xc7,
- 0x05, 0x47, 0xed, 0x2d, 0xc2, 0x0b, 0x61, 0x4b,
- 0xce, 0xe5, 0xb7, 0xd7, 0x27, 0x0c, 0x9e, 0x2f,
- 0xc5, 0x25, 0xe3, 0x81, 0x13, 0x9d, 0xa2, 0x67,
- 0xb2, 0x26, 0xfc, 0x99, 0x9d, 0xce, 0x0e, 0xaf,
- 0x30, 0xf3, 0x30, 0xec, 0xa3, 0x0a, 0xfe, 0x16,
- 0xb6, 0xda, 0x16, 0x90, 0x9a, 0x9a, 0x74, 0x7a,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- #endif // _M_IX86
- void CheckForSP3RSAOverwrite( void )
- {
- // check for them having installed NTSP3 over the top of IE4, it nukes
- // the RSABASE reg stuff, so we have to re-do it. (our default platform is NT + SP3, but this
- // problem doesn't occur on NT5, so ignore it.
- OSVERSIONINFO osVer;
- ZeroMemory(&osVer, sizeof(osVer));
- osVer.dwOSVersionInfoSize = sizeof(osVer);
- if( GetVersionEx((OSVERSIONINFO *)&osVer) && (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
- && (osVer.dwMajorVersion == 4))
- {
- // now check to see we are on SP3 ...
- DWORD dwValue = 0;
- DWORD dwSize = sizeof( dwValue );
- if ( ERROR_SUCCESS == SHGetValue( HKEY_LOCAL_MACHINE, CSD_REG_PATH, CSD_REG_VALUE, NULL,
- &dwValue, &dwSize) && LOWORD( dwValue ) == 0x300 )
- {
- BYTE rgbSig[136];
- dwSize = sizeof(rgbSig);
- if (ERROR_SUCCESS == SHGetValue ( HKEY_LOCAL_MACHINE, RSA_PATH_TO_KEY, TEXT("Signature"), NULL,
- rgbSig, &dwSize))
- {
- if ((dwSize == sizeof(SP3Sig)) &&
- (0 == memcmp(SP3Sig, rgbSig, sizeof(SP3Sig))))
- {
- // need to do a DLLRegisterServer on RSABase
- HINSTANCE hInst = LoadLibrary(TEXT("rsabase.dll"));
- if ( hInst )
- {
- FARPROC pfnDllReg = GetProcAddress( hInst, "DllRegisterServer");
- if ( pfnDllReg )
- {
- __try
- {
- pfnDllReg();
- }
- __except( EXCEPTION_EXECUTE_HANDLER)
- {
- }
- }
- FreeLibrary( hInst );
- }
- }
- }
- }
- }
- }
- #else
- #define CheckForSP3RSAOverwrite()
- #endif
- #ifdef WINNT
- //
- // Synopsis: Waits for the OLE SCM process to finish its initialization.
- // This is called before the first call to OleInitialize since
- // the SHELL runs early in the boot process.
- //
- // Arguments: None.
- //
- // Returns: S_OK - SCM is running. OK to call OleInitialize.
- // CO_E_INIT_SCM_EXEC_FAILURE - timed out waiting for SCM
- // other - create event failed
- //
- // History: 26-Oct-95 Rickhi Extracted from CheckAndStartSCM so
- // that only the SHELL need call it.
- //
- HRESULT WaitForSCMToInitialize()
- {
- static BOOL s_fScmStarted = FALSE;
- HANDLE hEvent;
- SECURITY_ATTRIBUTES sa;
- SECURITY_DESCRIPTOR sd;
- SECURITY_ATTRIBUTES *psa;
- if (s_fScmStarted)
- return S_OK;
- psa = CreateAllAccessSecurityAttributes(&sa, &sd);
- if (g_bRunOnNT5)
- {
- // on NT5 we need a global event that is shared between hydra sessions
- hEvent = CreateEvent(psa, TRUE, FALSE, SZ_SCMCREATEDEVENT_NT5);
- }
- else
- {
- hEvent = CreateEvent(psa, TRUE, FALSE, SZ_SCMCREATEDEVENT);
- }
- if (hEvent)
- {
- // wait for the SCM to signal the event, then close the handle
- // and return a code based on the WaitEvent result.
- int rc = WaitForSingleObject(hEvent, 60000);
- CloseHandle(hEvent);
- if (rc == WAIT_OBJECT_0)
- {
- s_fScmStarted = TRUE;
- return S_OK;
- }
- else if (rc == WAIT_TIMEOUT)
- {
- return CO_E_INIT_SCM_EXEC_FAILURE;
- }
- }
- return HRESULT_FROM_WIN32(GetLastError()); // event creation failed or WFSO failed.
- }
- #endif // WINNT
- // OleInitialize()
- STDAPI OleInitializeWaitForSCM()
- {
- #ifdef WINNT
- HRESULT hres = WaitForSCMToInitialize();
- if (FAILED(hres))
- return hres;
- #endif
- return OleInitialize(NULL);
- }
- // we need to figure out the fFirstShellBoot on a per-user
- // basis rather than once per machine. We want the welcome
- // splash screen to come up for every new user.
- BOOL IsFirstShellBoot()
- {
- DWORD dwDisp;
- HKEY hkey;
- BOOL fFirstShellBoot = TRUE; // default value
- if (RegCreateKeyEx(HKEY_CURRENT_USER, REGTIPS, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
- NULL, &hkey, &dwDisp) == ERROR_SUCCESS)
- {
- DWORD dwSize = sizeof(fFirstShellBoot);
- RegQueryValueEx(hkey, TEXT("DisplayInitialTipWindow"), NULL, NULL, (LPBYTE)&fFirstShellBoot, &dwSize);
- if (fFirstShellBoot)
- {
- // Turn off the initial tip window for future shell starts.
- BOOL bTemp = FALSE;
- RegSetValueEx(hkey, TEXT("DisplayInitialTipWindow"), 0, REG_DWORD, (LPBYTE) &bTemp, sizeof(bTemp));
- }
- RegCloseKey(hkey);
- }
- return fFirstShellBoot;
- }
- //
- // Post a message to the MTTF window if it is present
- // The MTTF tool tracks this process being up
- //
- #define STR_MTTF_WINDOW_CLASS TEXT("HARVEYCAT")
- #define MTTF_STARTUP 40006
- #define MTTF_SHUTDOWN 40007
- void PostMTTFMessage(WPARAM mttfMsg)
- {
- HWND hwndVerFind = FindWindow(STR_MTTF_WINDOW_CLASS, NULL);
- if (hwndVerFind)
- {
- PostMessage(hwndVerFind, WM_COMMAND,
- (WPARAM) mttfMsg,
- (LPARAM) GetCurrentProcessId());
- }
- }
- int ExplorerWinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPTSTR pszCmdLine, int nCmdShow)
- {
- DWORD dwShellStartTime; // used for perf times
- CcshellGetDebugFlags();
- if (g_dwProfileCAP & 0x00000001)
- StartCAP();
- hinstCabinet = hInstance;
- g_fCleanBoot = GetSystemMetrics(SM_CLEANBOOT); // also known as "Safe Mode"
- // Run IEAK via Wininet initialization if the autoconfig url is present.
- // No need to unload wininet in this case. Also only do this first time
- // Explorer loads (GetShellWindow() returns NULL).
- if (!GetShellWindow() && !g_fCleanBoot && SHRegGetUSValue(TEXT("Software\Microsoft\Windows\Internet Settings"),
- TEXT("AutoConfigURL"),
- NULL, NULL, NULL, FALSE, NULL, 0) == ERROR_SUCCESS)
- {
- LoadLibrary(TEXT("WININET.DLL"));
- }
- // Very Important: Make sure to init dde prior to any Get/Peek/Wait().
- InitializeCriticalSection(&g_csDll);
- _InitComctl32();
- if (g_dwPrototype & 0x80000000)
- {
- // Turn off GDI batching so that paints are performed immediately
- GdiSetBatchLimit(1);
- }
- RegCreateKey(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, &g_hkeyExplorer);
- ASSERT(g_hkeyExplorer); // Really really bad.. unable to create reg explorer key
- if (!ShouldStartDesktopAndTray())
- {
- MyCreateFromDesktop(hInstance, pszCmdLine, nCmdShow);
- }
- else
- {
- MSG msg;
- /* In case shell32 was kept in memory by a service process, tell him to
- * refresh all restrictions, before we call SHRestricted or any other
- * shell API that might depend on restrictions (SHGetSpecialFolderPath,
- * for example). Otherwise, the current user will inherit some of the
- * previous user's restrictions.
- */
- SHSettingsChanged(0, 0);
- /*
- * BUGBUG - Win9x - we need to nuke the drives list so the incoming
- * user doesn't inherit drive icons from the previous user
- */
- dwShellStartTime = GetTickCount(); // Compute shell startup time for perf automation
- ShellDDEInit(TRUE); // use shdocvw shell DDE code.
- // Specify the shutdown order of the shell process. 2 means
- // the explorer should shutdown after everything but ntsd/windbg
- // (level 0). (Taskman used to use 1, but is no more.)
- SetProcessShutdownParameters(2, 0);
- _AutoRunTaskMan();
- // NB Make this the primary thread by calling peek message
- // for a message we know we're not going to get.
- // If we don't do it really soon, the notify thread can sometimes
- // become the primary thread by accident. There's a bunch of
- // special code in user to implement DDE hacks by assuming that
- // the primary thread is handling DDE.
- // Also, the PeekMsg() will cause us to set the WaitForInputIdle()
- // event so we better be ready to do all dde.
- PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_NOREMOVE);
- // Make sure we are the first one to call the FileIconInit...
- FileIconInit(TRUE); // Tell the shell we want to play with a full deck
- g_fLogonCycle = IsFirstInstanceAfterLogon();
- g_fCleanShutdown = ReadCleanShutdown();
- if (g_fLogonCycle)
- {
- HWND hwndWait;
- // force kernel32 to update the timezone before running any apps
- DoDaylightCheck(TRUE);
- ProcessRunOnceEx();
- // We are about to do something that might take a long time so we want to display the
- // wait cursor, however we haven't created the desktop window yet. To get around this
- // we create a temporary window which we use to display the wait cursor.
- // REVIEW: Maybe we should move this up to show the wait cursor sooner and longer?
- hwndWait = CreateRegAppsWaitWindow();
- RunRegAppsAndObjects(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, RRA_DELETE | RRA_WAIT);
- DestroyRegAppsWaitWindow(hwndWait);
- }
- _CreateAppGlobals();
- CheckForSP3RSAOverwrite();
- if (g_fCleanBoot)
- DisplayCleanBootMsg(); // let users know we are in safe mode
- CreateShellDirectories(); // Create the other special folders.
- // Run install stubs for the current user, mostly to propagate
- // shortcuts to apps installed by another user.
- if (!g_fCleanBoot)
- RunInstallUninstallStubs();
- OleInitializeWaitForSCM();
- if (!g_fCleanShutdown)
- {
- HWND hwndVerFind;
- IActiveDesktopP *piadp;
- //
- // Post a message to the MTTF window if it is present
- //
- // BUGBUG Get LOR to use RegisterWindowMessage()
- //
- hwndVerFind = FindWindow(TEXT("BFG2000"), NULL);
- if (hwndVerFind)
- {
- PostMessage(hwndVerFind, WM_COMMAND, 40005, 0);
- }
- // Put the active desktop in safe mode if we faulted previously and this is a subsequent instance
- if (SUCCEEDED(CoCreateInstance(&CLSID_ActiveDesktop, NULL, CLSCTX_INPROC, &IID_IActiveDesktopP, (void **)&piadp)))
- {
- piadp->lpVtbl->SetSafeMode(piadp, SSM_SET | SSM_UPDATE);
- piadp->lpVtbl->Release(piadp);
- }
- }
- PostMTTFMessage(MTTF_STARTUP);
- WriteCleanShutdown(FALSE); // assume we will have a bad shutdown
- WinList_Init();
- // If any of the shellwindows are already present, then we want to bail out.
- //
- // NOTE: Compaq shell changes the "shell=" line during RunOnce time and
- // that will make ShouldStartDesktopAndTray() return FALSE
- if (!IsAnyShellWindowAlreadyPresent() && CreateDesktopAndTray())
- {
- _RunWinComCmdLine(pszCmdLine, nCmdShow);
- if (StopWatchMode())
- {
- // We used to save these off into global vars, and then write them at
- // WM_ENDSESSION, but that seems too unreliable
- DWORD dwShellStopTime = GetTickCount();
- StopWatch_StartTimed(SWID_STARTUP, TEXT("Shell Startup: Start"), SPMODE_SHELL | SPMODE_DEBUGOUT, dwShellStartTime);
- StopWatch_StopTimed(SWID_STARTUP, TEXT("Shell Startup: Stop"), SPMODE_SHELL | SPMODE_DEBUGOUT, dwShellStopTime);
- }
- if (g_dwProfileCAP & 0x00010000)
- StopCAP();
- // this must be whomever is the window on this thread
- SHDesktopMessageLoop(g_hDesktop);
- WriteCleanShutdown(TRUE); // we made it out ok, record that fact
- PostMTTFMessage(MTTF_SHUTDOWN);
- }
- WinList_Terminate(); // Turn off our window list processing
- OleUninitialize();
- ShellDDEInit(FALSE); // use shdocvw shell DDE code
- }
- DebugMsg(DM_TRACE, TEXT("c.App Exit."));
- return TRUE;
- }
- DWORD WINAPI RunStartupAppsThread(void *pvVoid)
- {
- // Some of the items we launch during startup assume that com is initialized. Make this
- // assumption true.
- CoInitialize(0);
- // These global flags are set once long before our thread starts and are then only
- // read so we don't need to worry about timing issues.
- if (g_fLogonCycle && !g_fCleanBoot)
- {
- // We only run these startup items if g_fLogonCycle is TRUE. This prevents
- // them from running again if the shell crashes and restarts.
- _DoRunEquals(); // Process the Load= and Run= lines...
- RunRegAppsAndObjects(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUN, RRA_NOUI);
- RunRegAppsAndObjects(HKEY_CURRENT_USER, REGSTR_PATH_RUN, RRA_NOUI);
- _ExecuteStartupPrograms(NULL);
- }
- // As a best guess, the CURunOnce key is executed regardless of the g_fLogonCycle
- // becuase it was once hoped that we could install newer versions of IE without
- // requiring a reboot. They would place something in the CURunOnce key and then
- // shutdown and restart the shell to continue their setup process. I believe this
- // idea was later abandoned but the code change is still here. Since that could
- // some day be a useful feature I'm leaving it the same.
- RunRegAppsAndObjects(HKEY_CURRENT_USER, REGSTR_PATH_RUNONCE, RRA_DELETE|RRA_NOUI);
- // we need to run all the non-blocking items first. Then we spend the rest of this threads life
- // runing the synchronized objects one after another.
- if (g_fLogonCycle && !g_fCleanBoot)
- {
- _RunWelcome();
- RunRegAppsAndObjects(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, RRA_NOUI|RRA_RUNSUBKEYS|RRA_WAIT|RRA_DELETE);
- RunRegAppsAndObjects(HKEY_CURRENT_USER, REGSTR_PATH_RUNONCE, RRA_NOUI|RRA_RUNSUBKEYS|RRA_WAIT|RRA_DELETE);
- RunRegAppsAndObjects(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUN, RRA_NOUI|RRA_RUNSUBKEYS|RRA_WAIT);
- RunRegAppsAndObjects(HKEY_CURRENT_USER, REGSTR_PATH_RUN, RRA_NOUI|RRA_RUNSUBKEYS|RRA_WAIT);
- }
- CoUninitialize();
- return TRUE;
- }
- void RunStartupApps()
- {
- DWORD dwThreadID;
- HANDLE handle;
- handle = CreateThread( NULL, 0, RunStartupAppsThread, 0, 0, &dwThreadID );
- if ( handle )
- {
- CloseHandle(handle);
- }
- else
- {
- // we couldn't create the thread so just call the thread proc directly.
- // The RunStartupAppsThread function takes a long time to complete and
- // the UI thread will be non-responsive. We call this from the tray.
- // REVIEW: Is this really safe?
- RunStartupAppsThread(0);
- }
- }