windows-nt/Source/XPSP1/NT/shell/services/hdsrv/lib/regsvr.cpp
2020-09-26 16:20:57 +08:00

353 lines
11 KiB
C++

#include "regsvr.h"
#include "reg.h"
#include "str.h"
#include "sfstr.h"
#include "factdata.h"
#include <sddl.h>
#define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0]))
///////////////////////////////////////////////////////////////////////////////
// Internal helper functions prototypes
LONG _RecursiveDeleteKey(HKEY hKeyParent, LPCWSTR szKeyChild);
///////////////////////////////////////////////////////////////////////////////
// Constants
// Size of a CLSID as a string
const int CLSID_STRING_SIZE = 39;
///////////////////////////////////////////////////////////////////////////////
// Public function implementation
HRESULT RegisterAppID(const CLSID* pclsidAppID)
{
WCHAR szAppID[CLSID_STRING_SIZE];
WCHAR szKey[MAX_KEY] = TEXT("AppID\\");
HRESULT hres = _StringFromGUID(pclsidAppID, szAppID, ARRAYSIZE(szAppID));
if (SUCCEEDED(hres))
{
hres = SafeStrCatN(szKey, szAppID, ARRAYSIZE(szKey));
if (SUCCEEDED(hres))
{
// Add the CLSID key and the FriendlyName
HKEY hkey;
hres= _RegCreateKey(HKEY_CLASSES_ROOT, szKey, &hkey, NULL);
if (S_OK == hres)
{
hres = _RegSetString(hkey, L"LocalService", L"ShellHWDetection");
if (SUCCEEDED(hres))
{
PSECURITY_DESCRIPTOR pSD;
ULONG cbSD;
//
// NTRAID#NTBUG9-258937-2001/01/17-jeffreys
//
// Set the launch permissions to prevent COM from ever
// launching the service. The only time we want the service
// to launch is at system startup.
//
// Don't think the owner and group matter, but they must be
// present, or COM thinks the security descriptor is invalid.
// O:SY --> Owner = LocalSystem
// G:BA --> Group = Local Administrators group
//
// The DACL has a single Deny ACE
// D:(D;;1;;;WD) --> Deny COM_RIGHTS_EXECUTE (1) to Everyone (WD)
//
if (ConvertStringSecurityDescriptorToSecurityDescriptorW(L"O:SYG:BAD:(D;;1;;;WD)", SDDL_REVISION, &pSD, &cbSD))
{
hres = _RegSetBinary(hkey, L"LaunchPermission", pSD, cbSD);
LocalFree(pSD);
}
else
{
hres = E_OUTOFMEMORY;
}
}
RegCloseKey(hkey);
}
}
}
return hres;
}
// Register the component in the registry.
HRESULT RegisterServer(HMODULE hModule, REFCLSID rclsid,
LPCWSTR pszFriendlyName, LPCWSTR pszVerIndProgID, LPCWSTR pszProgID,
DWORD dwThreadingModel, BOOL fInprocServer, BOOL fLocalServer,
BOOL fLocalService, LPCWSTR pszLocalService, const CLSID* pclsidAppID)
{
WCHAR szCLSID[CLSID_STRING_SIZE];
WCHAR szKey[MAX_KEY] = TEXT("CLSID\\");
HRESULT hres = _StringFromGUID(&rclsid, szCLSID, ARRAYSIZE(szCLSID));
if (SUCCEEDED(hres))
{
LPWSTR pszModel = NULL;
WCHAR szFree[] = TEXT("Free");
WCHAR szApartment[] = TEXT("Apartment");
WCHAR szNeutral[] = TEXT("Neutral");
WCHAR szBoth[] = TEXT("Both");
hres = SafeStrCatN(szKey, szCLSID, ARRAYSIZE(szKey));
// Boring set of operations....
if (SUCCEEDED(hres))
{
// Add the CLSID key and the FriendlyName
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, szKey, NULL, NULL,
pszFriendlyName);
}
if (SUCCEEDED(hres))
{
switch (dwThreadingModel)
{
case THREADINGMODEL_BOTH:
pszModel = szBoth;
break;
case THREADINGMODEL_FREE:
pszModel = szFree;
break;
case THREADINGMODEL_APARTMENT:
pszModel = szApartment;
break;
case THREADINGMODEL_NEUTRAL:
pszModel = szNeutral;
break;
default:
hres = E_FAIL;
break;
}
}
if (SUCCEEDED(hres))
{
// Add the server filename subkey under the CLSID key.
if (fInprocServer)
{
WCHAR szModule[MAX_PATH];
DWORD dwResult = GetModuleFileName(hModule, szModule,
ARRAYSIZE(szModule));
if (dwResult)
{
// Register as Inproc
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, szKey,
TEXT("InprocServer32"), NULL, szModule);
if (SUCCEEDED(hres))
{
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, szKey,
TEXT("InprocServer32"), TEXT("ThreadingModel"),
pszModel);
}
}
}
}
if (SUCCEEDED(hres))
{
// Add the server filename subkey under the CLSID key.
if (fLocalServer)
{
WCHAR szModule[MAX_PATH];
// Note the NULL as 1st arg. This way a DLL can register a
// factory as part of an EXE. Obviously, if this is done
// from 2 EXE's, only the last one will win...
DWORD dwResult = GetModuleFileName(NULL, szModule,
ARRAYSIZE(szModule));
if (dwResult)
{
// Register as LocalServer
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, szKey,
TEXT("LocalServer32"), NULL, szModule);
if (SUCCEEDED(hres))
{
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, szKey,
TEXT("LocalServer32"), TEXT("ThreadingModel"),
pszModel);
}
}
}
}
if (SUCCEEDED(hres))
{
// Add the server filename subkey under the CLSID key.
if (fLocalService)
{
// Register as LocalServer
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, szKey,
TEXT("LocalService"), NULL, pszLocalService);
if (SUCCEEDED(hres))
{
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, szKey,
TEXT("LocalService"), TEXT("ThreadingModel"),
pszModel);
}
{
// We had this bug for a while that a LocalServer32 key was
// also installed
// Delete it on upgrade (stephstm: Jun/02/2000)
// Remove this code when nobody will upgrade from
// builds earlier than 2242
WCHAR szKeyLocal[MAX_KEY];
SafeStrCpyN(szKeyLocal, szKey, ARRAYSIZE(szKeyLocal));
SafeStrCatN(szKeyLocal, TEXT("\\LocalServer32"),
ARRAYSIZE(szKeyLocal));
_RecursiveDeleteKey(HKEY_CLASSES_ROOT, szKeyLocal);
}
}
}
if (SUCCEEDED(hres))
{
// Add the ProgID subkey under the CLSID key.
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, szKey,
TEXT("ProgID"), NULL, pszProgID);
}
if (SUCCEEDED(hres))
{
// Add the version-independent ProgID subkey under CLSID
// key.
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, szKey,
TEXT("VersionIndependentProgID"), NULL, pszVerIndProgID);
}
if (SUCCEEDED(hres))
{
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, pszVerIndProgID,
NULL, NULL, pszFriendlyName);
}
if (SUCCEEDED(hres))
{
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, pszVerIndProgID,
TEXT("CLSID"), NULL, szCLSID);
}
if (SUCCEEDED(hres))
{
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, pszVerIndProgID,
TEXT("CurVer"), NULL, pszProgID);
}
if (SUCCEEDED(hres))
{
// Add the versioned ProgID subkey under HKEY_CLASSES_ROOT
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, pszProgID,
NULL, NULL, pszFriendlyName);
}
if (SUCCEEDED(hres))
{
// Add the versioned ProgID subkey under HKEY_CLASSES_ROOT
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, pszProgID,
TEXT("CLSID"), NULL, szCLSID);
}
if (SUCCEEDED(hres))
{
if (pclsidAppID)
{
// do the AppID.
WCHAR szAppID[CLSID_STRING_SIZE];
hres = _StringFromGUID(pclsidAppID, szAppID, ARRAYSIZE(szAppID));
if (SUCCEEDED(hres))
{
hres = _RegSetKeyAndString(HKEY_CLASSES_ROOT, szKey, NULL, TEXT("AppID"), szAppID);
}
RegisterAppID(pclsidAppID);
}
}
}
return hres;
}
// Remove the component from the registry.
HRESULT UnregisterServer(REFCLSID rclsid, LPCWSTR pszVerIndProgID,
LPCWSTR pszProgID)
{
WCHAR szCLSID[CLSID_STRING_SIZE];
WCHAR szKey[MAX_KEY] = TEXT("CLSID\\");
HRESULT hres = _StringFromGUID(&rclsid, szCLSID, ARRAYSIZE(szCLSID));
if (SUCCEEDED(hres))
{
SafeStrCatN(szKey, szCLSID, ARRAYSIZE(szKey));
// Delete the CLSID Key - CLSID\{...}
_RecursiveDeleteKey(HKEY_CLASSES_ROOT, szKey);
// Delete the version-independent ProgID Key.
_RecursiveDeleteKey(HKEY_CLASSES_ROOT, pszVerIndProgID);
// Delete the ProgID key.
_RecursiveDeleteKey(HKEY_CLASSES_ROOT, pszProgID);
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// Internal helper functions
// Delete a key and all of its descendents.
LONG _RecursiveDeleteKey(HKEY hKeyParent, LPCWSTR pszKeyChild)
{
HKEY hkeyChild;
LONG lRes = RegOpenKeyEx(hKeyParent, pszKeyChild, 0, KEY_ALL_ACCESS,
&hkeyChild);
if (ERROR_SUCCESS == lRes)
{
// Enumerate all of the decendents of this child.
WCHAR szBuffer[MAX_PATH];
DWORD dwSize = ARRAYSIZE(szBuffer);
while ((ERROR_SUCCESS == lRes) && (S_OK == RegEnumKeyEx(hkeyChild, 0,
szBuffer, &dwSize, NULL, NULL, NULL, NULL)))
{
// Delete the decendents of this child.
lRes = _RecursiveDeleteKey(hkeyChild, szBuffer);
dwSize = ARRAYSIZE(szBuffer);
}
// Close the child.
RegCloseKey(hkeyChild);
}
if (ERROR_SUCCESS == lRes)
{
// Delete this child.
lRes = RegDeleteKey(hKeyParent, pszKeyChild);
}
return lRes;
}