220 lines
6.7 KiB
C
220 lines
6.7 KiB
C
|
/*************************************************************************
|
||
|
**
|
||
|
** 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;
|
||
|
}
|