windows-nt/Source/XPSP1/NT/com/ole32/cs/cstore/catreg.cxx
2020-09-26 16:20:57 +08:00

449 lines
14 KiB
C++

//
// Author: ushaji
// Date: December/Jan 1996
//
//
// Providing support for Component Categories in Class Store
//
// This source file contains implementations for ICatRegister interfaces. ¦
//
// Refer Doc "Design for Support of File Types and Component Categories
// in Class Store" ? (or may be Class Store Schema)
//
//----------------------------------------------------------------------------
#include "cstore.hxx"
//-------------------------------------------------------------
// RegisterCategories:
// registering categories in the class store.
// cCategories: Number of Categories
// rgCategoryInfo: Size cCategories
//
// Returns as soon as one of them fails.
//-------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CClassContainer::RegisterCategories(
/* [in] */ ULONG cCategories,
/* [size_is][in] */ CATEGORYINFO __RPC_FAR rgCategoryInfo[ ])
{
/* Registering a list of Category ID in the Class Store */
HRESULT hr;
IADs *pADs = NULL;
IDispatch *pUnknown = NULL;
STRINGGUIDRDN szCatid;
ULONG i, j, cdesc, posn;
LPOLESTR *pszDescExisting, *pszDesc;
WCHAR *localedescription = NULL;
// sizeof description + seperator length + locale in hex
/* BUGBUG::Should check whether write permissions exist? */
if (!IsValidReadPtrIn(this, sizeof(*this))) {
return E_ACCESSDENIED;
}
if (!IsValidReadPtrIn(rgCategoryInfo, sizeof(rgCategoryInfo[0])*cCategories))
{
return E_INVALIDARG; // gd
}
if (!m_fOpen)
return E_FAIL;
for (i = 0; i < cCategories; i++)
{
localedescription = (WCHAR *)CoTaskMemAlloc(sizeof(WCHAR)*(128+16));
if (!localedescription)
return E_OUTOFMEMORY;
RdnFromGUID(rgCategoryInfo[i].catid, szCatid);
wsprintf(localedescription, L"%x %s %s", rgCategoryInfo[i].lcid, CATSEPERATOR,
rgCategoryInfo[i].szDescription);
hr = m_ADsCategoryContainer->GetObject(NULL, szCatid, (IDispatch **)&pADs);
if (SUCCEEDED(hr))
{
hr = GetPropertyListAlloc (pADs, LOCALEDESCRIPTION, &cdesc, &pszDescExisting);
RETURN_ON_FAILURE(hr);
// Existing list of descriptions
pszDesc = (LPOLESTR *)CoTaskMemAlloc(sizeof(LPOLESTR)*(cdesc+1));
if (!pszDesc)
return E_OUTOFMEMORY;
for (j = 0; j < cdesc; j++)
pszDesc[j] = pszDescExisting[j];
if (!(posn = FindDescription(pszDescExisting, cdesc, &(rgCategoryInfo[i].lcid), NULL, 0)))
{
// if no description exists for the lcid.
pszDesc[cdesc] = localedescription;
cdesc++;
}
else
{ // overwrite the old value
CoTaskMemFree(pszDesc[posn-1]);
pszDesc[posn-1] = localedescription;
}
}
else
{
hr = m_ADsCategoryContainer->Create(
CLASS_CS_CATEGORY,
szCatid,
&pUnknown
);
RETURN_ON_FAILURE(hr);
pszDesc = (LPOLESTR *)CoTaskMemAlloc(sizeof(LPOLESTR));
if (!pszDesc)
return E_OUTOFMEMORY;
cdesc = 1;
pszDesc[0] = localedescription;
hr = pUnknown->QueryInterface(IID_IADs, (void **)&pADs);
RETURN_ON_FAILURE(hr);
pUnknown->Release();
}
// StringFromGUID(rgCategoryInfo[i].catid, szCatid);
// SetProperty(pADs, CATEGORYCATID, szCatid);
hr = SetPropertyGuid(pADs, CATEGORYCATID, rgCategoryInfo[i].catid);
RETURN_ON_FAILURE(hr);
SetPropertyList(pADs, LOCALEDESCRIPTION, cdesc, pszDesc);
for (j = 0; j < cdesc; j++)
CoTaskMemFree(pszDesc[j]);
CoTaskMemFree(pszDesc);
RETURN_ON_FAILURE(hr);
hr = StoreIt (pADs);
RETURN_ON_FAILURE(hr);
pADs->Release();
}
return hr;
} /* RegisterCategories */
//--------------------------------------------------------
// Unregistering categories from the class store
// cCategories: Number of Categories
// rgcatid: catids of the categories.
//
// Stops after any one of them returns a error.
// Doesn't remove the category ids from each of the class ids.
HRESULT STDMETHODCALLTYPE CClassContainer::UnRegisterCategories(
/* [in] */ ULONG cCategories,
/* [size_is][in] */ CATID __RPC_FAR rgcatid[ ])
{
STRINGGUIDRDN szCatid;
ULONG i;
HRESULT hr;
if (!IsValidPtrOut(this, sizeof(*this))){
return E_ACCESSDENIED;
}
if (!IsValidReadPtrIn(rgcatid, sizeof(rgcatid[0])*cCategories)){
return E_INVALIDARG;
}
// Checking whether the caller has permissions
if (!m_fOpen)
return E_FAIL;
for (i = 0; i < cCategories; i++)
{
RdnFromGUID(rgcatid[i], szCatid);
hr = m_ADsCategoryContainer->Delete(CLASS_CS_CATEGORY,
szCatid);
}
return S_OK;
} /* UnRegisterCategories */
//------------------------------------------------------------------
// RegisterClassXXXCategories:
// rclsid: This category will be registered with this clsid.
// cCategories: The number of categories to be added.
// rgcatid The categories to be added (cCategories)
// impl_or_req The property to which this category will be added.
// "Implemented Categories" or "Required Categories"
//
//
// add all the categories given to the class store for this class.
// The previous entries will be lost and on error it would not be
// restored or made empty. A PRIVATE METHOD called by the 2 public methods.
//------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CClassContainer::RegisterClassXXXCategories(
/* [in] */ REFCLSID rclsid,
/* [in] */ ULONG cCategories,
/* [size_is][in] */ CATID __RPC_FAR rgcatid[ ],BSTR impl_or_req)
{
HRESULT hr;
STRINGGUIDRDN szName;
IADs *pADs = NULL;
ULONG i, j, tobeadded;
VARIANT Var;
GUID *pCatids, *pOldCatids=NULL;
IDispatch *pUnknown = NULL;
STRINGGUID szGUID;
if (!m_fOpen)
return E_FAIL;
if (!IsValidPtrOut(this, sizeof(*this))) {
return E_ACCESSDENIED;
}
if (!IsValidReadPtrIn(rgcatid, sizeof(rgcatid[0])*cCategories)){
return E_INVALIDARG; // gd
}
if (IsNullGuid(rclsid))
return E_INVALIDARG;
// Get the ADs interface corresponding to the clsid that is mentioned.
StringFromGUID(rclsid, szGUID);
wsprintf(szName, L"CN=%s", szGUID);
hr = m_ADsClassContainer->GetObject(NULL,
szName,
(IDispatch **)&pADs
);
// if it didn't exist create it.
if (FAILED(hr)) {
hr = m_ADsClassContainer->Create(
CLASS_CS_CLASS,
szName,
&pUnknown
);
RETURN_ON_FAILURE(hr);
hr = pUnknown->QueryInterface(
IID_IADs,
(void **)&pADs
);
pUnknown->Release();
}
hr = SetProperty (pADs, CLASSCLSID, szGUID);
RETURN_ON_FAILURE(hr);
hr = GetPropertyListAllocGuid(pADs, impl_or_req, &tobeadded, &pOldCatids);
RETURN_ON_FAILURE(hr);
pCatids = (GUID *)CoTaskMemAlloc(sizeof(GUID)*(tobeadded+cCategories));
if (!pCatids)
return E_OUTOFMEMORY;
for (i = 0; i < tobeadded; i++)
pCatids[i] = pOldCatids[i];
for (i=0; i < cCategories; ++i) {
for (j = 0; j < tobeadded; j++)
{
if (memcmp(&rgcatid[i], &pCatids[j], sizeof(GUID)) == 0)
break;
}
if (j < tobeadded)
continue;
// The ith element is already there in the array.
// Make sure of this when the property name changes.
pCatids[tobeadded] = rgcatid[i];
tobeadded++;
}
VariantInit(&Var);
hr = PackGuidArray2Variant(pCatids, tobeadded, &Var);
RETURN_ON_FAILURE(hr);
if (tobeadded)
hr = pADs->Put(impl_or_req, Var);
else
hr = pADs->PutEx(ADS_PROPERTY_CLEAR, impl_or_req, Var);
RETURN_ON_FAILURE(hr);
VariantClear(&Var);
// save the data modified
hr = StoreIt(pADs);
pADs->Release();
CoTaskMemFree(pCatids);
if (pOldCatids)
CoTaskMemFree(pOldCatids);
return hr;
} /* RegisterClassXXXCategories */
//---------------------------------------------------------------------
// UnRegisterClassXXXCategories
// rclsid: classid from which the categories have to be removed.
// cCategories: Number of Categories
// rgcatid: Categories
// impl_or_req: The property to which this has to be added.
//
// Presently gets all the categories from the class. parses through it
// removes the ones that match in rgcatid and reregister the category.
//---------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CClassContainer::UnRegisterClassXXXCategories(
/* [in] */ REFCLSID rclsid,
/* [in] */ ULONG cCategories,
/* [size_is][in] */ CATID __RPC_FAR rgcatid[ ],BSTR impl_or_req)
{
HRESULT hr;
STRINGGUIDRDN szName;
IADs *pADs = NULL;
ULONG i, j;
ULONG cNewCatids, cOldCatids;
VARIANT Var;
GUID *pOldCatids=NULL, *pNewCatids;
// BUGBUG:: Have to decide some way of removing clsids once all categories
// are unregistered.
if (!m_fOpen)
return E_FAIL;
if (IsNullGuid(rclsid))
return E_INVALIDARG;
if (cCategories == 0)
return S_OK;
if (!IsValidPtrOut(this, sizeof(*this))) {
return E_ACCESSDENIED;
}
if (!IsValidReadPtrIn(rgcatid, sizeof(rgcatid[0])*cCategories)){
return E_INVALIDARG; // gd
}
if (cCategories == 0)
return S_OK;
// Get all the catids corresp to this clsid.
// Get the ADs interface corresponding to the clsid that is mentioned.
RdnFromGUID(rclsid, szName);
hr = m_ADsClassContainer->GetObject(NULL,
szName,
(IDispatch **)&pADs
);
RETURN_ON_FAILURE(hr);
hr = GetPropertyListAllocGuid(pADs,
impl_or_req,
&cOldCatids,
&pOldCatids);
RETURN_ON_FAILURE(hr);
// parse through this list and delete all the catids that is part of
// the user supplied list.
pNewCatids = (GUID *)CoTaskMemAlloc(sizeof(GUID)*cOldCatids);
if (!pNewCatids)
return E_OUTOFMEMORY;
for (i = 0, cNewCatids = 0; i < cOldCatids; i++)
{
for (j = 0; j < cCategories; j++)
if (memcmp(&pOldCatids[i], &rgcatid[j], sizeof(GUID)) == 0)
break;
if (j == cCategories)
pNewCatids[cNewCatids++] = pOldCatids[i];
}
// reregister this.
VariantInit(&Var);
hr = PackGuidArray2Variant(pNewCatids, cNewCatids, &Var);
RETURN_ON_FAILURE(hr);
if (cNewCatids)
hr = pADs->Put(impl_or_req, Var);
else
hr = pADs->PutEx(ADS_PROPERTY_CLEAR, impl_or_req, Var);
RETURN_ON_FAILURE(hr);
VariantClear(&Var);
// save the data modified
hr = StoreIt(pADs);
pADs->Release();
CoTaskMemFree(pNewCatids);
if (pOldCatids)
CoTaskMemFree(pOldCatids);
return hr;
} /* UnRegisterClassXXXCategories */
HRESULT STDMETHODCALLTYPE CClassContainer::RegisterClassImplCategories(
/* [in] */ REFCLSID rclsid,
/* [in] */ ULONG cCategories,
/* [size_is][in] */ CATID __RPC_FAR rgcatid[ ])
{
return RegisterClassXXXCategories(rclsid, cCategories, rgcatid,
IMPL_CATEGORIES);
} /* RegisterClassImplCategories */
HRESULT STDMETHODCALLTYPE CClassContainer::UnRegisterClassImplCategories(
/* [in] */ REFCLSID rclsid,
/* [in] */ ULONG cCategories,
/* [size_is][in] */ CATID __RPC_FAR rgcatid[ ])
{
return UnRegisterClassXXXCategories(rclsid, cCategories, rgcatid,
IMPL_CATEGORIES);
} /* UnRegisterClassImplCategories */
HRESULT STDMETHODCALLTYPE CClassContainer::RegisterClassReqCategories(
/* [in] */ REFCLSID rclsid,
/* [in] */ ULONG cCategories,
/* [size_is][in] */ CATID __RPC_FAR rgcatid[ ])
{
return RegisterClassXXXCategories(rclsid, cCategories, rgcatid,
REQ_CATEGORIES);
} /* RegisterClassReqCategories */
HRESULT STDMETHODCALLTYPE CClassContainer::UnRegisterClassReqCategories(
/* [in] */ REFCLSID rclsid,
/* [in] */ ULONG cCategories,
/* [size_is][in] */ CATID __RPC_FAR rgcatid[ ])
{
return UnRegisterClassXXXCategories(rclsid, cCategories, rgcatid,
REQ_CATEGORIES);
} /* UnRegisterClassReqCategories */
//--------------------------------------------------------------------