/************************************************************************* ** ** OLE 2 Sample Code ** ** classfac.c ** ** This file contains the implementation for IClassFactory for both the ** server and the client version of the OUTLINE app. ** ** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved ** *************************************************************************/ #include "outline.h" OLEDBGDATA extern LPOUTLINEAPP g_lpApp; /* OLE2NOTE: this object illustrates the manner in which to statically ** (compile-time) initialize an interface VTBL. */ static IClassFactoryVtbl g_AppClassFactoryVtbl = { AppClassFactory_QueryInterface, AppClassFactory_AddRef, AppClassFactory_Release, AppClassFactory_CreateInstance, AppClassFactory_LockServer }; /* AppClassFactory_Create ** ---------------------- ** create an instance of APPCLASSFACTORY. ** NOTE: type of pointer returned is an IClassFactory* interface ptr. ** the returned pointer can be directly passed to ** CoRegisterClassObject and released later by calling the ** Release method of the interface. */ LPCLASSFACTORY WINAPI AppClassFactory_Create(void) { LPAPPCLASSFACTORY lpAppClassFactory; LPMALLOC lpMalloc; if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR) return NULL; lpAppClassFactory = (LPAPPCLASSFACTORY)lpMalloc->lpVtbl->Alloc( lpMalloc, (sizeof(APPCLASSFACTORY))); lpMalloc->lpVtbl->Release(lpMalloc); if (! lpAppClassFactory) return NULL; lpAppClassFactory->m_lpVtbl = &g_AppClassFactoryVtbl; lpAppClassFactory->m_cRef = 1; #if defined( _DEBUG ) lpAppClassFactory->m_cSvrLock = 0; #endif return (LPCLASSFACTORY)lpAppClassFactory; } /************************************************************************* ** OleApp::IClassFactory interface implementation *************************************************************************/ STDMETHODIMP AppClassFactory_QueryInterface( LPCLASSFACTORY lpThis, REFIID riid, LPVOID FAR* ppvObj) { LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; SCODE scode; // Two interfaces supported: IUnknown, IClassFactory if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown)) { lpAppClassFactory->m_cRef++; // A pointer to this object is returned *ppvObj = lpThis; scode = S_OK; } else { // unsupported interface *ppvObj = NULL; scode = E_NOINTERFACE; } return ResultFromScode(scode); } STDMETHODIMP_(ULONG) AppClassFactory_AddRef(LPCLASSFACTORY lpThis) { LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; return ++lpAppClassFactory->m_cRef; } STDMETHODIMP_(ULONG) AppClassFactory_Release(LPCLASSFACTORY lpThis) { LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; LPMALLOC lpMalloc; if (--lpAppClassFactory->m_cRef != 0) // Still used by others return lpAppClassFactory->m_cRef; // Free storage if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR) return 0; lpMalloc->lpVtbl->Free(lpMalloc, lpAppClassFactory); lpMalloc->lpVtbl->Release(lpMalloc); return 0; } STDMETHODIMP AppClassFactory_CreateInstance ( LPCLASSFACTORY lpThis, LPUNKNOWN lpUnkOuter, REFIID riid, LPVOID FAR* lplpvObj ) { LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp; LPOLEDOC lpOleDoc; HRESULT hrErr; OLEDBG_BEGIN2("AppClassFactory_CreateInstance\r\n") /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ *lplpvObj = NULL; /********************************************************************* ** OLE2NOTE: this is an SDI app; it can only create and support one ** instance. After the instance is created, the OLE libraries ** should not call CreateInstance again. it is a good practise ** to specifically guard against this. *********************************************************************/ if (lpOutlineApp->m_lpDoc != NULL) return ResultFromScode(E_UNEXPECTED); /* OLE2NOTE: create a new document instance. by the time we return ** from this method the document's refcnt must be 1. */ lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE); lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpDoc; if (! lpOleDoc) { OLEDBG_END2 return ResultFromScode(E_OUTOFMEMORY); } /* OLE2NOTE: retrieve pointer to requested interface. the ref cnt ** of the object after OutlineApp_CreateDoc is 0. this call to ** QueryInterface will increment the refcnt to 1. the object ** returned from IClassFactory::CreateInstance should have a ** refcnt of 1 and be controlled by the caller. If the caller ** releases the document, the document should be destroyed. */ hrErr = OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj); OLEDBG_END2 return hrErr; } STDMETHODIMP AppClassFactory_LockServer ( LPCLASSFACTORY lpThis, BOOL fLock ) { LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis; LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; HRESULT hrErr; OLEDBG_BEGIN2("AppClassFactory_LockServer\r\n") #if defined( _DEBUG ) if (fLock) { ++lpAppClassFactory->m_cSvrLock; OleDbgOutRefCnt3( "AppClassFactory_LockServer: cLock++\r\n", lpAppClassFactory, lpAppClassFactory->m_cSvrLock); } else { /* OLE2NOTE: when there are no open documents and the app is not ** under the control of the user and there are no outstanding ** locks on the app, then revoke our ClassFactory to enable the ** app to shut down. */ --lpAppClassFactory->m_cSvrLock; OleDbgAssertSz (lpAppClassFactory->m_cSvrLock >= 0, "AppClassFactory_LockServer(FALSE) called with cLock == 0" ); if (lpAppClassFactory->m_cSvrLock == 0) { OleDbgOutRefCnt2( "AppClassFactory_LockServer: UNLOCKED\r\n", lpAppClassFactory, lpAppClassFactory->m_cSvrLock); } else { OleDbgOutRefCnt3( "AppClassFactory_LockServer: cLock--\r\n", lpAppClassFactory, lpAppClassFactory->m_cSvrLock); } } #endif // _DEBUG /* OLE2NOTE: in order to hold the application alive we call ** CoLockObjectExternal to add a strong reference to our app ** object. this will keep the app alive when all other external ** references release us. if the user issues File.Exit the ** application will shut down in any case ignoring any ** outstanding LockServer locks because CoDisconnectObject is ** called in OleApp_CloseAllDocsAndExitCommand. this will ** forceably break any existing strong reference counts ** including counts that we add ourselves by calling ** CoLockObjectExternal and guarantee that the App object gets ** its final release (ie. cRefs goes to 0). */ hrErr = OleApp_Lock(lpOleApp, fLock, TRUE /* fLastUnlockReleases */); OLEDBG_END2 return hrErr; }