📄 compobj.c
字号:
*lpdwRegister = 0;
/*
* First, check if the class is already registered.
* If it is, this should cause an error.
*/
hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
if (hr == S_OK) {
if (flags & REGCLS_MULTIPLEUSE) {
if (dwClsContext & CLSCTX_LOCAL_SERVER)
hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
IUnknown_Release(foundObject);
return hr;
}
IUnknown_Release(foundObject);
ERR("object already registered for class %s\n", debugstr_guid(rclsid));
return CO_E_OBJISREG;
}
newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
if ( newClass == NULL )
return E_OUTOFMEMORY;
EnterCriticalSection( &csRegisteredClassList );
newClass->classIdentifier = *rclsid;
newClass->runContext = dwClsContext;
newClass->connectFlags = flags;
newClass->pMarshaledData = NULL;
/*
* Use the address of the chain node as the cookie since we are sure it's
* unique. FIXME: not on 64-bit platforms.
*/
newClass->dwCookie = (DWORD)newClass;
newClass->nextClass = firstRegisteredClass;
/*
* Since we're making a copy of the object pointer, we have to increase its
* reference count.
*/
newClass->classObject = pUnk;
IUnknown_AddRef(newClass->classObject);
firstRegisteredClass = newClass;
LeaveCriticalSection( &csRegisteredClassList );
*lpdwRegister = newClass->dwCookie;
if (dwClsContext & CLSCTX_LOCAL_SERVER) {
IClassFactory *classfac;
hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
(LPVOID*)&classfac);
if (hr) return hr;
hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
if (hr) {
FIXME("Failed to create stream on hglobal, %lx\n", hr);
IUnknown_Release(classfac);
return hr;
}
hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
(LPVOID)classfac, MSHCTX_LOCAL, NULL,
MSHLFLAGS_TABLESTRONG);
if (hr) {
FIXME("CoMarshalInterface failed, %lx!\n",hr);
IUnknown_Release(classfac);
return hr;
}
IUnknown_Release(classfac);
RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
}
return S_OK;
}
/***********************************************************************
* CoRevokeClassObject [OLE32.@]
*
* Removes a class object from the class registry.
*
* PARAMS
* dwRegister [I] Cookie returned from CoRegisterClassObject().
*
* RETURNS
* Success: S_OK.
* Failure: HRESULT code.
*
* SEE ALSO
* CoRegisterClassObject
*/
HRESULT WINAPI CoRevokeClassObject(
DWORD dwRegister)
{
HRESULT hr = E_INVALIDARG;
RegisteredClass** prevClassLink;
RegisteredClass* curClass;
TRACE("(%08lx)\n",dwRegister);
EnterCriticalSection( &csRegisteredClassList );
/*
* Iterate through the whole list and try to match the cookie.
*/
curClass = firstRegisteredClass;
prevClassLink = &firstRegisteredClass;
while (curClass != 0)
{
/*
* Check if we have a match on the cookie.
*/
if (curClass->dwCookie == dwRegister)
{
/*
* Remove the class from the chain.
*/
*prevClassLink = curClass->nextClass;
/*
* Release the reference to the class object.
*/
IUnknown_Release(curClass->classObject);
if (curClass->pMarshaledData)
{
LARGE_INTEGER zero;
memset(&zero, 0, sizeof(zero));
/* FIXME: stop local server thread */
IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
CoReleaseMarshalData(curClass->pMarshaledData);
}
/*
* Free the memory used by the chain node.
*/
HeapFree(GetProcessHeap(), 0, curClass);
hr = S_OK;
goto end;
}
/*
* Step to the next class in the list.
*/
prevClassLink = &(curClass->nextClass);
curClass = curClass->nextClass;
}
end:
LeaveCriticalSection( &csRegisteredClassList );
/*
* If we get to here, we haven't found our class.
*/
return hr;
}
/***********************************************************************
* COM_RegReadPath [internal]
*
* Reads a registry value and expands it when necessary
*/
HRESULT COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
{
HRESULT hres;
HKEY key;
DWORD keytype;
WCHAR src[MAX_PATH];
DWORD dwLength = dstlen * sizeof(WCHAR);
if((hres = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
if( (hres = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
if (keytype == REG_EXPAND_SZ) {
if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) hres = ERROR_MORE_DATA;
} else {
lstrcpynW(dst, src, dstlen);
}
}
RegCloseKey (key);
}
return hres;
}
static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
{
HINSTANCE hLibrary;
typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
DllGetClassObjectFunc DllGetClassObject;
WCHAR dllpath[MAX_PATH+1];
if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
{
/* failure: CLSID is not found in registry */
WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
return REGDB_E_CLASSNOTREG;
}
if ((hLibrary = LoadLibraryExW(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0)
{
/* failure: DLL could not be loaded */
ERR("couldn't load in-process dll %s\n", debugstr_w(dllpath));
return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
}
if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject")))
{
/* failure: the dll did not export DllGetClassObject */
ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(dllpath));
FreeLibrary( hLibrary );
return CO_E_DLLNOTFOUND;
}
/* OK: get the ClassObject */
COMPOBJ_DLLList_Add( hLibrary );
return DllGetClassObject(rclsid, riid, ppv);
}
/***********************************************************************
* CoGetClassObject [OLE32.@]
*
* FIXME. If request allows of several options and there is a failure
* with one (other than not being registered) do we try the
* others or return failure? (E.g. inprocess is registered but
* the DLL is not found but the server version works)
*/
HRESULT WINAPI CoGetClassObject(
REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
REFIID iid, LPVOID *ppv)
{
LPUNKNOWN regClassObject;
HRESULT hres = E_UNEXPECTED;
TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
if (pServerInfo) {
FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
}
/*
* First, try and see if we can't match the class ID with one of the
* registered classes.
*/
if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject))
{
/* Get the required interface from the retrieved pointer. */
hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
/*
* Since QI got another reference on the pointer, we want to release the
* one we already have. If QI was unsuccessful, this will release the object. This
* is good since we are not returning it in the "out" parameter.
*/
IUnknown_Release(regClassObject);
return hres;
}
/* First try in-process server */
if (CLSCTX_INPROC_SERVER & dwClsContext)
{
static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
HKEY hkey;
hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
if (FAILED(hres))
{
if (hres == REGDB_E_CLASSNOTREG)
ERR("class %s not registered\n", debugstr_guid(rclsid));
else
WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
}
if (SUCCEEDED(hres))
{
hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
RegCloseKey(hkey);
}
/* return if we got a class, otherwise fall through to one of the
* other types */
if (SUCCEEDED(hres))
return hres;
}
/* Next try in-process handler */
if (CLSCTX_INPROC_HANDLER & dwClsContext)
{
static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
HKEY hkey;
hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
if (FAILED(hres))
{
if (hres == REGDB_E_CLASSNOTREG)
ERR("class %s not registered\n", debugstr_guid(rclsid));
else
WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
}
if (SUCCEEDED(hres))
{
hres = get_inproc_class_object(hkey, rclsid, iid, ppv);
RegCloseKey(hkey);
}
/* return if we got a class, otherwise fall through to one of the
* other types */
if (SUCCEEDED(hres))
return hres;
}
/* Next try out of process */
if (CLSCTX_LOCAL_SERVER & dwClsContext)
{
return RPC_GetLocalClassObject(rclsid,iid,ppv);
}
/* Finally try remote: this requires networked DCOM (a lot of work) */
if (CLSCTX_REMOTE_SERVER & dwClsContext)
{
FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
hres = E_NOINTERFACE;
}
if (FAILED(hres))
ERR("no class object %s could be created for for context 0x%lx\n",
debugstr_guid(rclsid), dwClsContext);
return hres;
}
/***********************************************************************
* CoResumeClassObjects (OLE32.@)
*
* Resumes all class objects registered with REGCLS_SUSPENDED.
*
* RETURNS
* Success: S_OK.
* Failure: HRESULT code.
*/
HRESULT WINAPI CoResumeClassObjects(void)
{
FIXME("stub\n");
return S_OK;
}
/***********************************************************************
* GetClassFile (OLE32.@)
*
* This function supplies the CLSID associated with the given filename.
*/
HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
{
IStorage *pstg=0;
HRESULT res;
int nbElm, length, i;
LONG sizeProgId;
LPOLESTR *pathDec=0,absFile=0,progId=0;
LPWSTR extension;
static const WCHAR bkslashW[] = {'\\',0};
static const WCHAR dotW[] = {'.',0};
TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
/* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
if((StgIsStorageFile(filePathName))==S_OK){
res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
if (SUCCEEDED(res))
res=ReadClassStg(pstg,pclsid);
IStorage_Release(pstg);
return res;
}
/* if the file is not a storage object then attemps to match various bits in the file against a
pattern in the registry. this case is not frequently used ! so I present only the psodocode for
this case
for(i=0;i<nFileTypes;i++)
for(i=0;j<nPatternsForType;j++){
PATTERN pat;
HANDLE hFile;
pat=ReadPatternFromRegistry(i,j);
hFile=CreateFileW(filePathName,,,,,,hFile);
SetFilePosition(hFile,pat.offset);
ReadFile(hFile,buf,pat.size,&r,NULL);
if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
*pclsid=ReadCLSIDFromRegistry(i);
return S_OK;
}
}
*/
/* if the above strategies fail then search for the extension key in the registry */
/* get the last element (absolute file) in the path name */
nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
absFile=pathDec[nbElm-1];
/* failed if the path represente a directory and not an absolute file name*/
if (!lstrcmpW(absFile, bkslashW))
return MK_E_INVALIDEXTENSION;
/* get the extension of the file */
extension = NULL;
length=lstrlenW(absFile);
for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
/* nothing */;
if (!extension || !lstrcmpW(extension, dotW))
return MK_E_INVALIDEXTENSION;
res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
/* get the progId associated to the extension */
progId = CoTaskMemAlloc(sizeProgId);
res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
if (res==ERROR_SUCCESS)
/* return the clsid associated to the progId */
res= CLSIDFromProgID(progId,pclsid);
for(i=0; pathDec[i]!=NULL;i++)
CoTaskMemFree(pathDec[i]);
CoTaskMemFree(pathDec);
CoTaskMemFree(progId);
if (res==ERROR_SUCCESS)
return res;
return MK_E_INVALIDEXTENSION;
}
/***********************************************************************
* CoCreateInstance [OLE32.@]
*/
HRESULT WINAPI CoCreateInstance(
REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
DWORD dwClsContext,
REFIID iid,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -