#ifndef _Ole_Ctrl_OleCtrl_h_
#define _Ole_Ctrl_OleCtrl_h_

#include <CtrlCore/CtrlCore.h>
#include <Ole/Ole.h>

#define OCXLOG RLOG    // redefine to RLOG if you want logs in retail versions

#ifdef _DEBUG
#define LOG_SYSOCXS 1 // 1 = log system calls (DllCanUnloadNow, DllGetClassObject)
#define LOG_METHODS 1 // 1 = log method calls
#define LOG_CREATES 1 // 1 = log instance creations & destructions
#define LOG_QUERIES 1 // 1 = log failed QueryInterface's
//                    // 2 = log all QueryInterface's
//                    // 3 = dump interface map whenever Query fails
#define LOG_PERSIST 1 // 1 = log saves / loads
#define LOG_RESULTS 1 // 1 = log error results
//                    // 2 = log all results
#define LOG_ADDREFS 1 // 1 = log AddRef's / Releases
#define LOG_INVOKES 1 // 1 = log IDispatch::Invoke
#else
#define LOG_SYSOCXS 1
#define LOG_METHODS 0
#define LOG_CREATES 0
#define LOG_QUERIES 0
#define LOG_PERSIST 0
#define LOG_RESULTS 0
#define LOG_ADDREFS 0
#define LOG_INVOKES 0
#endif

#if LOG_SYSOCXS >= 1
#define LOGSYSOCX(x) OCXLOG(x)
#else
#define LOGSYSOCX(x)
#endif

#if LOG_METHODS >= 1
#define LOGMETHOD(x) OCXLOG(x)
#else
#define LOGMETHOD(x)
#endif

#if LOG_CREATES >= 1
#define LOGCREATE(x) OCXLOG(x)
#else
#define LOGCREATE(x)
#endif

#if LOG_QUERIES >= 1
#define LOGQUERY(x) OCXLOG(x)
#else
#define LOGQUERY(x)
#endif

#if LOG_PERSIST >= 1
#define LOGPERSIST(x) OCXLOG(x)
#else
#define LOGPERSIST(x)
#endif

#if LOG_RESULTS >= 2
#define LOGRESULT(x) LogResult((x))
#elif LOG_RESULTS >= 1
#define LOGRESULT(x) LogError((x))
#else
#define LOGRESULT(x) (x)
#endif

#if LOG_INVOKES >= 1
#define LOGINVOKE(x) OCXLOG(x)
#else
#define LOGINVOKE(x)
#endif

typedef void (*InitProc)();
InitProc& LateInitProc();

#define OCX_APP_MAIN \
void _DllMainAppInit(); \
\
static void _DllMainLateInit() \
{ \
	RLOGBLOCK("_DllMainLateInit"); \
	RLOG("Ctrl::InitWin32"); \
	Ctrl::InitWin32(AppGetHandle()); \
	RLOG("AppInitEnvironment"); \
	AppInitEnvironment__(); \
	RLOG("DllMainAppInit"); \
	_DllMainAppInit(); \
} \
\
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpReserved) \
{ \
	if(fdwReason == DLL_PROCESS_ATTACH) { \
		AppSetHandle(hinstDll); \
		SetVppLogName(ForceExt(GetExeFilePath(), ".log")); \
	} \
	RLOG("DllMain(" << FormatIntHex(hinstDll) << ", reason = " << (int)fdwReason << ")"); \
	if(fdwReason == DLL_PROCESS_ATTACH) { \
		LateInitProc() = &_DllMainLateInit; \
	} \
	RLOG("//DllMain(" << FormatIntHex(hinstDll) << ", reason = " << (int)fdwReason << ")"); \
	return true; \
} \
\
void _DllMainAppInit()

/*
_variant_t ValueToVariant(const Value& v);
Value      DispatchToValue(IDispatch *disp);
Value      UnknownToValue(IUnknown *unk);
void       ReturnVariant(VARIANT *var, const Value& v);
HRESULT    CheckReturnString(BSTR *bstr, const String& s);
Color      PackColor(long rgb);
long       UnpackColor(Color c);
HRESULT    CheckReturnColor(long *ptr, Color c);
*/

#define std_method      HRESULT STDMETHODCALLTYPE
#define void_method     void    STDMETHODCALLTYPE

class OcxTypeInfo;

typedef VectorMap<Guid, void *> InterfaceMap;

template <class T>
inline void AddInterfaceRaw(InterfaceMap& map, T *iface)
{
	map.FindAdd(__uuidof(T), iface);
}

template <class T>
inline void AddInterface(InterfaceMap& map, T *iface)
{
	AddInterfaceRaw<T>(map, iface);
}

#define PARENT_INTERFACE(clss, base) \
template <> \
inline void AddInterface(InterfaceMap& map, clss *iface) \
{ \
	AddInterfaceRaw<clss>(map, iface); \
	AddInterface<base>(map, iface); \
}

PARENT_INTERFACE(IProvideClassInfo2, IProvideClassInfo)
PARENT_INTERFACE(IViewObject2, IViewObject)
PARENT_INTERFACE(IViewObjectEx, IViewObject2)
PARENT_INTERFACE(IOleInPlaceObject, IOleWindow)
PARENT_INTERFACE(IOleInPlaceObjectWindowless, IOleInPlaceObject)
PARENT_INTERFACE(IOleInPlaceActiveObject, IOleWindow)
PARENT_INTERFACE(IPersistStorage, IPersist)
PARENT_INTERFACE(IPersistStream, IPersist)
PARENT_INTERFACE(IPersistFile, IPersist)

class OcxObject
{
	friend class OcxTypeInfo;

public:
	OcxObject() : ocx_info(0) {}

	IUnknown          *GetUnknown();

	HRESULT            RawQueryInterface(const GUID& iid, void **ppv);
	HRESULT            RawGetTypeInfoCount(unsigned *pctinfo) { *pctinfo = 1; return S_OK; }
	HRESULT            RawGetTypeInfo(unsigned tinfo, LCID lcid, ITypeInfo **ppinfo);
	HRESULT            RawGetIDsOfNames(REFIID riid, OLECHAR **names, unsigned cnames, LCID lcid, DISPID *dispid);
	HRESULT            RawInvoke(IDispatch *disp, DISPID dispid, word flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep, unsigned *arg_err);

#if LOG_ADDREFS
	virtual int        AddRef0(const char *name) = 0;
	virtual int        Release0(const char *name) = 0;
#endif

	static const char *GetObjectName()   { return ""; }          // programmatic object name (synthetic = <ocx name>.<class name>)
	static const char *GetObjectHelp()   { return ""; }          // user-visible object name (synthetic = <class name> (CONTROL ? " Control " | " Object ") <version>
	static GUID        GetDispatchGUID() { return __uuidof(0); } // default ingoing dispatch interface
	static GUID        GetEventGUID()    { return __uuidof(0); } // default outgoing dispatch interface

	enum
	{
		VERSION = 0,
		CONTROL = 0, // override with 1 to make a control class
	};

protected:
	OcxTypeInfo       *ocx_info;
	InterfaceMap       interface_map;
};

template <class I>
class Interface : public I, virtual public OcxObject
{
public:
	Interface() { AddInterface<I>(interface_map, this); }

#if LOG_ADDREFS
	virtual ULONG STDMETHODCALLTYPE AddRef()          { return AddRef0(typeid(I).name()); }
	virtual ULONG STDMETHODCALLTYPE Release()         { return Release0(typeid(I).name()); }
#endif
};

template <class I>
class DispatchInterface : public Interface<I>
{
public:
	DispatchInterface() { AddInterface<IDispatch>(interface_map, this); }
	static GUID GetDispatchGUID() { return __uuidof(I); }

	// IDispatch

	STDMETHOD(GetTypeInfoCount)(unsigned *pctinfo) { return RawGetTypeInfoCount(pctinfo); }
	STDMETHOD(GetTypeInfo)(unsigned tinfo, LCID lcid, ITypeInfo **ppinfo) { return RawGetTypeInfo(tinfo, lcid, ppinfo); }
	STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR **names, unsigned cnames, LCID lcid, DISPID *dispid) { return RawGetIDsOfNames(riid, names, cnames, lcid, dispid); }
	STDMETHOD(Invoke)(DISPID dispid, REFIID riid, LCID lcid, word flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *excep, unsigned *arg_err) { return RawInvoke(static_cast<I *>(this), dispid, flags, params, result, excep, arg_err); }
};

class OcxProvideClassInfo : public Interface<IProvideClassInfo2>
{
public:
	// IProvideClassInfo

	STDMETHOD(GetClassInfo)(ITypeInfo **info);

	// IProvideClassInfo2

	STDMETHOD(GetGUID)(dword guidkind, GUID *guid);
};

template <class T>
class OcxObjectWrapper : public T
{
public:
	OcxObjectWrapper() : refcount(0) {}
	OcxObjectWrapper(OcxTypeInfo& _ocx_info) : refcount(0) { ocx_info = &_ocx_info; _ocx_info.object_count++; }

	static IUnknown      *New()                       { return (new OcxObjectWrapper<T>())->GetUnknown(); }
	static IUnknown      *New(OcxTypeInfo& _ocx_info) { return (new OcxObjectWrapper<T>(_ocx_info))->GetUnknown(); }

	STDMETHOD(QueryInterface)(REFIID iid, void **ppv) { return RawQueryInterface(iid, ppv); }

	static String         GetName();

#if LOG_ADDREFS
	virtual int           AddRef0(const char *iface);
	virtual int           Release0(const char *iface);
#else
	virtual ULONG STDMETHODCALLTYPE AddRef()          { return ++refcount; }
	virtual ULONG STDMETHODCALLTYPE Release()         { ULONG u = --refcount; if(!u) Destroy(); return u; }
#endif

private:
	void                  Destroy();

private:
	ULONG                 refcount;
};

#if LOG_ADDREFS
template <class T>
int OcxObjectWrapper<T>::AddRef0(const char *iface)
{
	++refcount;
	RLOG("[" << GetTypeName(typeid(*this)) << "] " << iface << "::AddRef(" << refcount << ")");
	return refcount;
}
#endif

#if LOG_ADDREFS
template <class T>
int OcxObjectWrapper<T>::Release0(const char *iface)
{
	int u = --refcount;
	RLOG("[" << GetTypeName(typeid(*this)) << "] " << iface << "::Release(" << refcount << ")");
	if(!u)
		Destroy();
	return u;
}
#endif

template <class T>
String OcxObjectWrapper<T>::GetName()
{
	if(*T::GetObjectName())
		return T::GetObjectName();
	return GetTypeName(typeid(T));
}

template <class T>
void OcxObjectWrapper<T>::Destroy()
{
	if(ocx_info)
	{
		ocx_info->object_count--;
		LOGCREATE("\tdelete " << GetTypeName(typeid(T)) << ": "
			<< (int)ocx_info->object_count << " instances left in system");
	}
	else
		LOGCREATE("\tdelete " << GetTypeName(typeid(T)));
	delete this;
}

class OcxTypeInfo : public Interface<IClassFactory>
{
	friend class OcxTypeLib;

public:
	typedef IUnknown *(*New)(OcxTypeInfo& entry);

	OcxTypeInfo(const GUID& coclass_guid, const GUID& dispatch_guid, const GUID& event_guid,
		New new_fn, String name, const char* help = "", int ver = 0,
		bool is_control = false);

	bool            IsControl() const       { return is_control; }
	bool            CanUnload() const       { return object_count == 0 && refcount <= 1 && lock_count <= 0; }

	const Guid&     GetCoClassGUID() const  { return coclass_guid; }
	const Guid&     GetDispatchGUID() const { return dispatch_guid; }
	const Guid&     GetEventGUID() const    { return event_guid; }

	String          GetName() const         { return name; }

	IRef<ITypeInfo> GetDispatchTypeInfo();
	IRef<ITypeInfo> GetCoClassTypeInfo();

	// IUnknown

#if LOG_ADDREFS
	virtual int     AddRef0(const char *iface)  { return IncRef(); }
	virtual int     Release0(const char *iface) { return DecRef(); }
#else
	virtual ULONG   STDMETHODCALLTYPE AddRef()    { return IncRef(); }
	virtual ULONG   STDMETHODCALLTYPE Release()   { return DecRef(); }
#endif
	STDMETHOD(QueryInterface)(REFIID iid, void **ppv) { return RawQueryInterface(iid, ppv); }

	// IClassFactory

	STDMETHOD(CreateInstance)(IUnknown *outer, REFIID iid, void **object);
	STDMETHOD(LockServer)(BOOL lock);

public:
	long            object_count;  // managed object count
	IRef<ITypeInfo> coclass_info;  // coclass type info
	IRef<ITypeInfo> dispatch_info; // ingoing dispatch interface type info
	CriticalSection critical;      // critical section used for initializations

private:
	int             IncRef();
	int             DecRef();

private:
	Guid            coclass_guid;  // coclass GUID
	Guid            dispatch_guid; // GUID of default ingoing dispatch interface
	Guid            event_guid;    // GUID of default outgoing dispatch interface
	New             new_fn;        // constructor
	String          name;          // programmatic object name - <ocx name>.<class name>.<version> by default
	const char     *help;          // user-visible object name - <class name> (" Control " | " Object ") <version> by default
	int             ver;           // 0 = use main library version
	bool            is_control;    // false = generic object, true = insertable control

	long            refcount;      // AddRef/Release counter
	Atomic          lock_count;    // LockServer lock count

#ifndef _USRDLL
	dword           registration;  // for CoRevokeClassObject
#endif
};

class OcxTypeLib
{
public:
	static OcxTypeLib&     Get();

	OcxTypeLib&            Name(String name)           { lib_name = name; return *this; }
	String                 GetName() const             { return lib_name; }
	OcxTypeLib&            DisplayName(String dn)      { display_name = dn; return *this; }
	String                 GetDisplayName() const      { return display_name; }
	String                 GetLibName() const;

	OcxTypeLib&            Version(int _ver)           { lib_ver  = _ver; return *this; }
	int                    GetVersion() const          { return lib_ver; }

	HRESULT                Register();
	HRESULT                Unregister();
	HRESULT                GetFactory(REFCLSID clsid, REFIID iid, void **ppv);
	bool                   CanUnload() const;
#ifndef _USRDLL
	HRESULT                RegisterObjects(); // call CoRegisterClassObject for each object
	void                   RevokeObjects();   // call CoRevokeClassObject
#endif

	void                   Add(OcxTypeInfo& entry)     { objects.FindAdd(entry.coclass_guid, &entry); }
	void                   AddInit(void (*fn)())       { ocx_init.Add(fn); }

	IRef<ITypeLib>&        GetTypeLib();
	IRef<ITypeLib>&        operator -> ()              { return GetTypeLib(); }

public:
	IRef<ITypeLib>         typelib;
	CriticalSection        critical;

private:
	OcxTypeLib();

private:
	VectorMap<Guid, OcxTypeInfo *> objects;
	Vector<void (*)()>     ocx_init;
	String                 lib_name;
	String                 display_name;
	int                    lib_ver;
};

struct OcxInit { OcxInit(void (*fn)()) { OcxTypeLib::Get().AddInit(fn); } };
#define OCX_INIT(fn) static OcxInit MK__s = fn;

#define OCX_OBJECT(type) \
	static OcxTypeInfo MK__s( \
		__uuidof(type),                    /* coclass GUID */ \
		type::GetDispatchGUID(),           /* default ingoing dispatch interface GUID */ \
		type::GetEventGUID(),              /* default outgoing dispatch interface GUID */ \
		OcxObjectWrapper<type>::New,       /* constructor */ \
		OcxObjectWrapper<type>::GetName(), /* name */ \
		type::GetObjectHelp(),             /* help */ \
		type::VERSION,                     /* version */ \
		type::CONTROL);                    /* control object */

#define OCX_NEWOBJECT(type) \
	OCX_OBJECT(type) \
	static IRef<type> COMBINE(OcxNew_, type)() { return new OcxObjectWrapper<type>(MK__s); }

Size ToHiMetric(Size pixel_size);
Size FromHiMetric(Size himetric_size);
Rect GetWindow(HDC hdc);
Rect GetViewport(HDC hdc);

word        *AllocString(String s);

template <class T>
class SinkMap : public VectorMap<dword, T>
{
public:
	typedef VectorMap<dword, T> Base;
	SinkMap() : next_sink_id(0) {}
	dword Add(const T& object) { Base::Add(++next_sink_id, object); return next_sink_id; }
	bool  Remove(dword id)     { int i = Find(id); return (i >= 0 ? (Base::Remove(i), true) : false); }

private:
	dword next_sink_id;
};

//template OleType<IAdviseSinkPtr>;

class OcxControl : public Ctrl,
	public Interface<IOleInPlaceActiveObject>,
	public Interface<IOleInPlaceObject>,
	public Interface<IViewObjectEx>,
	public Interface<IDataObject>,
	public Interface<IPersistStorage>,
	public Interface<IPersistStreamInit>,
	public Interface<IOleObject>,
	public Interface<IOleControl>,
	public Interface<IPointerInactive>,
	public OcxProvideClassInfo
{
public:
	OcxControl();
	virtual ~OcxControl();

	virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
	bool            Open(HWND parent);
	virtual void    Serialize(Stream& stream);
	void            SerializePos(Stream& stream);

	virtual bool    IsOcxChild();

	using Ctrl::GetRect;
	using Ctrl::SetData;
	using Ctrl::GetData;

	// IOleObject

	STDMETHOD(SetClientSite)(IOleClientSite *site);
	STDMETHOD(GetClientSite)(IOleClientSite **res);
	STDMETHOD(SetHostNames)(const word * app_name, const word *doc_name);
	STDMETHOD(Close)(dword save_option);
	STDMETHOD(SetMoniker)(dword which, IMoniker *moniker);
	STDMETHOD(GetMoniker)(dword assign, dword which, IMoniker **moniker);
	STDMETHOD(InitFromData)(IDataObject *data, BOOL creation, dword);
	STDMETHOD(GetClipboardData)(dword, IDataObject **data);
	STDMETHOD(DoVerb)(long verb, MSG *msg, IOleClientSite *active_site, long index, HWND hwnd, const RECT *rc);
	STDMETHOD(EnumVerbs)(IEnumOLEVERB **verbs);
	STDMETHOD(Update)();
	STDMETHOD(IsUpToDate)();
	STDMETHOD(GetUserClassID)(GUID *guid);
	STDMETHOD(GetUserType)(dword form, word **type);
	STDMETHOD(SetExtent)(dword aspect, SIZEL *size);
	STDMETHOD(GetExtent)(dword aspect, SIZEL *size);
	STDMETHOD(Advise)(IAdviseSink *sink, dword *connection);
	STDMETHOD(Unadvise)(dword connection);
	STDMETHOD(EnumAdvise)(IEnumSTATDATA **sink_enum);
	STDMETHOD(GetMiscStatus)(dword aspect, dword *status);
	STDMETHOD(SetColorScheme)(LOGPALETTE *logpal);

	// IPersistStorage

	STDMETHOD(GetClassID)(GUID *guid);
	STDMETHOD(IsDirty)(); // IPersistStreamInit as well
	STDMETHOD(InitNew)(IStorage *stg);
	STDMETHOD(Load)(IStorage *stg);
	STDMETHOD(Save)(IStorage *stg, BOOL same_as_load);
	STDMETHOD(SaveCompleted)(IStorage *stg);
	STDMETHOD(HandsOffStorage)();

	// IPersistStreamInit

	STDMETHOD(Load)(IStream *stream);
	STDMETHOD(Save)(IStream *stream, BOOL clear_dirty);
	STDMETHOD(GetSizeMax)(ULARGE_INTEGER *size);
	STDMETHOD(InitNew)();

	// IDataObject

	STDMETHOD(GetData)(FORMATETC *format, STGMEDIUM *medium);
	STDMETHOD(GetDataHere)(FORMATETC *format, STGMEDIUM *medium);
	STDMETHOD(QueryGetData)(FORMATETC *format);
	STDMETHOD(GetCanonicalFormatEtc)(FORMATETC *in, FORMATETC *out);
	STDMETHOD(SetData)(FORMATETC *format, STGMEDIUM *medium, BOOL free);
	STDMETHOD(EnumFormatEtc)(dword dir, IEnumFORMATETC **enumerator);
	STDMETHOD(DAdvise)(FORMATETC *format, dword advf, IAdviseSink *sink, dword *connection);
	STDMETHOD(DUnadvise)(dword connection);
	STDMETHOD(EnumDAdvise)(IEnumSTATDATA **enumerator);

	// IViewObject

	STDMETHOD(Draw)(dword aspect, long index, void *aspectinfo,
		DVTARGETDEVICE *device, HDC target, HDC draw,
		const RECTL *bounds, const RECTL *wbounds,
		BOOL (STDMETHODCALLTYPE *progress)(dword arg), dword arg);
	STDMETHOD(GetColorSet)(dword aspect, long index, void *aspectinfo,
		DVTARGETDEVICE *device, HDC target, LOGPALETTE **palette);
	STDMETHOD(Freeze)(dword aspect, long index, void *aspectinfo,
		dword *freeze_key);
	STDMETHOD(Unfreeze)(dword freeze_key);
	STDMETHOD(SetAdvise)(dword aspect, dword advf, IAdviseSink *sink);
	STDMETHOD(GetAdvise)(dword *aspect, dword *advf, IAdviseSink **sink);

	// IViewObject2

	STDMETHOD(GetExtent)(dword aspect, long index, DVTARGETDEVICE *device, SIZEL *size);

	// IViewObjectEx

	STDMETHOD(GetRect)(dword aspect, RECTL *rc);
	STDMETHOD(GetViewStatus)(dword *status);
	STDMETHOD(QueryHitPoint)(dword aspect, const RECT *bounds, POINT pos, long close_hint, dword *result);
	STDMETHOD(QueryHitRect)(dword aspect, const RECT *bounds, const RECT *, long close_hint, dword *result);
	STDMETHOD(GetNaturalExtent)(dword aspect, long index, DVTARGETDEVICE *ptd, HDC tdc, DVEXTENTINFO *extinfo, SIZEL *psize);

	// IOleWindow

	STDMETHOD(GetWindow)(HWND *hwnd);
	STDMETHOD(ContextSensitiveHelp)(BOOL enter_mode);

	// IOleInPlaceObject

	STDMETHOD(InPlaceDeactivate)();
	STDMETHOD(UIDeactivate)();
	STDMETHOD(SetObjectRects)(const RECT *pos, const RECT *clip);
	STDMETHOD(ReactivateAndUndo)();

	// IOleInPlaceActiveObject

	STDMETHOD(TranslateAccelerator)(MSG *msg);
	STDMETHOD(OnFrameWindowActivate)(BOOL activate);
	STDMETHOD(OnDocWindowActivate)(BOOL activate);
	STDMETHOD(ResizeBorder)(const RECT *border, IOleInPlaceUIWindow *ui, BOOL frame);
	STDMETHOD(EnableModeless)(BOOL enable);

	// IOleControl

	STDMETHOD(GetControlInfo)(CONTROLINFO *cinfo);
	STDMETHOD(OnMnemonic)(MSG *msg);
	STDMETHOD(OnAmbientPropertyChange)(DISPID dispid);
	STDMETHOD(FreezeEvents)(BOOL freeze);

	// IPointerInactive

	STDMETHOD(GetActivationPolicy)(DWORD *pdwPolicy);
	STDMETHOD(OnInactiveMouseMove)(LPCRECT pRectBounds, LONG x, LONG y, DWORD grfKeyState);
	STDMETHOD(OnInactiveSetCursor)(LPCRECT pRectBounds, LONG x, LONG y, DWORD dwMouseMsg, BOOL fSetAlways);

	// default verb

	virtual HRESULT DoVerbPrimary();
	virtual HRESULT DoVerbShow();
	virtual HRESULT DoVerbInPlaceActivate();
	virtual HRESULT DoVerbUIActivate();
	virtual HRESULT DoVerbOpen();
	virtual HRESULT DoVerbHide();
	virtual HRESULT DoVerbDiscardUndo();
	virtual HRESULT DoVerbProperties();

	// various helpers

	bool            IsClosed() const            { return status == CLOSED; }
//	bool            IsForged() const            { return status == FORGED; }
	bool            IsActive() const            { return status >= ACTIVE; }
	bool            IsUIActive() const          { return status == UIACTIVE; }

	void            RefreshSink();

	enum { CONTROL = 1 };

protected:
	void            UpdateControlRect();
	HRESULT         ShowControl(bool ui_activate);
	void            SetActiveObject(bool set);

	void            TimerThread();

protected:
	static const WCHAR data_stream_name[]; // default data stream

	enum STATE { CLOSED, /* FORGED, */ ACTIVE, UIACTIVE };

	Thread                       timer_thread;
	IRef<IOleClientSite>         client_site;
	IRef<IOleInPlaceSite>        in_place_site;
	SinkMap< IRef<IAdviseSink> > advise_sinks;
	dword                        view_sink_aspect;
	dword                        view_sink_advf;
	IRef<IAdviseSink>            view_sink;
	Rect                         ctrl_rect;
	STATE                        status;
	bool                         stream_inited;
	bool                         timer_shutdown;
};

class OcxRunnableControl : public OcxControl, public Interface<IRunnableObject>
{
public:
	OcxRunnableControl() {}

	// IRunnableObject

	STDMETHOD(GetRunningClass)(GUID *clsid);
	STDMETHOD(Run)(LPBC ctx);
	BOOL STDMETHODCALLTYPE IsRunning();
	STDMETHOD(LockRunning)(BOOL lock, BOOL last_unlock_closes);
	STDMETHOD(SetContainedObject)(BOOL contained);
};

/*
struct CtrlHook : public Ctrl
{
public:
	void _CreateChild() { Ctrl::CreateChild(); }
};
*/

class OcxConnectionPoint : public Interface<IConnectionPoint>
{
public:
	OcxConnectionPoint() {}

	void SetEventGUID(const Guid& g)                   { guid = g; }
	void SetContainer(IConnectionPointContainer *cont) { container = cont; }
	void FireEvent(int method_id, const Vector<Value>& values);

	STDMETHOD(GetConnectionInterface)(IID *iid);
	STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer **ppCPC);
	STDMETHOD(Advise)(IUnknown *ptr, DWORD *cookie);
	STDMETHOD(Unadvise)(DWORD cookie);
	STDMETHOD(EnumConnections)(IEnumConnections **enum_conn);

	class Enumerator : public Interface<IEnumConnections>
	{
	public:
		Enumerator() {}

		void            Attach(OcxConnectionPoint *pt) { point = IRef<OcxConnectionPoint>(pt); index = 0; }

		STDMETHOD(Next)(unsigned long count, CONNECTDATA *data, unsigned long *fetched);
		STDMETHOD(Skip)(unsigned long connections);
		STDMETHOD(Reset)();
		STDMETHOD(Clone)(IEnumConnections **enum_conn);

	private:
		IRef<OcxConnectionPoint> point;
		int                          index;
	};

	friend class Enumerator;

public:
	Guid                               guid;

protected:
	IConnectionPointContainer         *container;
	VectorMap<dword, IRef<IDispatch> > conn_map;
	Vector<dword>                      free_id;
};

class OcxConnectionPointContainer : public Interface<IConnectionPointContainer>
{
public:
	OcxConnectionPointContainer();

	void AddConnectionPoint(OcxConnectionPoint *conn) { point_map.GetAdd(conn -> guid) = conn; conn -> SetContainer(this); }

	STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints **ppEnum);
	STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint **ppCP);

private:
	class Enumerator : public Interface<IEnumConnectionPoints>
	{
	public:
		Enumerator() {}

		void            Attach(OcxConnectionPointContainer *pt) { point = pt; index = 0; }

		STDMETHOD(Next)(unsigned long count, IConnectionPoint **rgpcn, unsigned long *fetched);
		STDMETHOD(Skip)(unsigned long connections);
		STDMETHOD(Reset)();
		STDMETHOD(Clone)(IEnumConnectionPoints **enum_conn);

	private:
		IRef<OcxConnectionPointContainer> point;
		int                               index;
	};

	friend class Enumerator;

private:
	VectorMap<Guid, IConnectionPoint *> point_map;
};

#endif
