xref: /aoo4110/main/extensions/source/ole/oleobjw.hxx (revision b1cdbd2c)
1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski #ifndef __OLEOBJW_HXX
25*b1cdbd2cSJim Jagielski #define __OLEOBJW_HXX
26*b1cdbd2cSJim Jagielski #include "ole2uno.hxx"
27*b1cdbd2cSJim Jagielski 
28*b1cdbd2cSJim Jagielski #ifdef _MSC_VER
29*b1cdbd2cSJim Jagielski #pragma warning (push,1)
30*b1cdbd2cSJim Jagielski #pragma warning (disable:4548)
31*b1cdbd2cSJim Jagielski #endif
32*b1cdbd2cSJim Jagielski 
33*b1cdbd2cSJim Jagielski #include <tools/presys.h>
34*b1cdbd2cSJim Jagielski #define _WIN32_WINNT 0x0400
35*b1cdbd2cSJim Jagielski 
36*b1cdbd2cSJim Jagielski #if defined(_MSC_VER) && (_MSC_VER >= 1300)
37*b1cdbd2cSJim Jagielski #undef _DEBUG
38*b1cdbd2cSJim Jagielski #endif
39*b1cdbd2cSJim Jagielski #include <atlbase.h>
40*b1cdbd2cSJim Jagielski #include <vector>
41*b1cdbd2cSJim Jagielski #include <hash_map>
42*b1cdbd2cSJim Jagielski #include <tools/postsys.h>
43*b1cdbd2cSJim Jagielski 
44*b1cdbd2cSJim Jagielski #ifdef _MSC_VER
45*b1cdbd2cSJim Jagielski #pragma warning (pop)
46*b1cdbd2cSJim Jagielski #endif
47*b1cdbd2cSJim Jagielski #include <cppuhelper/implbase3.hxx>
48*b1cdbd2cSJim Jagielski #include <cppuhelper/implbase4.hxx>
49*b1cdbd2cSJim Jagielski #include <cppuhelper/implbase7.hxx>
50*b1cdbd2cSJim Jagielski 
51*b1cdbd2cSJim Jagielski #include <com/sun/star/lang/XInitialization.hpp>
52*b1cdbd2cSJim Jagielski #include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp>
53*b1cdbd2cSJim Jagielski #include <rtl/ustring.hxx>
54*b1cdbd2cSJim Jagielski 
55*b1cdbd2cSJim Jagielski #include <com/sun/star/script/XDefaultProperty.hpp>
56*b1cdbd2cSJim Jagielski #include <com/sun/star/script/XDefaultMethod.hpp>
57*b1cdbd2cSJim Jagielski #include <com/sun/star/script/XDirectInvocation.hpp>
58*b1cdbd2cSJim Jagielski 
59*b1cdbd2cSJim Jagielski #include <typelib/typedescription.hxx>
60*b1cdbd2cSJim Jagielski #include "unoconversionutilities.hxx"
61*b1cdbd2cSJim Jagielski #include "windata.hxx"
62*b1cdbd2cSJim Jagielski using namespace cppu;
63*b1cdbd2cSJim Jagielski using namespace rtl;
64*b1cdbd2cSJim Jagielski using namespace std;
65*b1cdbd2cSJim Jagielski using namespace com::sun::star::lang;
66*b1cdbd2cSJim Jagielski using namespace com::sun::star::bridge;
67*b1cdbd2cSJim Jagielski using namespace com::sun::star::bridge::oleautomation;
68*b1cdbd2cSJim Jagielski 
69*b1cdbd2cSJim Jagielski namespace ole_adapter
70*b1cdbd2cSJim Jagielski {
71*b1cdbd2cSJim Jagielski 
72*b1cdbd2cSJim Jagielski 
73*b1cdbd2cSJim Jagielski 
74*b1cdbd2cSJim Jagielski typedef hash_map<OUString, pair<DISPID, unsigned short>, hashOUString_Impl, equalOUString_Impl> DispIdMap;
75*b1cdbd2cSJim Jagielski 
76*b1cdbd2cSJim Jagielski typedef hash_multimap<OUString, unsigned int, hashOUString_Impl, equalOUString_Impl> TLBFuncIndexMap;
77*b1cdbd2cSJim Jagielski 
78*b1cdbd2cSJim Jagielski // This class wraps an IDispatch and maps XInvocation calls to IDispatch calls on the wrapped object.
79*b1cdbd2cSJim Jagielski // If m_TypeDescription is set then this class represents an UNO interface implemented in a COM component.
80*b1cdbd2cSJim Jagielski // The interface is not a real interface in terms of an abstract class but is realized through IDispatch.
81*b1cdbd2cSJim Jagielski class IUnknownWrapper_Impl : public WeakImplHelper7< XInvocation, XBridgeSupplier2, XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod, XDirectInvocation >,
82*b1cdbd2cSJim Jagielski 
83*b1cdbd2cSJim Jagielski 							 public UnoConversionUtilities<IUnknownWrapper_Impl>
84*b1cdbd2cSJim Jagielski 
85*b1cdbd2cSJim Jagielski {
86*b1cdbd2cSJim Jagielski public:
87*b1cdbd2cSJim Jagielski 	IUnknownWrapper_Impl(Reference<XMultiServiceFactory> &xFactory,
88*b1cdbd2cSJim Jagielski                          sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass);
89*b1cdbd2cSJim Jagielski 
90*b1cdbd2cSJim Jagielski 	~IUnknownWrapper_Impl();
91*b1cdbd2cSJim Jagielski 
92*b1cdbd2cSJim Jagielski     //XInterface
93*b1cdbd2cSJim Jagielski 	Any SAL_CALL queryInterface(const Type& t)
94*b1cdbd2cSJim Jagielski         throw (RuntimeException);
95*b1cdbd2cSJim Jagielski 
96*b1cdbd2cSJim Jagielski 	// XInvokation
97*b1cdbd2cSJim Jagielski 	virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection(  )
98*b1cdbd2cSJim Jagielski         throw(RuntimeException);
99*b1cdbd2cSJim Jagielski     virtual Any SAL_CALL invoke( const OUString& aFunctionName,
100*b1cdbd2cSJim Jagielski                                  const Sequence< Any >& aParams,
101*b1cdbd2cSJim Jagielski                                  Sequence< sal_Int16 >& aOutParamIndex,
102*b1cdbd2cSJim Jagielski                                  Sequence< Any >& aOutParam )
103*b1cdbd2cSJim Jagielski         throw(IllegalArgumentException, CannotConvertException,
104*b1cdbd2cSJim Jagielski               InvocationTargetException, RuntimeException);
105*b1cdbd2cSJim Jagielski     virtual void SAL_CALL setValue( const OUString& aPropertyName,
106*b1cdbd2cSJim Jagielski                                     const Any& aValue )
107*b1cdbd2cSJim Jagielski         throw(UnknownPropertyException, CannotConvertException,
108*b1cdbd2cSJim Jagielski               InvocationTargetException, RuntimeException);
109*b1cdbd2cSJim Jagielski     virtual Any SAL_CALL getValue( const OUString& aPropertyName )
110*b1cdbd2cSJim Jagielski         throw(UnknownPropertyException, RuntimeException);
111*b1cdbd2cSJim Jagielski     virtual sal_Bool SAL_CALL hasMethod( const OUString& aName )
112*b1cdbd2cSJim Jagielski         throw(RuntimeException);
113*b1cdbd2cSJim Jagielski     virtual sal_Bool SAL_CALL hasProperty( const OUString& aName )
114*b1cdbd2cSJim Jagielski         throw(RuntimeException);
115*b1cdbd2cSJim Jagielski 
116*b1cdbd2cSJim Jagielski 	// XBridgeSupplier2
117*b1cdbd2cSJim Jagielski 	// This interface is implemented to provide a safe way to obtain the original
118*b1cdbd2cSJim Jagielski 	// IUnknown or IDispatch within the function anyToVariant. The function asks
119*b1cdbd2cSJim Jagielski 	// every UNO object for its XBridgeSupplier2 and if it is available uses it to convert
120*b1cdbd2cSJim Jagielski 	// the object with its own supplier.
121*b1cdbd2cSJim Jagielski 	virtual Any SAL_CALL createBridge( const Any& modelDepObject,
122*b1cdbd2cSJim Jagielski                                        const Sequence< sal_Int8 >& aProcessId,
123*b1cdbd2cSJim Jagielski                                        sal_Int16 sourceModelType,
124*b1cdbd2cSJim Jagielski                                        sal_Int16 destModelType )
125*b1cdbd2cSJim Jagielski         throw(IllegalArgumentException, RuntimeException);
126*b1cdbd2cSJim Jagielski 
127*b1cdbd2cSJim Jagielski 	// XInitialization
128*b1cdbd2cSJim Jagielski     virtual void SAL_CALL initialize( const Sequence< Any >& aArguments )
129*b1cdbd2cSJim Jagielski         throw(Exception, RuntimeException);
130*b1cdbd2cSJim Jagielski 
131*b1cdbd2cSJim Jagielski     // XDefaultProperty
getDefaultPropertyName()132*b1cdbd2cSJim Jagielski     virtual ::rtl::OUString SAL_CALL getDefaultPropertyName(  ) throw (::com::sun::star::uno::RuntimeException) { return m_sDefaultMember; }
133*b1cdbd2cSJim Jagielski 
134*b1cdbd2cSJim Jagielski     // XDefaultMethod
getDefaultMethodName()135*b1cdbd2cSJim Jagielski     virtual ::rtl::OUString SAL_CALL getDefaultMethodName(  ) throw (::com::sun::star::uno::RuntimeException) { return m_sDefaultMember; }
136*b1cdbd2cSJim Jagielski 
137*b1cdbd2cSJim Jagielski     // XDirectInvocation
138*b1cdbd2cSJim Jagielski     virtual ::com::sun::star::uno::Any SAL_CALL directInvoke( const ::rtl::OUString& aName, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aParams ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::script::CannotConvertException, ::com::sun::star::reflection::InvocationTargetException, ::com::sun::star::uno::RuntimeException);
139*b1cdbd2cSJim Jagielski     virtual ::sal_Bool SAL_CALL hasMember( const ::rtl::OUString& aName ) throw (::com::sun::star::uno::RuntimeException);
140*b1cdbd2cSJim Jagielski 
141*b1cdbd2cSJim Jagielski protected:
142*b1cdbd2cSJim Jagielski 	// ----------------------------------------------------------------------------
143*b1cdbd2cSJim Jagielski     virtual Any invokeWithDispIdUnoTlb(const OUString& sFunctionName,
144*b1cdbd2cSJim Jagielski                                        const Sequence< Any >& Params,
145*b1cdbd2cSJim Jagielski                                        Sequence<sal_Int16 >& OutParamIndex,
146*b1cdbd2cSJim Jagielski                                        Sequence< Any >& OutParam);
147*b1cdbd2cSJim Jagielski 	// Is used for OleObjectFactory service
148*b1cdbd2cSJim Jagielski 	virtual Any invokeWithDispIdComTlb(const OUString& sFuncName,
149*b1cdbd2cSJim Jagielski                                        const Sequence< Any >& Params,
150*b1cdbd2cSJim Jagielski                                        Sequence< sal_Int16 >& OutParamIndex,
151*b1cdbd2cSJim Jagielski                                        Sequence< Any >& OutParam);
152*b1cdbd2cSJim Jagielski 
153*b1cdbd2cSJim Jagielski //    virtual void setValueWithDispId(DISPID dispID, const Any& Value);
154*b1cdbd2cSJim Jagielski 
155*b1cdbd2cSJim Jagielski //    virtual Any getValueWithDispId(const OUString& sName, DISPID dispID);
156*b1cdbd2cSJim Jagielski 
157*b1cdbd2cSJim Jagielski 
158*b1cdbd2cSJim Jagielski 	// UnoConversionUtilities -------------------------------------------------------------------------------
159*b1cdbd2cSJim Jagielski 	virtual	Reference<XInterface> createUnoWrapperInstance();
160*b1cdbd2cSJim Jagielski 	virtual Reference<XInterface> createComWrapperInstance();
161*b1cdbd2cSJim Jagielski 
162*b1cdbd2cSJim Jagielski     /**Obtains a FUNCDESC structure for a function.
163*b1cdbd2cSJim Jagielski        Fills the FUNCDESC structure if ITypeInfo provides information for
164*b1cdbd2cSJim Jagielski        the function of name sFuncName or pFuncDesc will not be filled in.
165*b1cdbd2cSJim Jagielski        May throw a BridgeRuntimeError.
166*b1cdbd2cSJim Jagielski      */
167*b1cdbd2cSJim Jagielski     void getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc);
168*b1cdbd2cSJim Jagielski     /**Obtains a FUNCDESC structures or a VARDESC structure
169*b1cdbd2cSJim Jagielski        for a property. pFuncDescPut may also contain
170*b1cdbd2cSJim Jagielski        a structure for a "propertyputref" operation. If pFuncDesc contains a
171*b1cdbd2cSJim Jagielski        "put ref" or "put" FUNCDESC depends on what was found first in the type
172*b1cdbd2cSJim Jagielski        description.
173*b1cdbd2cSJim Jagielski        Fills the FUNCDESC structure if ITypeInfo provides information for
174*b1cdbd2cSJim Jagielski        the respective property functions or the structures will not be filled in.
175*b1cdbd2cSJim Jagielski        May throw a BridgeRuntimeError.
176*b1cdbd2cSJim Jagielski      */
177*b1cdbd2cSJim Jagielski     void getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet,
178*b1cdbd2cSJim Jagielski                      FUNCDESC** pFuncDescPut, VARDESC ** pVarDesc);
179*b1cdbd2cSJim Jagielski 	// These functions are for the case if an object of this class wraps an IDispatch
180*b1cdbd2cSJim Jagielski 	// object that implements UNO interfaces. In that case the member m_seqTypes
181*b1cdbd2cSJim Jagielski 	// is set through XInitialization::initialize.
182*b1cdbd2cSJim Jagielski 	void getMethodInfo(const OUString& sName, TypeDescription& methodDescription);
183*b1cdbd2cSJim Jagielski 	// After return attributInfo contains typelib_InterfaceAttributeTypeDescription::pAttributeTypeRef
184*b1cdbd2cSJim Jagielski 	void getAttributeInfo(const OUString& sName, TypeDescription& attributeInfo);
185*b1cdbd2cSJim Jagielski 	// used by get MethodInfo
186*b1cdbd2cSJim Jagielski 	TypeDescription	 getInterfaceMemberDescOfCurrentCall(const OUString& sName);
187*b1cdbd2cSJim Jagielski     /** Returns alway a valid ITypeInfo interface or throws a BridgeRuntimeError.
188*b1cdbd2cSJim Jagielski         The returned interface does not need to be AddRef'ed as long as it is locally
189*b1cdbd2cSJim Jagielski         used. The interface is kept in the instance of this class.
190*b1cdbd2cSJim Jagielski      */
191*b1cdbd2cSJim Jagielski 	ITypeInfo*	getTypeInfo();
192*b1cdbd2cSJim Jagielski 
193*b1cdbd2cSJim Jagielski 	/** Returns the DISPID for a function or property name. If true is returned then
194*b1cdbd2cSJim Jagielski 		id contains a valid DISPID.
195*b1cdbd2cSJim Jagielski 	*/
196*b1cdbd2cSJim Jagielski 	bool getDispid(const OUString& sFuncName, DISPID * id);
197*b1cdbd2cSJim Jagielski 
198*b1cdbd2cSJim Jagielski 	/** Gets the element type in a VARIANT like style. E.g. if desc->lptdesc contains
199*b1cdbd2cSJim Jagielski 		a VT_PTR than it is replaced by VT_BYREF and VT_SAFEARRAY is replaced by VT_ARRAY
200*b1cdbd2cSJim Jagielski 		If the TYPEDESC describes an SAFEARRAY then varType is a combination of VT_ARRAY
201*b1cdbd2cSJim Jagielski 		and the element type.
202*b1cdbd2cSJim Jagielski 		The argument desc must be obtained from FUNCDESC::lprgelemdescParam[i].tdesc where
203*b1cdbd2cSJim Jagielski 		FUNCDESC was obtained from the ITypeInfo belonging to wrapped IDispatch.
204*b1cdbd2cSJim Jagielski 	*/
205*b1cdbd2cSJim Jagielski 	VARTYPE getElementTypeDesc( const TYPEDESC *desc);
206*b1cdbd2cSJim Jagielski 	/** Iterates over all functions and put the names and indices into the map
207*b1cdbd2cSJim Jagielski         m_mapComFunc of type TLBFuncIndexMap.
208*b1cdbd2cSJim Jagielski         Call the function every time before accessing the map.
209*b1cdbd2cSJim Jagielski         Throws a BridgeRuntimeError on failure.
210*b1cdbd2cSJim Jagielski     */
211*b1cdbd2cSJim Jagielski 	void  buildComTlbIndex();
212*b1cdbd2cSJim Jagielski 
213*b1cdbd2cSJim Jagielski     /** Returns a FUNCDESC structure which contains type information about the
214*b1cdbd2cSJim Jagielski         current XInvocation::invoke call. The FUNCDESC either describes a method,
215*b1cdbd2cSJim Jagielski         a property put or a property get operation.
216*b1cdbd2cSJim Jagielski         It uses the types  com.sun.star.bridge.oleautomation.PropertyPutArgument
217*b1cdbd2cSJim Jagielski         which can be
218*b1cdbd2cSJim Jagielski         contained in the sequence of in-arguments of invoke to determine if the call is
219*b1cdbd2cSJim Jagielski         a property put or property get operation.
220*b1cdbd2cSJim Jagielski         If no adequate FUNCDESC was found, an IllegalArgumentException is thrown.
221*b1cdbd2cSJim Jagielski         Therefore it is safe to assume that the returned FUNCDESC* is not NULL.
222*b1cdbd2cSJim Jagielski 
223*b1cdbd2cSJim Jagielski         @exception IllegalArgumentException
224*b1cdbd2cSJim Jagielski         Thrown if no adequate FUNCDESC could be found.
225*b1cdbd2cSJim Jagielski     */
226*b1cdbd2cSJim Jagielski     void getFuncDescForInvoke(const OUString & sFuncName,
227*b1cdbd2cSJim Jagielski                               const Sequence<Any> & seqArgs, FUNCDESC** pFuncDesc);
228*b1cdbd2cSJim Jagielski 
229*b1cdbd2cSJim Jagielski     // Finds out wheter the wrapped IDispatch is an JScript Object. This is is
230*b1cdbd2cSJim Jagielski 	// done by
231*b1cdbd2cSJim Jagielski 	// asking for the property "_environment". If it has the value "JScript"
232*b1cdbd2cSJim Jagielski 	// (case insensitive) then the IDispatch is considered a JScript object.
233*b1cdbd2cSJim Jagielski 	sal_Bool isJScriptObject();
234*b1cdbd2cSJim Jagielski 	// -------------------------------------------------------------------------------
235*b1cdbd2cSJim Jagielski 
236*b1cdbd2cSJim Jagielski 	// If UNO interfaces are implemented in JScript objects, VB or C++ COM objects
237*b1cdbd2cSJim Jagielski 	// and those are passed as parameter to a UNO interface function, then
238*b1cdbd2cSJim Jagielski 	// the IDispatch* are wrapped by objects of this class. Assuming that the functions
239*b1cdbd2cSJim Jagielski 	// implemented by the IDispatch object returns another UNO interface then
240*b1cdbd2cSJim Jagielski 	// it has to be wrapped to this type. But this is only possible if an object of this
241*b1cdbd2cSJim Jagielski 	// wrapper class knows what type it is represting. The member m_TypeDescription holds this
242*b1cdbd2cSJim Jagielski 	// information.
243*b1cdbd2cSJim Jagielski 	// m_TypeDescription is only useful when an object wraps an IDispatch object that implements
244*b1cdbd2cSJim Jagielski 	// an UNO interface. The value is set during a call to XInitialization::initialize.
245*b1cdbd2cSJim Jagielski 	Sequence<Type> m_seqTypes;
246*b1cdbd2cSJim Jagielski 	CComPtr<IUnknown> m_spUnknown;
247*b1cdbd2cSJim Jagielski 	CComPtr<IDispatch> m_spDispatch;
248*b1cdbd2cSJim Jagielski         rtl::OUString m_sTypeName; // is "" ( not initialised ), "IDispatch" ( we have no idea ) or "SomeLibrary.SomeTypeName" if we managed to get a type
249*b1cdbd2cSJim Jagielski     /** This value is set dureing XInitialization::initialize. It indicates that the COM interface
250*b1cdbd2cSJim Jagielski     was transported as VT_DISPATCH in a VARIANT rather then a VT_UNKNOWN
251*b1cdbd2cSJim Jagielski     */
252*b1cdbd2cSJim Jagielski     sal_Bool  m_bOriginalDispatch;
253*b1cdbd2cSJim Jagielski 	DispIdMap 			m_dispIdMap;
254*b1cdbd2cSJim Jagielski 	Reference<XIdlClass>*		m_pxIdlClass;
255*b1cdbd2cSJim Jagielski 
256*b1cdbd2cSJim Jagielski 
257*b1cdbd2cSJim Jagielski 	// used by isJScriptObject
258*b1cdbd2cSJim Jagielski 	enum JScriptDetermination{ JScriptUndefined=0, NoJScript, IsJScript};
259*b1cdbd2cSJim Jagielski 	JScriptDetermination m_eJScript;
260*b1cdbd2cSJim Jagielski 	// The map is filled by buildComTlbIndex
261*b1cdbd2cSJim Jagielski     // It maps Uno Function names to an index which is used in ITypeInfo::GetFuncDesc
262*b1cdbd2cSJim Jagielski 	TLBFuncIndexMap m_mapComFunc;
263*b1cdbd2cSJim Jagielski     // used for synchroizing the computation of the content for m_mapComFunc
264*b1cdbd2cSJim Jagielski     bool m_bComTlbIndexInit;
265*b1cdbd2cSJim Jagielski 	// Keeps the ITypeInfo obtained from IDispatch::GetTypeInfo
266*b1cdbd2cSJim Jagielski 	CComPtr< ITypeInfo > m_spTypeInfo;
267*b1cdbd2cSJim Jagielski     rtl::OUString m_sDefaultMember;
268*b1cdbd2cSJim Jagielski     bool m_bHasDfltMethod;
269*b1cdbd2cSJim Jagielski     bool m_bHasDfltProperty;
270*b1cdbd2cSJim Jagielski };
271*b1cdbd2cSJim Jagielski 
272*b1cdbd2cSJim Jagielski } // end namespace
273*b1cdbd2cSJim Jagielski #endif
274*b1cdbd2cSJim Jagielski 
275