398 lines
9.8 KiB
C++
398 lines
9.8 KiB
C++
/*
|
|
* init.c - DLL startup routines module.
|
|
*/
|
|
|
|
/* Headers
|
|
**********/
|
|
|
|
#include "project.h"
|
|
#pragma hdrstop
|
|
|
|
#include "shlwapi.h"
|
|
#include "shlobj.h"
|
|
#include "ieguidp.h"
|
|
|
|
#include "init.h"
|
|
#include "clsfact.h"
|
|
#include "inetcpl.h"
|
|
#include "refcount.hpp"
|
|
#include "shlstock.h"
|
|
#include "olestock.h"
|
|
#include "ftps.hpp" /* for CLSID_MIMEFileTypesPropSheetHook */
|
|
#include "inetps.hpp" /* for CLSID_Internet */
|
|
#include "shguidp.h" // for CLSID_URLExecHook
|
|
#include "cfmacros.h" // static class factory macros
|
|
|
|
#define MLUI_INIT
|
|
#include <mluisupp.h>
|
|
|
|
/****************************** Public Functions *****************************/
|
|
|
|
/* Declare _main() so we can link with the CRT lib, but not have to
|
|
** use the DllMainCRTStartup entry point.
|
|
*/
|
|
void
|
|
_cdecl
|
|
main(void)
|
|
{
|
|
}
|
|
|
|
|
|
#pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
|
|
|
|
#ifdef MAINWIN
|
|
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, PVOID pvReserved);
|
|
|
|
extern "C" BOOL url_DllMain(
|
|
IN HINSTANCE DllHandle,
|
|
IN DWORD Reason,
|
|
IN LPVOID Reserved
|
|
)
|
|
{
|
|
return DllMain(DllHandle,Reason,Reserved);
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
** DllMain()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PUBLIC_CODE BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason,
|
|
PVOID pvReserved)
|
|
{
|
|
BOOL bResult;
|
|
|
|
DebugEntry(DllMain);
|
|
|
|
/* Validate dwReason below. */
|
|
/* pvReserved may be any value. */
|
|
|
|
ASSERT(IS_VALID_HANDLE(hModule, MODULE));
|
|
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
MLLoadResources(hModule, TEXT("urllc.dll"));
|
|
bResult = AttachProcess(hModule);
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
MLFreeResources(hModule);
|
|
bResult = DetachProcess(hModule);
|
|
break;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
bResult = AttachThread(hModule);
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
bResult = DetachThread(hModule);
|
|
break;
|
|
|
|
default:
|
|
ERROR_OUT(("LibMain() called with unrecognized dwReason %lu.",
|
|
dwReason));
|
|
bResult = FALSE;
|
|
break;
|
|
}
|
|
|
|
DebugExitBOOL(DllMain, bResult);
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
UINT
|
|
WhichPlatform(void)
|
|
{
|
|
HINSTANCE hinst;
|
|
|
|
//
|
|
// in retail we cache this info
|
|
// in debug we always re-fetch it (so people can switch)
|
|
//
|
|
#ifdef DEBUG
|
|
UINT uInstall = PLATFORM_UNKNOWN;
|
|
#else
|
|
static UINT uInstall = PLATFORM_UNKNOWN;
|
|
|
|
if (uInstall != PLATFORM_UNKNOWN)
|
|
return uInstall;
|
|
#endif
|
|
|
|
hinst = GetModuleHandle(TEXT("SHDOCVW.DLL"));
|
|
if (hinst)
|
|
{
|
|
// NOTE: GetProcAddress always takes ANSI strings!
|
|
DLLGETVERSIONPROC pfnGetVersion =
|
|
(DLLGETVERSIONPROC)GetProcAddress(hinst, "DllGetVersion");
|
|
|
|
if (pfnGetVersion)
|
|
{
|
|
DLLVERSIONINFO info;
|
|
|
|
info.cbSize = sizeof(info);
|
|
if (SUCCEEDED(pfnGetVersion(&info)))
|
|
{
|
|
if (4 <= info.dwMajorVersion &&
|
|
71 <= info.dwMinorVersion &&
|
|
429 <= info.dwBuildNumber)
|
|
{
|
|
uInstall = PLATFORM_INTEGRATED;
|
|
}
|
|
else
|
|
uInstall = PLATFORM_IE3;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
// To allow easier debugging, we can override the platform by
|
|
// setting InstallPlatform value in ccshell.ini.
|
|
{
|
|
UINT uInstallT = GetPrivateProfileInt(TEXT("urldebugoptions"),
|
|
TEXT("InstallPlatform"),
|
|
PLATFORM_UNKNOWN,
|
|
TEXT("ohare.ini"));
|
|
if (PLATFORM_UNKNOWN != uInstallT)
|
|
{
|
|
TRACE_OUT((" ***Overriding real platform installation***\r\n"));
|
|
uInstall = uInstallT;
|
|
}
|
|
}
|
|
|
|
switch (uInstall)
|
|
{
|
|
case PLATFORM_IE3:
|
|
TRACE_OUT((" ***Assuming IE3***\r\n"));
|
|
break;
|
|
|
|
case PLATFORM_INTEGRATED:
|
|
TRACE_OUT((" ***Assuming Nashville***\r\n"));
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return uInstall;
|
|
}
|
|
|
|
|
|
#pragma data_seg(DATA_SEG_PER_INSTANCE)
|
|
|
|
// DLL reference count == number of class factories +
|
|
// number of URLs +
|
|
// LockServer() count
|
|
|
|
PRIVATE_DATA ULONG s_ulcDLLRef = 0;
|
|
|
|
#pragma data_seg()
|
|
|
|
|
|
PUBLIC_CODE ULONG DLLAddRef(void)
|
|
{
|
|
ULONG ulcRef;
|
|
|
|
ASSERT(s_ulcDLLRef < ULONG_MAX);
|
|
|
|
ulcRef = ++s_ulcDLLRef;
|
|
|
|
TRACE_OUT(("DLLAddRef(): DLL reference count is now %lu.",
|
|
ulcRef));
|
|
|
|
return(ulcRef);
|
|
}
|
|
|
|
|
|
PUBLIC_CODE ULONG DLLRelease(void)
|
|
{
|
|
ULONG ulcRef;
|
|
|
|
if (EVAL(s_ulcDLLRef > 0))
|
|
s_ulcDLLRef--;
|
|
|
|
ulcRef = s_ulcDLLRef;
|
|
|
|
TRACE_OUT(("DLLRelease(): DLL reference count is now %lu.",
|
|
ulcRef));
|
|
|
|
return(ulcRef);
|
|
}
|
|
|
|
|
|
PUBLIC_CODE PULONG GetDLLRefCountPtr(void)
|
|
{
|
|
// REARCHITECT: this is dangerous. Shouldn't be used like this.
|
|
|
|
return(&s_ulcDLLRef);
|
|
}
|
|
|
|
|
|
typedef HRESULT (CALLBACK* DLLGETCLASSOBJECTPROC)(REFCLSID, REFIID, void**);
|
|
|
|
STDMETHODIMP_(BOOL)
|
|
PatchForNashville(
|
|
REFCLSID rclsid,
|
|
REFIID riid,
|
|
void **ppv,
|
|
HRESULT * phres)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
*phres = CLASS_E_CLASSNOTAVAILABLE; // assume error
|
|
|
|
if (IsEqualIID(rclsid, CLSID_InternetShortcut) &&
|
|
PLATFORM_INTEGRATED == WhichPlatform())
|
|
{
|
|
HINSTANCE hinst;
|
|
|
|
// Normally we can just patch the registry. But there is a valid
|
|
// case where url.dll is the InprocServer, and that is when the
|
|
// user has chosen to uninstall IE 4.0 and we haven't restarted
|
|
// the machine yet. In this case, we don't want to patch the
|
|
// registry. Use the "MayChangeDefaultMenu" as an indication
|
|
// of whether we should really patch it or not.
|
|
|
|
// Are we uninstalling IE 4.0?
|
|
if (NO_ERROR == SHGetValue(HKEY_CLASSES_ROOT,
|
|
TEXT("CLSID\\{FBF23B40-E3F0-101B-8488-00AA003E56F8}\\shellex\\MayChangeDefaultMenu"),
|
|
TEXT(""),
|
|
NULL, NULL, NULL))
|
|
{
|
|
// No; patch the registry so shdocvw is the handler again
|
|
SetRegKeyValue(HKEY_CLASSES_ROOT,
|
|
"CLSID\\{FBF23B40-E3F0-101B-8488-00AA003E56F8}\\InProcServer32",
|
|
NULL,
|
|
REG_SZ,
|
|
(PCBYTE)"shdocvw.dll", sizeof("shdocvw.dll"));
|
|
|
|
// Now call shdocvw's DllGetClassObject
|
|
hinst = GetModuleHandle(TEXT("SHDOCVW.DLL"));
|
|
if (hinst)
|
|
{
|
|
DLLGETCLASSOBJECTPROC pfn =
|
|
(DLLGETCLASSOBJECTPROC)GetProcAddress(hinst, "DllGetClassObject");
|
|
|
|
if (pfn)
|
|
{
|
|
*phres = pfn(rclsid, riid, ppv);
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
|
|
STDAPI CreateInstance_Intshcut(IUnknown *punkOuter, REFIID riid, void **ppvOut);
|
|
STDAPI CreateInstance_MIMEHook(IUnknown *punkOuter, REFIID riid, void **ppvOut);
|
|
STDAPI CreateInstance_Internet(IUnknown *punkOuter, REFIID riid, void **ppvOut);
|
|
STDAPI CreateInstance_URLExec(IUnknown *punkOuter, REFIID riid, void **ppvOut);
|
|
|
|
//
|
|
// ClassFactory methods.
|
|
//
|
|
|
|
STDMETHODIMP CClassFactory::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IClassFactory) || IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
*ppvObj = (void *)GET_ICLASSFACTORY(this);
|
|
DLLAddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CClassFactory::AddRef()
|
|
{
|
|
return DLLAddRef();
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CClassFactory::Release()
|
|
{
|
|
return DLLRelease();
|
|
}
|
|
|
|
STDMETHODIMP CClassFactory::CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppvObject)
|
|
{
|
|
CObjectInfo *localthis = (CObjectInfo*)(this);
|
|
return localthis->pfnCreate(punkOuter, riid, ppvObject);
|
|
}
|
|
|
|
STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
|
|
{
|
|
if (fLock)
|
|
DLLAddRef();
|
|
else
|
|
DLLRelease();
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// we always do a linear search here so put your most often used things first
|
|
//
|
|
|
|
CF_TABLE_BEGIN(c_clsmap)
|
|
|
|
CF_TABLE_ENTRY(&CLSID_URLExecHook, CreateInstance_URLExec)
|
|
CF_TABLE_ENTRY(&CLSID_InternetShortcut, CreateInstance_Intshcut)
|
|
CF_TABLE_ENTRY(&CLSID_MIMEFileTypesPropSheetHook, CreateInstance_MIMEHook)
|
|
CF_TABLE_ENTRY(&CLSID_Internet, CreateInstance_Internet)
|
|
|
|
CF_TABLE_END(c_clsmap)
|
|
|
|
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
|
|
{
|
|
HRESULT hres = CLASS_E_CLASSNOTAVAILABLE;
|
|
|
|
*ppv = NULL; // assume error
|
|
|
|
if (IsEqualIID(riid, IID_IClassFactory))
|
|
{
|
|
// Under Nashville, the internet shortcuts are handled by shdocvw.
|
|
// It is possible that the user installed Netscape after installing
|
|
// Nashville, which would cause url.dll to be the handler again
|
|
// for internet shortcuts. This patches the registry and calls
|
|
// shdocvw's DllGetClassObject if we're in that scenario.
|
|
|
|
// Did we patch for nashville?
|
|
if ( !PatchForNashville(rclsid, riid, ppv, &hres) )
|
|
{
|
|
// No; carry on...
|
|
const CObjectInfo *pcls;
|
|
for (pcls = c_clsmap; pcls->pclsid; pcls++)
|
|
{
|
|
if (IsEqualIID(rclsid, *(pcls->pclsid)))
|
|
{
|
|
*ppv = (void *)GET_ICLASSFACTORY(pcls);
|
|
DLLAddRef(); // creation of the CF, CF holds DLL Ref count
|
|
return NOERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
STDAPI DllCanUnloadNow(void)
|
|
{
|
|
if (s_ulcDLLRef > 0)
|
|
return S_FALSE;
|
|
|
|
return InternetCPLCanUnloadNow();
|
|
}
|
|
|
|
#pragma warning(default:4100) /* "unreferenced formal parameter" warning */
|