You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
367 lines
7.7 KiB
367 lines
7.7 KiB
// Copyright (C) 2002 Microsoft Corporation
|
|
//
|
|
// DllMain and COM DllXxx functions
|
|
//
|
|
// 21 January 2002
|
|
|
|
|
|
// To test this app: "mshta.exe res://mys.dll/mys.hta"
|
|
|
|
|
|
|
|
#include "headers.hxx"
|
|
#include "ManageYourServer.hpp"
|
|
|
|
|
|
|
|
HINSTANCE hResourceModuleHandle = 0;
|
|
const wchar_t* HELPFILE_NAME = 0;
|
|
const wchar_t* RUNTIME_NAME = L"mys";
|
|
|
|
DWORD DEFAULT_LOGGING_OPTIONS = Burnslib::Log::OUTPUT_MUTE;
|
|
|
|
|
|
|
|
static WCHAR moduleFileName[MAX_PATH]; // Initialized in DllMain
|
|
|
|
|
|
|
|
struct RegistryEntry
|
|
{
|
|
const wchar_t *keyName;
|
|
const wchar_t *valueName;
|
|
const wchar_t *value;
|
|
};
|
|
|
|
|
|
|
|
// This is the junk we put in the registry to register the COM objects
|
|
// this dll implements.
|
|
|
|
static const RegistryEntry registryEntries[] =
|
|
{
|
|
{
|
|
L"CLSID\\" CLSID_STRING,
|
|
0,
|
|
CLASSNAME_STRING
|
|
},
|
|
{
|
|
L"CLSID\\" CLSID_STRING L"\\InprocServer32",
|
|
0,
|
|
moduleFileName
|
|
},
|
|
{
|
|
L"CLSID\\" CLSID_STRING L"\\InprocServer32",
|
|
L"ThreadingModel",
|
|
L"Apartment"
|
|
},
|
|
{
|
|
L"CLSID\\" CLSID_STRING L"\\ProgID",
|
|
0,
|
|
PROGID_VERSION_STRING
|
|
},
|
|
{
|
|
L"CLSID\\" CLSID_STRING L"\\VersionIndependentProgID",
|
|
0,
|
|
PROGID_STRING
|
|
},
|
|
{
|
|
PROGID_VERSION_STRING,
|
|
0,
|
|
CLASSNAME_STRING
|
|
},
|
|
{
|
|
PROGID_VERSION_STRING L"\\CLSID",
|
|
0,
|
|
CLSID_STRING
|
|
},
|
|
{
|
|
PROGID_STRING,
|
|
0,
|
|
CLASSNAME_STRING
|
|
},
|
|
{
|
|
PROGID_STRING L"\\CLSID",
|
|
0,
|
|
CLSID_STRING
|
|
},
|
|
{
|
|
PROGID_STRING L"\\CurVer",
|
|
0,
|
|
PROGID_VERSION_STRING
|
|
},
|
|
};
|
|
|
|
|
|
|
|
HRESULT
|
|
Unregister(const RegistryEntry *rgEntries, int cEntries)
|
|
{
|
|
LOG_FUNCTION(Unregister);
|
|
|
|
LOG(L"Calling UnRegisterTypeLib");
|
|
|
|
HRESULT hr =
|
|
::UnRegisterTypeLib(LIBID_ManageYourServerLib, 1, 0, 0, SYS_WIN32);
|
|
|
|
LOG_HRESULT(hr);
|
|
|
|
// don't break: continue on attempting to remove as much as possible
|
|
// of our registration
|
|
|
|
bool success = SUCCEEDED(hr);
|
|
for (int i = cEntries - 1; i >= 0; i--)
|
|
{
|
|
LONG err = ::RegDeleteKey(HKEY_CLASSES_ROOT, rgEntries[i].keyName);
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
success = false;
|
|
}
|
|
}
|
|
|
|
return success ? S_OK : S_FALSE;
|
|
}
|
|
|
|
|
|
|
|
// unregisters the CYS (srvwiz.dll) from win2k, if applicable
|
|
|
|
void
|
|
UnregisterPriorCys()
|
|
{
|
|
LOG_FUNCTION(UnregisterPriorCys);
|
|
|
|
static const GUID LIBID_OldSrvWiz =
|
|
{ /* D857B805-5F40-11D2-B002-00C04FC30936 */
|
|
0xD857B805,
|
|
0x5F40,
|
|
0x11D2,
|
|
{0xB0, 0x02, 0x00, 0xC0, 0x4F, 0xC3, 0x09, 0x36}
|
|
};
|
|
|
|
LOG(L"UnRegisterTypeLib");
|
|
|
|
HRESULT hr = ::UnRegisterTypeLib(LIBID_OldSrvWiz, 1, 0, 0, SYS_WIN32);
|
|
|
|
LOG_HRESULT(hr);
|
|
|
|
// the list of subkeys of HKCR to delete
|
|
|
|
static const String keys[] =
|
|
{
|
|
L"CLSID\\{D857B813-5F40-11D2-B002-00C04FC30936}",
|
|
L"Interface\\{D857B811-5F40-11D2-B002-00C04FC30936}",
|
|
L"SrvWiz.SrvWiz",
|
|
L"SrvWiz.SrvWiz.1"
|
|
};
|
|
|
|
for (int i = 0; i < (sizeof(keys) / sizeof(String)); ++i)
|
|
{
|
|
LOG(keys[i]);
|
|
|
|
hr = Win32ToHresult(::SHDeleteKey(HKEY_CLASSES_ROOT, keys[i].c_str()));
|
|
|
|
LOG_HRESULT(hr);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static
|
|
HRESULT
|
|
Register(const RegistryEntry *rgEntries, int cEntries)
|
|
{
|
|
|
|
BOOL bSuccess = TRUE;
|
|
HRESULT hr = S_OK; // 447822 prefix warning
|
|
const RegistryEntry *pEntry = rgEntries;
|
|
|
|
UnregisterPriorCys();
|
|
|
|
while (pEntry < rgEntries + cEntries)
|
|
{
|
|
HKEY hkey;
|
|
LONG err = RegCreateKey(HKEY_CLASSES_ROOT,
|
|
pEntry->keyName,
|
|
&hkey);
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
if (pEntry->value)
|
|
err = RegSetValueEx(hkey,
|
|
pEntry->valueName,
|
|
0, REG_SZ,
|
|
(const BYTE*)pEntry->value,
|
|
(lstrlen(pEntry->value) + 1) * sizeof(TCHAR));
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
bSuccess = FALSE;
|
|
Unregister(rgEntries, static_cast<int>(1 + pEntry - rgEntries));
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
bSuccess = FALSE;
|
|
if (pEntry != rgEntries)
|
|
Unregister(rgEntries, static_cast<int>(pEntry - rgEntries));
|
|
}
|
|
pEntry++;
|
|
};
|
|
|
|
if (bSuccess)
|
|
{
|
|
|
|
OLECHAR g_wszFileName[MAX_PATH];
|
|
|
|
// ISSUE-2002/03/07-sburns consider strsafe function
|
|
|
|
//NTRAID#NTBUG9-571986-2002/03/10-jmessec Defense in Depth, should check length of moduleFileName; even
|
|
//though buffers are currently the same size, this may later change, and/or
|
|
//moduleFileName might get horked, not initialized, etc
|
|
lstrcpy(g_wszFileName, moduleFileName);
|
|
ITypeLib *ptl = 0;
|
|
hr = LoadTypeLib(g_wszFileName, &ptl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = RegisterTypeLib(ptl, g_wszFileName, 0);
|
|
ptl->Release();
|
|
}
|
|
|
|
if (bSuccess)
|
|
hr = S_OK;
|
|
else
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr ;//bSuccess ? S_OK : E_FAIL;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
APIENTRY
|
|
DllMain(HINSTANCE h, DWORD dwReason, void *)
|
|
{
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
{
|
|
hResourceModuleHandle = h;
|
|
|
|
LOG(L"DLL_PROCESS_ATTACH");
|
|
|
|
GetModuleFileName(h, moduleFileName, MAX_PATH);
|
|
//NTRAID#NTBUG9-571986-2002/03/10-jmessec Not checking for error return value of GetModuleFileName
|
|
|
|
// we don't need thread attach notifications
|
|
|
|
::DisableThreadLibraryCalls(h);
|
|
|
|
break;
|
|
}
|
|
case DLL_PROCESS_DETACH:
|
|
{
|
|
|
|
#ifdef DBG
|
|
LOG(TEXT("DLL_PROCESS_DETACH"));
|
|
if (!ComServerLockState::CanUnloadNow())
|
|
{
|
|
LOG(L"server locks and/or outstanding object instances exit");
|
|
}
|
|
else
|
|
{
|
|
LOG(L"server can unload now.");
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
case DLL_THREAD_ATTACH:
|
|
case DLL_THREAD_DETACH:
|
|
default:
|
|
{
|
|
// we should never get here
|
|
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
STDAPI
|
|
DllRegisterServer()
|
|
{
|
|
LOG_FUNCTION(DllRegisterServer);
|
|
|
|
return
|
|
Register(
|
|
registryEntries,
|
|
sizeof(registryEntries) / sizeof(*registryEntries));
|
|
}
|
|
|
|
|
|
|
|
STDAPI
|
|
DllUnregisterServer()
|
|
{
|
|
LOG_FUNCTION(DllUnregisterServer);
|
|
|
|
return
|
|
Unregister(
|
|
registryEntries,
|
|
sizeof(registryEntries) / sizeof(*registryEntries));
|
|
}
|
|
|
|
|
|
|
|
STDAPI
|
|
DllCanUnloadNow()
|
|
{
|
|
LOG_FUNCTION(DllCanUnloadNow);
|
|
|
|
if (ComServerLockState::CanUnloadNow())
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
|
|
STDAPI
|
|
DllGetClassObject(
|
|
const CLSID& classID,
|
|
const IID& interfaceID,
|
|
void** interfaceDesired)
|
|
{
|
|
LOG_FUNCTION(DllGetClassObject);
|
|
|
|
IClassFactory* factory = 0;
|
|
|
|
// The class objects are instances of ClassFactory<>, which are ref-counted
|
|
// in the usual fashion (i.e. they track their ref counts, and
|
|
// self-destruct on final Release). I could have used static instances of
|
|
// a C++ class that ignored the refcounting (ala Don Box's examples in
|
|
// Essential COM)
|
|
|
|
if (classID == CLSID_ManageYourServer)
|
|
{
|
|
factory = new ClassFactory<ManageYourServer>;
|
|
}
|
|
else
|
|
{
|
|
*interfaceDesired = 0;
|
|
return CLASS_E_CLASSNOTAVAILABLE;
|
|
}
|
|
|
|
// the class factory instance starts with a ref count of 1. If the QI
|
|
// fails, then it self-destructs upon Release.
|
|
HRESULT hr = factory->QueryInterface(interfaceID, interfaceDesired);
|
|
factory->Release();
|
|
return hr;
|
|
}
|