summaryrefslogtreecommitdiffstats
path: root/private/oleutest/letest/outline/classfac.c
blob: cf307022760346803da4b6c69a64300b6b220f45 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/*************************************************************************
**
**    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;
}