aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/EcmIf.h
blob: fc96525c2508eb5a17a4dd5418cc41b5f503931c (plain)
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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
/* -*- mode: C++; tab-width: 4 -*- */
/* ===================================================================== *\
	Copyright (c) 2001 PocketPyro, Inc.
	All rights reserved.

	This file is part of the Palm OS Emulator.

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
\* ===================================================================== */


#ifndef EcmIf_h
#define EcmIf_h

#include <string>

/*
	This file is the root file for ECM, the Extended Component Model
	system used within the Palm OS Emulator.

	ECM is a COM-like component system.  "Packages" (that is, plug-ins
	in the form of DLLs and the like) publicize their functionality in
	the form of "interfaces".  Packages can be queried (that is, the
	module can be asked for a particular interface by name, and the
	module can either return the interface, or fail, indicating that the
	requested facility is not supported).

	Interfaces are expressed as a table of function pointers.  As such,
	they are very similar to C++ vtables, are are often created using
	C++ class definitions.

	Every interface has base functionality.  That is, every interface
	starts off its function table with three standard functions:
	RequestInterface, Refer, and Release.  These three functions are
	defined as member functions of the pure virtual class IEcmComponent.
	Therefore, for consistancy, all C++ classes defining interfaces
	should ultimately descend from IEcmComponent.

	The three methods in IEcmComponent are pure virtual, and so need to
	be implemented in the class descending from it.  The implementation
	of these functions will likely be the same for all interfaces, and
	so there is a concrete subclass of IEcmComponent that provides a
	standard implementation.  This subclass is EcmObject.  Therefore,
	most interface implementation classes will probably descend from
	EcmObject and not directly from IEcmComponent.

	When an interface is defined (that is, the set of functions in the
	function table is established), it is introduced with the macro
	"ecm_interface".  This tells the reader that the following C++
	struct/class merely defines a set of functions for a client to use.
	Thus a new interface would look as follows:

		ecm_interface MyBaseInterface
		{
			virtual EcmErr MyFunction1() = 0;
			virtual EcmErr MyFunction2() = 0;
			virtual EcmErr MyFunction3() = 0;
		};

	When an interface needs to be extended (that is, a base interface
	needs to have some more functions added to it), the interface
	is again introduced with "ecm_interface", but is followed by the
	macro "ecm_extends" in the place where a C++ class indicates the
	base class it descends from.  Thus, an interface that inherited
	from a base interface would look as follows:

		ecm_interface MyDerivedInterface : ecm_extends MyBaseInterface
		{
			virtual EcmErr MyFunction4() = 0;
			virtual EcmErr MyFunction5() = 0;
			virtual EcmErr MyFunction6() = 0;
		};

	So far, we've just defined interfaces: the layout of the function
	pointer table.  We also need to implement the functions.  To do
	that, we create a class that descends from the interface we want
	to implement, using the macro "ecm_implements".  Thus, to implement
	the functions described by MyDerivedInterface, we use the following:

		class MyDerivedImplementation : ecm_implements MyDerivedInterface
		{
			virtual EcmErr MyFunction1();
			virtual EcmErr MyFunction2();
			virtual EcmErr MyFunction3();
			virtual EcmErr MyFunction4();
			virtual EcmErr MyFunction5();
			virtual EcmErr MyFunction6();
		};

	Once all of these interface and implementation classes are defined,
	they need to be used somehow.  The plug-in needs to be given a way
	to get to the interfaces it needs, and the container for the plug-in
	needs to know what interfaces the plug-in supports.

	This exchange of interface information takes place when the plug-in
	is loaded.  The plug-in needs to support an entry point that will
	(a) accept a container object and (b) return a package object.  The
	as with all interfaces, these objects contain RequestInterface methods
	from with all other interfaces can be obtained.

	Obtaining an interface using RequestInterface is simple: you pass a
	"name" of an interface to some ECM object, and that object will
	say that it supports or doesn't support that interface.  If it does
	support that interface, it returns a pointer to the interface.
*/


#define ecm_interface	struct
#define ecm_implements	virtual public
#define ecm_extends		virtual public


#define ECM_CLASS_IF_LIST_BEGIN(classname, basename)					\
	virtual EcmErr FindInterface(const EcmIfName &name, void **iPP)		\
	{																	\
		if (iPP == NULL)												\
			return kEcmErrInvalidParameter;


#define ECM_CLASS_IF(ifid, iftype)										\
		if (name == (ifid))												\
		{																\
			*iPP = (void *) static_cast<iftype *>(this);				\
			return kEcmErrNone;											\
		}


#define ECM_CLASS_IF_LIST_END(classname, basename)						\
		  return(basename::FindInterface(name, iPP));					\
	}



// ===========================================================================
//
//		Extended Component Model (ECM) -- Interfaces
//
//		We're adding support for component interfaces because 
//			exporting  c++ classes is a real pain from loadable libraries 
//			(at least Windows DLLs), Anyway, component design using interfaces
//			works really well for "plugin" type designs.
//
//		In our implementation, an interface is a c++ abstract base class.
// ===========================================================================


enum EcmErr
{
	kEcmErrNone,
	kEcmErrYikes,				// if this shows up, something really unexpected happened!
								// flag any appearance of this return code as a defect.

	kEcmErrInvalidParameter,	// a parameter was not set up correctly
	kEcmErrInvalidHandle,		// handle doesn't refer to anything appropriate
	kEcmErrInvalidIfName,		// invalid name of interface or event interface
	kEcmErrInvalidPubName,		// invalid name of publisher
	kEcmErrInvalidSrvName,		// invalid name of service
	kEcmErrInvalidCompName,		// invalid name of component
	kEcmErrBadEventType,		// inapropriate event type
	kEcmErrInvalidConnection,	//
	kEcmErrAlreadyConnected,	//
	kEcmErrNotInitialized		//
};




// ===========================================================================
//		EcmIfName -- type to define name used to reference an interface.
//			NOTE: If ECM becomes more widely used, this can be optimized to use an
//			atom table of strings.  An actual string comparison would then only need
//			to be done once.
// ===========================================================================

typedef string	EcmIfName;
typedef string	EcmCompName;


// ===========================================================================
//		EcmHandle -- Handle used for opaque references
// ===========================================================================

typedef void*	EcmHandle;



// ===========================================================================
//		IEcmComponent all interfaces must extend IEcmComponent..
//			this is how all patch modules appear to the patching sub-system
// ===========================================================================

const EcmIfName kEcmComponentIfn = "component.i.ecm";

ecm_interface IEcmComponent
{
	/***********************************************************************
	 *
	 * FUNCTION:	RequestInterface
	 *
	 * DESCRIPTION:	Requests an interface of type EcmIfName from the component
	 *
	 * PARAMETERS:	name	[IN   ] Name of the interface being requested.
	 *				iPP		[OUT  ] Interface to the event being sent.
	 *
	 * RETURNED:	ECMErrNone
	 *				ECMErrInvalidName
	 *
	 *
	 ***********************************************************************/

	virtual EcmErr RequestInterface(const EcmIfName &name, void **iPP) = 0;


	/***********************************************************************
	 *
	 * FUNCTION:	Refer
	 *
	 * DESCRIPTION:	Called before handing an interface pointer off to another 
	 *					"piece of code", adding an addition owner.  This is used to
	 *					maintain the reference count so the component can be destroyed
	 *					at the appropriate time.
	 *
	 * PARAMETERS:	none
	 *
	 * RETURNED:	ECMErrNone
	 *
	 *
	 ***********************************************************************/

    virtual EcmErr Refer() = 0;


	/***********************************************************************
	 *
	 * FUNCTION:	Release
	 *
	 * DESCRIPTION:	Releases the interface from a reference, when the reference count is 0,
	 *					the component can be destroyed.
	 *
	 * PARAMETERS:	none
	 *
	 * RETURNED:	ECMErrNone
	 *
	 *
	 ***********************************************************************/

    virtual EcmErr Release() = 0;
};



// ===========================================================================
//		IEcmContainer
// ===========================================================================

const EcmIfName kEcmContainerIfn = "container.i.ecm";

ecm_interface IEcmContainer : ecm_extends IEcmComponent
{
};



// ===========================================================================
//		IEcmPackage
// ===========================================================================

const EcmIfName kEcmPackageIfn = "package.i.ecm";

ecm_interface IEcmPackage : ecm_extends IEcmComponent
{
};



// ===========================================================================
//		IEcmEventBase
// ===========================================================================

const EcmIfName kEcmEventBaseIfn = "eventbase.events.i.ecm";

ecm_interface IEcmEventBase : ecm_extends IEcmComponent
{


};



// ===========================================================================
//		IEcmEventListener
// ===========================================================================

const EcmIfName kEcmEventListenerIfn = "listener.events.i.ecm";

/**
 **  Base interface for all event sinks.
 **/
ecm_interface IEcmEventListener
{
	/***********************************************************************
	 *
	 * FUNCTION:	OnEvent
	 *
	 * DESCRIPTION:	Delivers an event to the event listener
	 *
	 * PARAMETERS:	evtIP		[IN   ] Interface to the event being sent.
	 *
	 * RETURNED:	ECMErrNone
	 *				ECMErrBadEventType
	 *
	 *
	 ***********************************************************************/

    EcmErr OnEvent(const IEcmEventBase *evtIP);
};


// ===========================================================================
//		IEcmEvents
// ===========================================================================

const EcmIfName kEcmEventsIfn = "events.i.ecm";

ecm_interface IEcmEvents
{
	/***********************************************************************
	 *
	 * FUNCTION:	RequestListener
	 *
	 * DESCRIPTION:	Obtains an event listener interface (for a "category of events")
	 *
	 * PARAMETERS:	name			[IN   ] Name of the event interface being requested.
	 *				listenerIPP		[OUT  ] Interface to the given event listener.
	 *
	 * RETURNED:	ECMErrNone
	 *				ECMErrInvalidParameter
	 *				ECMErrInvalidName
	 *
	 *
	 ***********************************************************************/

    virtual EcmErr RequestListener(const EcmIfName &name, void **listenerIPP) = 0;


	/***********************************************************************
	 *
	 * FUNCTION:	Subscribe
	 *
	 * DESCRIPTION:	Allows an event "consumer" to subscribe to the named "category of events"
	 *
	 * PARAMETERS:	publisher		[IN   ] Name of the event publisher being requested.
	 *				subscriberIP	[IN   ] Interface to the subscribers event listener interface
	 *				handle			[OUT  ] Unique identifier handle associated with the subscription.
	 *
	 * RETURNED:	ECMErrNone
	 *				ECMErrInvalidParameter
	 *				ECMErrInvalidName
	 *
	 *
	 ***********************************************************************/

    virtual EcmErr Subscribe(const EcmIfName &publisher, const IEcmEventListener *subscriberIP, EcmHandle &handle) = 0;


	/***********************************************************************
	 *
	 * FUNCTION:	Unsubscribe
	 *
	 * DESCRIPTION:	Unsubscribes from an event publisher.
	 *
	 * PARAMETERS:	handle			[IN   ] Unique identifier created by "IEcmComponent::Subscribe".
	 *
	 * RETURNED:	ECMErrNone
	 *				ECMErrInvalidHandle
	 *
	 *
	 ***********************************************************************/

    virtual EcmErr Unsubscribe(const EcmHandle handle) = 0;

};


#endif // EcmIf_h