328 lines
7.7 KiB
C++
328 lines
7.7 KiB
C++
/***************************************************************************
|
|
* dll.c
|
|
*
|
|
* Standard DLL entry-point functions
|
|
*
|
|
***************************************************************************/
|
|
|
|
// Note: Proxy/Stub Information from ATL
|
|
//
|
|
// To merge the proxy/stub code into the object DLL, add the file
|
|
// dlldatax.c to the project. Make sure precompiled headers
|
|
// are turned off for this file, and add _MERGE_PROXYSTUB to the
|
|
// defines for the project.
|
|
//
|
|
// If you are not running WinNT4.0 or Win95 with DCOM, then you
|
|
// need to remove the following define from dlldatax.c
|
|
// #define _WIN32_WINNT 0x0400
|
|
//
|
|
// Further, if you are running MIDL without /Oicf switch, you also
|
|
// need to remove the following define from dlldatax.c.
|
|
// #define USE_STUBLESS_PROXY
|
|
//
|
|
// Modify the custom build rule for shappmgr.idl by adding the following
|
|
// files to the Outputs.
|
|
// shappmgr_p.c
|
|
// dlldata.c
|
|
// To build a separate proxy/stub DLL,
|
|
// run nmake -f shappmgrps.mk in the project directory.
|
|
|
|
|
|
#include "priv.h"
|
|
#include "sccls.h"
|
|
|
|
#ifndef DOWNLEVEL
|
|
#include "adcctl.h"
|
|
#endif //DOWNLEVEL
|
|
|
|
#include <ntverp.h>
|
|
#include <advpub.h> // For REGINSTALL
|
|
|
|
// Define GUIDs
|
|
|
|
|
|
extern "C"
|
|
{
|
|
HINSTANCE g_hinst = NULL;
|
|
|
|
int g_cxIcon;
|
|
int g_cyIcon;
|
|
BOOL g_bMirroredOS;
|
|
LONG g_cRefThisDll = 0; // per-instance
|
|
|
|
#ifdef WX86
|
|
//
|
|
// from uninstal.c
|
|
//
|
|
extern BOOL bWx86Enabled;
|
|
BOOL IsWx86Enabled(VOID);
|
|
#endif
|
|
|
|
};
|
|
|
|
#ifndef DOWNLEVEL
|
|
CComModule _Module; // ATL module object
|
|
|
|
BEGIN_OBJECT_MAP(ObjectMap)
|
|
OBJECT_ENTRY(CLSID_ADCCtl, CADCCtl)
|
|
END_OBJECT_MAP()
|
|
#endif //DOWNLEVEL
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: DllEntryPoint
|
|
|
|
*/
|
|
BOOL
|
|
APIENTRY
|
|
DllMain(
|
|
IN HINSTANCE hinst,
|
|
IN DWORD dwReason,
|
|
IN LPVOID lpReserved)
|
|
{
|
|
#ifdef _MERGE_PROXYSTUB
|
|
if (!PrxDllMain(hInstance, dwReason, lpReserved))
|
|
return FALSE;
|
|
#endif
|
|
|
|
switch(dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
#ifndef DOWNLEVEL
|
|
_Module.Init(ObjectMap, hinst);
|
|
#endif //DOWNLEVEL
|
|
DisableThreadLibraryCalls(hinst);
|
|
SHFusionInitializeFromModule(hinst);
|
|
|
|
#ifdef DEBUG
|
|
CcshellGetDebugFlags();
|
|
|
|
if (g_dwBreakFlags & BF_ONDLLLOAD)
|
|
DebugBreak();
|
|
#endif
|
|
|
|
g_hinst = hinst;
|
|
|
|
g_cxIcon = GetSystemMetrics(SM_CXICON);
|
|
g_cyIcon = GetSystemMetrics(SM_CYICON);
|
|
g_bMirroredOS = IS_MIRRORING_ENABLED();
|
|
#ifdef WX86
|
|
bWx86Enabled = IsWx86Enabled();
|
|
#endif
|
|
break;
|
|
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
#ifndef DOWNLEVEL
|
|
_Module.Term();
|
|
#endif //DOWNLEVEL
|
|
SHFusionUninitialize();
|
|
break;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
case DLL_THREAD_DETACH:
|
|
// We shouldn't get these because we called
|
|
// DisableThreadLibraryCalls().
|
|
ASSERT_MSG(0, "DllMain received DLL_THREAD_ATTACH/DETACH! We're not expecting this.");
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: This function provides the DLL version info. This
|
|
allows the caller to distinguish running NT SUR vs.
|
|
Win95 shell vs. Nashville, etc.
|
|
|
|
The caller must GetProcAddress this function.
|
|
|
|
Returns: NO_ERROR
|
|
ERROR_INVALID_PARAMETER if pinfo is invalid
|
|
|
|
*/
|
|
|
|
// All we have to do is declare this puppy and CCDllGetVersion does the rest
|
|
DLLVER_DUALBINARY(VER_PRODUCTVERSION_DW, VER_PRODUCTBUILD_QFE);
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Calls the ADVPACK entry-point which executes an inf
|
|
file section.
|
|
*/
|
|
HRESULT _CallRegInstall(LPCSTR szSection, BOOL bUninstall)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL"));
|
|
|
|
if (hinstAdvPack)
|
|
{
|
|
REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, "RegInstall");
|
|
|
|
if (pfnri)
|
|
{
|
|
#ifdef WINNT
|
|
STRENTRY seReg[] = {
|
|
{ "25", "%SystemRoot%" },
|
|
{ "11", "%SystemRoot%\\system32" },
|
|
};
|
|
STRTABLE stReg = { ARRAYSIZE(seReg), seReg };
|
|
|
|
hr = pfnri(g_hinst, szSection, &stReg);
|
|
#else
|
|
hr = pfnri(g_hinst, szSection, NULL);
|
|
#endif
|
|
if (bUninstall)
|
|
{
|
|
// ADVPACK will return E_UNEXPECTED if you try to uninstall
|
|
// (which does a registry restore) on an INF section that was
|
|
// never installed. We uninstall sections that may never have
|
|
// been installed, so ignore this error
|
|
hr = ((E_UNEXPECTED == hr) ? S_OK : hr);
|
|
}
|
|
}
|
|
FreeLibrary(hinstAdvPack);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Install/uninstall user settings
|
|
|
|
*/
|
|
STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrExternal = S_OK;
|
|
|
|
#ifdef DEBUG
|
|
if (IsFlagSet(g_dwBreakFlags, BF_ONAPIENTER))
|
|
{
|
|
TraceMsg(TF_ALWAYS, "Stopping in DllInstall");
|
|
DEBUG_BREAK;
|
|
}
|
|
#endif
|
|
|
|
if (bInstall)
|
|
{
|
|
// Delete any old registration entries, then add the new ones.
|
|
// Keep ADVPACK.DLL loaded across multiple calls to RegInstall.
|
|
// (The inf engine doesn't guarantee DelReg/AddReg order, that's
|
|
// why we explicitly unreg and reg here.)
|
|
//
|
|
hr = THR(_CallRegInstall("RegDll", FALSE));
|
|
if (SUCCEEDED(hrExternal))
|
|
hrExternal = hr;
|
|
}
|
|
else
|
|
{
|
|
hr = THR(_CallRegInstall("UnregDll", TRUE));
|
|
if (SUCCEEDED(hrExternal))
|
|
hrExternal = hr;
|
|
}
|
|
|
|
return hrExternal;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Returns a class factory to create an object of
|
|
the requested type.
|
|
|
|
*/
|
|
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
|
|
{
|
|
TraceMsg(TF_OBJLIFE, "DllGetClassObject called with riid=%x (%x)", riid, &riid);
|
|
|
|
#ifdef _MERGE_PROXYSTUB
|
|
if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK)
|
|
return S_OK;
|
|
#endif
|
|
|
|
if (riid == IID_IClassFactory || riid == IID_IUnknown)
|
|
{
|
|
// Try our native class factory
|
|
HRESULT hres = GetClassObject(rclsid, riid, ppv);
|
|
|
|
#ifndef DOWNLEVEL
|
|
if (FAILED(hres))
|
|
{
|
|
// Try the ATL class factory
|
|
hres = _Module.GetClassObject(rclsid, riid, ppv);
|
|
}
|
|
#endif //DOWNLEVEL
|
|
|
|
return hres;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
return CLASS_E_CLASSNOTAVAILABLE;
|
|
}
|
|
|
|
|
|
STDAPI DllCanUnloadNow(void)
|
|
{
|
|
#ifdef _MERGE_PROXYSTUB
|
|
if (PrxDllCanUnloadNow() != S_OK)
|
|
return S_FALSE;
|
|
#endif
|
|
|
|
#ifndef DOWNLEVEL
|
|
// This component uses ATL and natively-implemented COM objects
|
|
if (0 != g_cRefThisDll || 0 != _Module.GetLockCount())
|
|
return S_FALSE;
|
|
#endif //DOWNLEVEL
|
|
|
|
TraceMsg(DM_TRACE, "DllCanUnloadNow returning S_OK (bye, bye...)");
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDAPI_(void) DllAddRef(void)
|
|
{
|
|
InterlockedIncrement(&g_cRefThisDll);
|
|
ASSERT(g_cRefThisDll < 1000); // reasonable upper limit
|
|
}
|
|
|
|
|
|
STDAPI_(void) DllRelease(void)
|
|
{
|
|
InterlockedDecrement(&g_cRefThisDll);
|
|
ASSERT(g_cRefThisDll >= 0); // don't underflow
|
|
}
|
|
|
|
|
|
STDAPI DllRegisterServer(void)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
|
|
#ifdef _MERGE_PROXYSTUB
|
|
hres = THR(PrxDllRegisterServer());
|
|
if (FAILED(hres))
|
|
return hres;
|
|
#endif
|
|
|
|
#ifndef DOWNLEVEL
|
|
// registers object, typelib and all interfaces in typelib
|
|
hres = THR(_Module.RegisterServer(TRUE));
|
|
#endif //DOWNLEVEL
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
STDAPI DllUnregisterServer(void)
|
|
{
|
|
#ifdef _MERGE_PROXYSTUB
|
|
PrxDllUnregisterServer();
|
|
#endif
|
|
|
|
#ifndef DOWNLEVEL
|
|
_Module.UnregisterServer();
|
|
#endif //DOWNLEVEL
|
|
return S_OK;
|
|
}
|