/* * 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 /****************************** 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 */